/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* Large portions of this software are based upon public domain software
* https://sip-communicator.dev.java.net/
*
*/
package net.sourceforge.gjtapi.raw.sipprovider.sip;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Properties;
import java.util.TooManyListenersException;
import javax.sip.ClientTransaction;
import javax.sip.Dialog;
import javax.sip.InvalidArgumentException;
import javax.sip.ListeningPoint;
import javax.sip.ObjectInUseException;
import javax.sip.PeerUnavailableException;
import javax.sip.RequestEvent;
import javax.sip.ResponseEvent;
import javax.sip.ServerTransaction;
import javax.sip.SipException;
import javax.sip.SipFactory;
import javax.sip.SipListener;
import javax.sip.SipProvider;
import javax.sip.SipStack;
import javax.sip.TimeoutEvent;
import javax.sip.Transaction;
import javax.sip.TransactionAlreadyExistsException;
import javax.sip.TransactionUnavailableException;
import javax.sip.TransportNotSupportedException;
import javax.sip.address.Address;
import javax.sip.address.AddressFactory;
import javax.sip.address.SipURI;
import javax.sip.header.CSeqHeader;
import javax.sip.header.ContactHeader;
import javax.sip.header.FromHeader;
import javax.sip.header.HeaderFactory;
import javax.sip.header.MaxForwardsHeader;
import javax.sip.header.ToHeader;
import javax.sip.header.ViaHeader;
import javax.sip.message.Message;
import javax.sip.message.MessageFactory;
import javax.sip.message.Request;
import javax.sip.message.Response;
import net.sourceforge.gjtapi.raw.sipprovider.common.Console;
import net.sourceforge.gjtapi.raw.sipprovider.common.NetworkAddressManager;
import net.sourceforge.gjtapi.raw.sipprovider.sip.event.CallEvent;
import net.sourceforge.gjtapi.raw.sipprovider.sip.event.CallRejectedEvent;
import net.sourceforge.gjtapi.raw.sipprovider.sip.event.CommunicationsErrorEvent;
import net.sourceforge.gjtapi.raw.sipprovider.sip.event.CommunicationsListener;
import net.sourceforge.gjtapi.raw.sipprovider.sip.event.MessageEvent;
import net.sourceforge.gjtapi.raw.sipprovider.sip.event.RegistrationEvent;
import net.sourceforge.gjtapi.raw.sipprovider.sip.event.UnknownMessageEvent;
import net.sourceforge.gjtapi.raw.sipprovider.sip.security.SecurityAuthority;
import net.sourceforge.gjtapi.raw.sipprovider.sip.security.SipSecurityManager;
import net.sourceforge.gjtapi.raw.sipprovider.sip.security.UserCredentials;
/**
* The SipManager provides wrapping of the underlying stack's functionalities.
* It also implements the SipListener interface and handles incoming
* SIP messages.
*
* @author Emil Ivov
* @version 1.0
*/
public class SipManager implements SipListener
{
/**
* Specifies the number of retries that should be attempted when deleting
* a sipProvider
*/
protected static final int RETRY_OBJECT_DELETES = 10;
/**
* Specifies the time to wait before retrying delete of a sipProvider.
*/
protected static final long RETRY_OBJECT_DELETES_AFTER = 500;
protected static final Console console = Console.getConsole(SipManager.class);
protected static final String DEFAULT_TRANSPORT = "udp";
//jain-sip objects - package accessibility as they should be
//available for XxxProcessing classes
/**
* The SipFactory instance used to create the SipStack and the Address
* Message and Header Factories.
*/
public SipFactory sipFactory;
/**
* The AddressFactory used to create URLs and Address objects.
*/
public AddressFactory addressFactory;
/**
* The HeaderFactory used to create SIP message headers.
*/
public HeaderFactory headerFactory;
/**
* The Message Factory used to create SIP messages.
*/
public MessageFactory messageFactory;
/**
* The sipStack instance that handles SIP communications.
*/
SipStack sipStack;
/**
* The default (and currently the only) SIP listening point of the
* application.
*/
ListeningPoint listeningPoint;
/**
* The JAIN SIP SipProvider instance.
*/
public SipProvider sipProvider;
/**
* An instance used to provide user credentials
*/
private SecurityAuthority securityAuthority = null;
/**
* Used for the contact header to provide firewall support.
*/
private InetSocketAddress publicIpAddress = null;
//properties
protected String sipStackPath = null;
public String currentlyUsedURI = null;
protected String displayName = null;
protected String transport = null;
protected String registrarAddress = null;
protected int localPort = -1;
protected int registrarPort = -1;
protected int registrationsExpiration = -1;
protected String registrarTransport = null;
//mandatory stack properties
protected String stackAddress = null;
protected String stackName = "sip-communicator";
//Prebuilt Message headers
protected FromHeader fromHeader = null;
protected ContactHeader contactHeader = null;
protected ArrayList viaHeaders = null;
protected static final int MAX_FORWARDS = 70;
protected MaxForwardsHeader maxForwardsHeader = null;
protected long registrationTransaction = -1;
protected Collection listeners = new java.util.ArrayList();
//XxxProcessing managers
/**
* The instance that handles all registration associated activity such as
* registering, unregistering and keeping track of expirations.
*/
RegisterProcessing registerProcessing = null;
/**
* The instance that handles all call associated activity such as
* establishing, managing, and terminating calls.
*/
CallProcessing callProcessing = null;
/**
* The instance that handles subscriptions.
*/
//public Watcher watcher = null;
/**
* The instance that informs others of our avaibility.
*/
// public PresenceAgent presenceAgent = null;
/**
* The instance that handles status management and notifications.
*/
// public PresenceUserAgent presenceUserAgent = null;
/**
* The instance that handles incoming/outgoing REFER requests.
*/
TransferProcessing transferProcessing = null;
/**
* Authentication manager.
*/
public SipSecurityManager sipSecurityManager = null;
protected boolean isStarted = false;
private final Properties sipProp;
/** Reference to the address manager. */
private final NetworkAddressManager addressManager;
/**
* Constructor. It only creates a SipManager instance without initializing
* the stack itself.
*/
public SipManager(Properties sipProp, NetworkAddressManager manager)
{
this.sipProp = new Properties() ;
this.sipProp.putAll(sipProp);
addressManager = manager;
registerProcessing = new RegisterProcessing(this);
callProcessing = new CallProcessing(this, sipProp);
// watcher = new Watcher(this);
sipSecurityManager = new SipSecurityManager(this.sipProp);
}
/**
* Creates and initializes JAIN SIP objects (factories, stack, listening
* point and provider). Once this method is called the application is ready
* to handle (incoming and outgoing) sip messages.
*
* @throws CommunicationsException if an exception should occur during the
* initialization process
*/
public void start() throws CommunicationsException
{
try
{
console.logEntry();
initProperties();
sipFactory = SipFactory.getInstance();
sipFactory.setPathName("gov.nist");
try {
addressFactory = sipFactory.createAddressFactory();
headerFactory = sipFactory.createHeaderFactory();
messageFactory = sipFactory.createMessageFactory();
} catch (PeerUnavailableException ex) {
console.error("Could not could not create factories!", ex);
throw new CommunicationsException(
"Could not could not create factories!",
ex
);
}
try
{
sipStack = sipFactory.createSipStack(sipProp);
}
catch (PeerUnavailableException ex)
{
console.error("Could not could not create SipStack!", ex);
throw new CommunicationsException(
"Could not could not create SipStack!\n"
+
"A possible reason is an incorrect OUTBOUND_PROXY property\n"
+ "(Syntax:<proxy_address:port/transport>)",
ex
);
}
try
{
//try and capture the firewall mapping for this address
//just before it gets occuppied by the stack
publicIpAddress = addressManager.getPublicAddressFor(localPort);
listeningPoint = sipStack.createListeningPoint(localPort, transport);
}
catch (InvalidArgumentException ex)
{
//choose another port between 1024 and 65000
console.error("error binging stack to port " + localPort + ".",
ex);
throw new CommunicationsException(
"error binging stack to port " + localPort, ex);
}
catch (TransportNotSupportedException ex)
{
console.error(
"Transport " + transport
+
" is not suppported by the stack!\n Try specifying another"
+ " transport in SipCommunicator property files.\n",
ex);
throw new CommunicationsException(
"Transport " + transport
+
" is not suppported by the stack!\n Try specifying another"
+ " transport in SipCommunicator property files.\n",
ex);
}
try
{
sipProvider = sipStack.createSipProvider(listeningPoint);
}
catch (ObjectInUseException ex)
{
console.error("Could not could not create factories!\n", ex);
throw new CommunicationsException(
"Could not could not create factories!\n", ex);
}
try
{
sipProvider.addSipListener(this);
}
catch (TooManyListenersException exc)
{
console.error(
"Could not register SipManager as a sip listener!", exc);
throw new CommunicationsException(
"Could not register SipManager as a sip listener!", exc);
}
// we should have a security authority to be able to handle
// authentication
if(sipSecurityManager.getSecurityAuthority() == null)
{
throw new CommunicationsException(
"No SecurityAuthority was provided to SipManager!");
}
sipSecurityManager.setHeaderFactory(headerFactory);
sipSecurityManager.setTransactionCreator(sipProvider);
sipSecurityManager.setSipManCallback(this);
//Make sure prebuilt headers are nulled so that they get reinited
//if this is a restart
contactHeader = null;
fromHeader = null;
viaHeaders = null;
maxForwardsHeader = null;
isStarted = true;
}
finally
{
console.logExit();
}
}
/**
* Unregisters listening points, deletes sip providers, and generally
* prepares the stack for a re-start(). This method is meant to be used
* when properties are changed and should be reread by the stack.
* @throws CommunicationsException
*/
public void stop() throws CommunicationsException
{
try
{
console.logEntry();
//Delete SipProvider
int tries = 0;
for (tries = 0; tries < RETRY_OBJECT_DELETES; tries++)
{
try
{
sipStack.deleteSipProvider(sipProvider);
}
catch (ObjectInUseException ex)
{
// System.err.println("Retrying delete of riSipProvider!");
sleep(RETRY_OBJECT_DELETES_AFTER);
continue;
}
break;
}
if (tries >= RETRY_OBJECT_DELETES)
throw new CommunicationsException("Failed to delete the sipProvider!");
//Delete RI ListeningPoint
for (tries = 0; tries < RETRY_OBJECT_DELETES; tries++)
{
try
{
sipStack.deleteListeningPoint(listeningPoint);
}
catch (ObjectInUseException ex)
{
//System.err.println("Retrying delete of riListeningPoint!");
sleep(RETRY_OBJECT_DELETES_AFTER);
continue;
}
break;
}
if (tries >= RETRY_OBJECT_DELETES)
throw new CommunicationsException("Failed to delete a listeningPoint!");
sipProvider = null;
listeningPoint = null;
addressFactory = null;
messageFactory = null;
headerFactory = null;
sipStack = null;
viaHeaders = null;
contactHeader = null;
fromHeader = null;
}finally
{
console.logExit();
}
}
/**
* Waits during _no_less_ than sleepFor milliseconds.
* Had to implement it on top of Thread.sleep() to guarantee minimum
* sleep time.
*
* @param sleepFor the number of miliseconds to wait
*/
protected static void sleep(long sleepFor)
{
try
{
console.logEntry();
long startTime = System.currentTimeMillis();
long haveBeenSleeping = 0;
while (haveBeenSleeping < sleepFor)
{
try
{
Thread.sleep(sleepFor - haveBeenSleeping);
}
catch (InterruptedException ex)
{
//we-ll have to wait again!
}
haveBeenSleeping = (System.currentTimeMillis() - startTime);
}
}finally
{
console.logExit();
}
}
public void setCurrentlyUsedURI(String uri)
{
this.currentlyUsedURI = uri;
}
/**
* Causes the RegisterProcessing object to send a registration request
* to the registrar defined in
* net.java.sip.communicator.sip.REGISTRAR_ADDRESS and to register with
* the address defined in the net.java.sip.communicator.sip.PUBLIC_ADDRESS
* property
*
* @throws CommunicationsException if an exception is thrown by the
* underlying stack. The exception that caused this CommunicationsException
* may be extracted with CommunicationsException.getCause()
*/
public void register() throws CommunicationsException
{
register(currentlyUsedURI);
}
/**
* Registers using the specified public address. If public add
* @param publicAddress
* @throws CommunicationsException
*/
public void register(String publicAddress) throws CommunicationsException
{
try
{
console.logEntry();
if(publicAddress == null || publicAddress.trim().length() == 0)
return; //maybe throw an exception?
//Handle default domain name (i.e. transform 1234 -> 1234@sip.com
String defaultDomainName =
sipProp.getProperty("net.java.sip.communicator.sip.DEFAULT_DOMAIN_NAME");
//feature request, Michael Robertson (sipphone.com)
//strip the following chars of their user names: ( - ) <space>
if(publicAddress.toLowerCase().indexOf("sipphone.com") != -1
|| defaultDomainName.indexOf("sipphone.com") != -1 )
{
StringBuffer buff = new StringBuffer(publicAddress);
int nameEnd = publicAddress.indexOf('@');
nameEnd = nameEnd==-1?Integer.MAX_VALUE:nameEnd;
nameEnd = Math.min(nameEnd, buff.length())-1;
int nameStart = publicAddress.indexOf("sip:");
nameStart = nameStart == -1 ? 0 : nameStart + "sip:".length();
for(int i = nameEnd; i >= nameStart; i--)
if(!Character.isLetter( buff.charAt(i) )
&& !Character.isDigit( buff.charAt(i)))
buff.deleteCharAt(i);
publicAddress = buff.toString();
}
// if user didn't provide a domain name in the URL and someone
// has defined the DEFAULT_DOMAIN_NAME property - let's fill in the blank.
if (defaultDomainName != null
&& publicAddress.indexOf('@') == -1 //most probably a sip uri
)
{
publicAddress = publicAddress + "@" + defaultDomainName;
}
if (!publicAddress.trim().toLowerCase().startsWith("sip:"))
{
publicAddress = "sip:" + publicAddress;
}
this.currentlyUsedURI = publicAddress;
registerProcessing.register( registrarAddress, registrarPort,
registrarTransport, registrationsExpiration);
//at this point we are sure we have a sip: prefix in the uri
// we construct our pres: uri by replacing that prefix.
// String presenceUri = "pres"
// + publicAddress.substring(publicAddress.indexOf(':'));
}
finally
{
console.logExit();
}
}
public void startRegisterProcess() throws CommunicationsException
{
try
{
console.logEntry();
checkIfStarted();
//Obtain initial credentials
UserCredentials defaultCredentials = new UserCredentials();
//avoid nullpointer exceptions
String uName = sipProp.getProperty(
"net.java.sip.communicator.sip.USER_NAME");
defaultCredentials.setUserName(uName == null? "" : uName);
defaultCredentials.setPassword(new char[0]);
String realm = sipProp.getProperty(
"net.java.sip.communicator.sip.DEFAULT_AUTHENTICATION_REALM");
realm = realm == null ? "" : realm;
UserCredentials initialCredentials = securityAuthority.obtainCredentials(realm,
defaultCredentials);
register(initialCredentials.getUserName());
//at this point a simple register request has been sent and the global
//from header in SipManager has been set to a valid value by the RegisterProcesing
//class. Use it to extract the valid user name that needs to be cached by
//the security manager together with the user provider password.
initialCredentials.setUserName(((SipURI)getFromHeader().getAddress().getURI()).getUser());
cacheCredentials(realm, initialCredentials);
}
finally
{
console.logExit();
}
}
/**
* Causes the RegisterProcessing object to send a registration request with
* a 0 "expires" interval to the registrar defined in
* net.java.sip.communicator.sip.REGISTRAR_ADDRESS.
*
* @throws CommunicationsException if an exception is thrown by the
* underlying stack. The exception that caused this CommunicationsException
* may be extracted with CommunicationsException.getCause()
*/
public void unregister() throws CommunicationsException
{
try
{
console.logEntry();
if (!isRegistered())
{
return;
}
checkIfStarted();
registerProcessing.unregister();
}
finally
{
console.logExit();
}
}
/**
* Queries the RegisterProcessing object whether the application is registered
* with a registrar.
* @return true if the application is registered with a registrar.
*/
public boolean isRegistered()
{
return (registerProcessing != null && registerProcessing.isRegistered());
}
/**
* Determines whether the SipManager was start()ed.
* @return true if the SipManager was start()ed.
*/
public boolean isStarted()
{
return isStarted;
}
//============================ COMMUNICATION FUNCTIONALITIES =========================
/**
* Causes the CallProcessing object to send an INVITE request to the
* URI specified by <code>callee</code>
* setting sdpContent as message body. The method generates a Call object
* that will represent the resulting call and will be used for later
* references to the same call.
*
* @param callee the URI to send the INVITE to.
* @param sdpContent the sdp session offer.
* @return the Call object that will represent the call resulting
* from invoking this method.
* @throws CommunicationsException if an exception occurs while sending and
* parsing.
*/
public Call establishCall(String callee, String sdpContent) throws
CommunicationsException
{
try
{
console.logEntry();
checkIfStarted();
return callProcessing.invite(callee, sdpContent);
}
finally
{
console.logExit();
}
} //CALL
//------------------ hang up on
/**
* Causes the CallProcessing object to send a terminating request (CANCEL,
* BUSY_HERE or BYE) and thus terminate that call with id <code>callID</code>.
* @param callID the id of the call to terminate.
* @throws CommunicationsException if an exception occurs while invoking this
* method.
*/
public void endCall(int callID) throws CommunicationsException
{
try
{
console.logEntry();
checkIfStarted();
callProcessing.endCall(callID);
}
finally
{
console.logExit();
}
}
/**
* Calls endCall for all currently active calls.
* @throws CommunicationsException if an exception occurs while
*/
public void endAllCalls() throws CommunicationsException
{
try
{
console.logEntry();
if (callProcessing == null)
{
return;
}
Object[] keys = callProcessing.getCallDispatcher().getAllCalls();
for (int i = 0; i < keys.length; i++)
{
endCall( ( (Integer) keys[i]).intValue());
}
}
finally
{
console.logExit();
}
}
/**
* Causes CallProcessing to send a 200 OK response, with the specified
* sdp description, to the specified call's remote party.
* @param callID the id of the call that is to be answered.
* @param sdpContent this party's media description (as defined by SDP).
* @throws CommunicationsException if an axeption occurs while invoking this
* method.
*/
public void answerCall(int callID, String sdpContent) throws
CommunicationsException
{
try
{
console.logEntry();
checkIfStarted();
callProcessing.sayOK(callID, sdpContent);
}
finally
{
console.logExit();
}
} //answer to
/**
* Sends a NOT_IMPLEMENTED response through the specified transaction.
* @param serverTransaction the transaction to send the response through.
* @param request the request that is being answered.
*/
void sendNotImplemented(ServerTransaction serverTransaction,
Request request)
{
try
{
console.logEntry();
Response notImplemented = null;
try
{
notImplemented =
messageFactory.createResponse(Response.NOT_IMPLEMENTED,
request);
attachToTag(notImplemented, serverTransaction.getDialog());
}
catch (ParseException ex)
{
fireCommunicationsError(
new CommunicationsException(
"Failed to create a NOT_IMPLEMENTED response to a "
+ request.getMethod()
+ " request!",
ex)
);
return;
}
try
{
serverTransaction.sendResponse(notImplemented);
}
catch (SipException ex)
{
fireCommunicationsError(
new CommunicationsException(
"Failed to create a NOT_IMPLEMENTED response to a "
+ request.getMethod()
+ " request!",
ex)
);
}
}
finally
{
console.logExit();
}
}
//============================= Utility Methods ==================================
/**
* Initialises SipManager's fromHeader field in accordance with
* net.java.sip.communicator.sip.PUBLIC_ADDRESS
* net.java.sip.communicator.sip.DISPLAY_NAME
* net.java.sip.communicator.sip.TRANSPORT
* net.java.sip.communicator.sip.PREFERRED_LOCAL_PORT and returns a
* reference to it.
* @return a reference to SipManager's fromHeader field.
* @throws CommunicationsException if a ParseException occurs while
* initially composing the FromHeader.
*/
public FromHeader getFromHeader() throws CommunicationsException
{
try
{
console.logEntry();
if (fromHeader != null)
{
return fromHeader;
}
try
{
final SipURI fromURI = (SipURI) addressFactory.createURI(
currentlyUsedURI);
fromURI.setTransportParam(listeningPoint.getTransport());
fromURI.setPort(listeningPoint.getPort());
Address fromAddress = addressFactory.createAddress(fromURI);
if (displayName != null && displayName.trim().length() > 0)
{
fromAddress.setDisplayName(displayName);
}
fromHeader = headerFactory.createFromHeader(fromAddress,
Integer.toString(hashCode()));
console.debug("Generated from header: " + fromHeader);
}
catch (ParseException ex)
{
console.error(
"A ParseException occurred while creating From Header!", ex);
throw new CommunicationsException(
"A ParseException occurred while creating From Header!", ex);
}
return fromHeader;
}
finally
{
console.logExit();
}
}
/**
* Same as calling getContactHeader(true)
*
* @return the result of getContactHeader(true)
* @throws CommunicationsException if an exception is thrown while calling
* getContactHeader(false)
*/
public ContactHeader getContactHeader() throws CommunicationsException
{
return getContactHeader(true);
}
/**
* Same as calling getContactHeader(true).
* @return the result of calling getContactHeader(true).
* @throws CommunicationsException if an exception occurs while executing
* getContactHeader(true).
*/
public ContactHeader getRegistrationContactHeader() throws CommunicationsException
{
return getContactHeader(true);
}
/**
* Initialises SipManager's contactHeader field in accordance with
* javax.sip.IP_ADDRESS
* net.java.sip.communicator.sip.DISPLAY_NAME
* net.java.sip.communicator.sip.TRANSPORT
* net.java.sip.communicator.sip.PREFERRED_LOCAL_PORT and returns a
* reference to it.
* @param useLocalHostAddress specifies whether the SipURI in the contact
* header should contain the value of javax.sip.IP_ADDRESS (true) or that of
* net.java.sip.communicator.sip.PUBLIC_ADDRESS (false).
* @return a reference to SipManager's contactHeader field.
* @throws CommunicationsException if a ParseException occurs while
* initially composing the FromHeader.
*/
public ContactHeader getContactHeader(boolean useLocalHostAddress) throws
CommunicationsException
{
try
{
console.logEntry();
if (contactHeader != null)
{
return contactHeader;
}
try
{
SipURI contactURI;
if (useLocalHostAddress)
{
//ContacHeader it's incomplite
/*contactURI = (SipURI) addressFactory.createSipURI(null,
publicIpAddress.getAddress().getHostAddress());*/
/*In this way, allow multiple terminals located in the same machine
and generate a correct ContactHeader
before: <sip:IP:port;transport=udp> after: <sip:user@IP:port;transport=udp>>
*/
String _publicAddrsUsed = sipProp.getProperty(
"net.java.sip.communicator.sip.PUBLIC_ADDRESS");
contactURI = (SipURI) addressFactory.createURI(
_publicAddrsUsed);
}
else
{
contactURI = (SipURI) addressFactory.createURI(
currentlyUsedURI);
}
contactURI.setTransportParam(listeningPoint.getTransport());
contactURI.setPort(publicIpAddress.getPort());
Address contactAddress = addressFactory.createAddress(
contactURI);
if (displayName != null && displayName.trim().length() > 0)
{
contactAddress.setDisplayName(displayName);
}
contactHeader = headerFactory.createContactHeader(
contactAddress);
if (console.isDebugEnabled())
{
console.debug("generated contactHeader:" + contactHeader);
}
}
catch (ParseException ex)
{
console.error(
"A ParseException occurred while creating From Header!", ex);
throw new CommunicationsException(
"A ParseException occurred while creating From Header!", ex);
}
return contactHeader;
}
finally
{
console.logExit();
}
}
/**
* Initializes (if null) and returns an ArrayList with a single ViaHeader
* containing localhost's address. This ArrayList may be used when sending
* requests.
* @return ViaHeader-s list to be used when sending requests.
* @throws CommunicationsException if a ParseException is to occur while
* initializing the array list.
*/
public ArrayList getLocalViaHeaders() throws CommunicationsException
{
try
{
console.logEntry();
if (viaHeaders != null)
{
return viaHeaders;
}
ListeningPoint lp = sipProvider.getListeningPoint();
viaHeaders = new ArrayList();
try
{
ViaHeader viaHeader = headerFactory.createViaHeader(
sipStack.getIPAddress(),
lp.getPort(),
lp.getTransport(),
null
);
viaHeaders.add(viaHeader);
if (console.isDebugEnabled())
{
console.debug("generated via headers:" + viaHeader);
}
return viaHeaders;
}
catch (ParseException ex)
{
console.error(
"A ParseException occurred while creating Via Headers!");
throw new CommunicationsException(
"A ParseException occurred while creating Via Headers!");
}
catch (InvalidArgumentException ex)
{
console.error(
"Unable to create a via header for port " + lp.getPort(),
ex);
throw new CommunicationsException(
"Unable to create a via header for port " + lp.getPort(),
ex);
}
}
finally
{
console.logExit();
}
}
/**
* Initializes and returns SipManager's maxForwardsHeader field using the
* value specified by MAX_FORWARDS.
* @return an instance of a MaxForwardsHeader that can be used when
* sending requests
* @throws CommunicationsException if MAX_FORWARDS has an invalid value.
*/
public MaxForwardsHeader getMaxForwardsHeader() throws CommunicationsException
{
try
{
console.logEntry();
if (maxForwardsHeader != null)
{
return maxForwardsHeader;
}
try
{
maxForwardsHeader = headerFactory.createMaxForwardsHeader(MAX_FORWARDS);
if (console.isDebugEnabled())
{
console.debug("generate max forwards: "
+ maxForwardsHeader.toString());
}
return maxForwardsHeader;
}
catch (InvalidArgumentException ex)
{
throw new CommunicationsException(
"A problem occurred while creating MaxForwardsHeader", ex);
}
}
finally
{
console.logExit();
}
}
/**
* Returns the user used to create the From Header URI.
* @return the user used to create the From Header URI.
*/
public String getLocalUser()
{
try
{
console.logEntry();
final FromHeader header = getFromHeader();
final Address address = header.getAddress();
final SipURI uri = (SipURI) address.getURI();
return uri.getUser();
}
catch (CommunicationsException ex)
{
return "";
}
finally
{
console.logExit();
}
}
/**
* Generates a ToTag (the containingDialog's hashCode())and attaches it to
* response's ToHeader.
* @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())
*/
public void attachToTag(Response response, Dialog containingDialog)
{
try
{
console.logEntry();
ToHeader to = (ToHeader) response.getHeader(ToHeader.NAME);
if (to == null)
{
fireCommunicationsError(
new CommunicationsException(
"No TO header found in, attaching a to tag is therefore impossible"));
}
try
{
if (to.getTag() == null || to.getTag().trim().length() == 0)
{
if (console.isDebugEnabled())
{
console.debug("generated to tag: " +
containingDialog.hashCode());
}
to.setTag(Integer.toString(containingDialog.hashCode()));
}
}
catch (ParseException ex)
{
fireCommunicationsError(
new CommunicationsException(
"Failed to attach a TO tag to an outgoing response"));
}
}
finally
{
console.logExit();
}
}
//================================ PROPERTIES ================================
protected void initProperties()
{
try
{
console.logEntry();
// ------------------ stack properties --------------
stackAddress = sipProp.getProperty("javax.sip.IP_ADDRESS");
if (stackAddress == null)
{
stackAddress = getLocalHostAddress();
//Add the host address to the properties that will pass the stack
sipProp.setProperty("javax.sip.IP_ADDRESS", stackAddress);
}
//ensure IPv6 address compliance
if (stackAddress.indexOf(':') != stackAddress.lastIndexOf(':')
&& stackAddress.charAt(0) != '['
)
{
stackAddress = '[' + stackAddress.trim() + ']';
}
if (console.isDebugEnabled())
{
console.debug("stack address=" + stackAddress);
}
stackName = sipProp.getProperty("javax.sip.STACK_NAME");
if (stackName == null)
{
stackName = "SipCommunicator@" + Integer.toString(hashCode());
//Add the stack name to the properties that will pass the stack
sipProp.setProperty("javax.sip.STACK_NAME", stackName);
}
if (console.isDebugEnabled())
{
console.debug("stack name is:" + stackName);
}
String retransmissionFilter = sipProp.getProperty("javax.sip.RETRANSMISSION_FILTER");
if (retransmissionFilter == null)
{
retransmissionFilter = "true";
//Add the retransmission filter param to the properties that will pass the stack
sipProp.setProperty("javax.sip.RETRANSMISSION_FILTER", retransmissionFilter);
}
if (console.isDebugEnabled())
{
console.debug("retransmission filter is:" + stackName);
}
//------------ application properties --------------
currentlyUsedURI = sipProp.getProperty(
"net.java.sip.communicator.sip.PUBLIC_ADDRESS");
if (currentlyUsedURI == null)
{
currentlyUsedURI = sipProp.getProperty("user.name") + "@" +
stackAddress;
}
if (!currentlyUsedURI.trim().toLowerCase().startsWith("sip:"))
{
currentlyUsedURI = "sip:" + currentlyUsedURI.trim();
}
if (console.isDebugEnabled())
{
console.debug("public address=" + currentlyUsedURI);
}
registrarAddress = sipProp.getProperty(
"net.java.sip.communicator.sip.REGISTRAR_ADDRESS");
if (console.isDebugEnabled())
{
console.debug("registrar address=" + registrarAddress);
}
try
{
registrarPort = Integer.parseInt(sipProp.getProperty(
"net.java.sip.communicator.sip.REGISTRAR_PORT"));
}
catch (NumberFormatException ex)
{
registrarPort = 5060;
}
if (console.isDebugEnabled())
{
console.debug("registrar port=" + registrarPort);
}
registrarTransport = sipProp.getProperty(
"net.java.sip.communicator.sip.REGISTRAR_TRANSPORT");
if (registrarTransport == null)
{
registrarTransport = DEFAULT_TRANSPORT;
}
try
{
registrationsExpiration = Integer.parseInt(sipProp.getProperty(
"net.java.sip.communicator.sip.REGISTRATIONS_EXPIRATION"));
}
catch (NumberFormatException ex)
{
registrationsExpiration = 3600;
}
if (console.isDebugEnabled())
{
console.debug("registrar transport=" + registrarTransport);
// Added by mranga
}
String serverLog = sipProp.getProperty
("gov.nist.javax.sip.SERVER_LOG");
if (serverLog != null)
{
sipProp.setProperty
("gov.nist.javax.sip.TRACE_LEVEL", "16");
}
if (console.isDebugEnabled())
{
console.debug("server log=" + serverLog);
}
sipStackPath = sipProp.getProperty(
"net.java.sip.communicator.sip.STACK_PATH");
if (sipStackPath == null)
{
sipStackPath = "gov.nist";
}
if (console.isDebugEnabled())
{
console.debug("stack path=" + sipStackPath);
}
String routerPath = sipProp.getProperty("javax.sip.ROUTER_PATH");
if (routerPath == null)
{
sipProp.setProperty("javax.sip.ROUTER_PATH",
"net.sourceforge.gjtapi.raw.sipprovider.sip.SipCommRouter");
}
if (console.isDebugEnabled())
{
console.debug("router path=" + routerPath);
}
transport = sipProp.getProperty("net.java.sip.communicator.sip.TRANSPORT");
if (transport == null)
{
transport = DEFAULT_TRANSPORT;
}
if (console.isDebugEnabled())
{
console.debug("transport=" + transport);
}
String localPortStr = sipProp.getProperty(
"net.java.sip.communicator.sip.PREFERRED_LOCAL_PORT");
try
{
localPort = Integer.parseInt(localPortStr);
}
catch (NumberFormatException exc)
{
localPort = 5060;
}
if (console.isDebugEnabled())
{
console.debug("preferred local port=" + localPort);
}
displayName = sipProp.getProperty(
"net.java.sip.communicator.sip.DISPLAY_NAME");
if (console.isDebugEnabled())
{
console.debug("display name=" + displayName);
}
}
finally
{
console.logExit();
}
}
//============================ SECURITY ================================
/**
* Sets the SecurityAuthority instance that should be consulted later on for
* user credentials.
*
* @param authority the SecurityAuthority instance that should be consulted
* later on for user credentials.
*/
public void setSecurityAuthority(SecurityAuthority authority)
{
//keep a copty
this.securityAuthority = authority;
sipSecurityManager.setSecurityAuthority(authority);
}
/**
* Adds the specified credentials to the security manager's credentials cache
* so that they get tried next time they're needed.
*
* @param realm the realm these credentials should apply for.
* @param credentials a set of credentials (username and pass)
*/
public void cacheCredentials(String realm, UserCredentials credentials )
{
sipSecurityManager.cacheCredentials(realm, credentials);
}
//============================ EVENT DISPATHING ================================
/**
* Adds a CommunicationsListener to SipManager.
* @param listener The CommunicationsListener to be added.
*/
public void addCommunicationsListener(CommunicationsListener listener) {
listeners.add(listener);
}
//------------ call received dispatch
public void fireCallReceived(Call call)
{
try
{
console.logEntry();
if (console.isDebugEnabled())
{
console.debug("received call" + call);
}
CallEvent evt = new CallEvent(call);
Iterator iterator = listeners.iterator();
while (iterator.hasNext()) {
CommunicationsListener current =
(CommunicationsListener) iterator.next();
current.callReceived(evt);
}
}
finally
{
console.logExit();
}
} //call received
//------------ call received dispatch
void fireMessageReceived(Request message)
{
try
{
console.logEntry();
if (console.isDebugEnabled())
{
console.debug("received instant message=" + message);
}
MessageEvent evt = new MessageEvent(message);
Iterator iterator = listeners.iterator();
while (iterator.hasNext()) {
CommunicationsListener current =
(CommunicationsListener) iterator.next();
current.messageReceived(evt);
}
}
finally
{
console.logExit();
}
} //call received
//------------ registerred
public void fireRegistered(String address)
{
try
{
console.logEntry();
if (console.isDebugEnabled())
{
console.debug("registered with address = " + address);
}
RegistrationEvent evt = new RegistrationEvent(address);
Iterator iterator = listeners.iterator();
while (iterator.hasNext()) {
CommunicationsListener current =
(CommunicationsListener) iterator.next();
current.registered(evt);
}
}
finally
{
console.logExit();
}
} //call received
//------------ registering
public void fireRegistering(String address)
{
try
{
console.logEntry();
if (console.isDebugEnabled())
{
console.debug("registering with address=" + address);
}
RegistrationEvent evt = new RegistrationEvent(address);
Iterator iterator = listeners.iterator();
while (iterator.hasNext()) {
CommunicationsListener current =
(CommunicationsListener) iterator.next();
current.registering(evt);
}
}
finally
{
console.logExit();
}
} //call received
//------------ unregistered
public void fireUnregistered(String address)
{
try
{
console.logEntry();
if (console.isDebugEnabled())
{
console.debug("unregistered, address is " + address);
}
RegistrationEvent evt = new RegistrationEvent(address);
Iterator iterator = listeners.iterator();
while (iterator.hasNext()) {
CommunicationsListener current =
(CommunicationsListener) iterator.next();
current.unregistered(evt);
}
}
finally
{
console.logExit();
}
} //call received
public void fireUnregistering(String address)
{
try
{
console.logEntry();
if (console.isDebugEnabled())
{
console.debug("unregistering, address is " + address);
}
RegistrationEvent evt = new RegistrationEvent(address);
Iterator iterator = listeners.iterator();
while (iterator.hasNext()) {
CommunicationsListener current =
(CommunicationsListener) iterator.next();
current.unregistering(evt);
}
}
finally
{
console.logExit();
}
} //call received
//---------------- received unknown message
public void fireUnknownMessageReceived(Message message)
{
try
{
console.logEntry();
if (console.isDebugEnabled())
{
console.debug("unknown message=" + message);
}
UnknownMessageEvent evt = new UnknownMessageEvent(message);
Iterator iterator = listeners.iterator();
while (iterator.hasNext()) {
CommunicationsListener current =
(CommunicationsListener) iterator.next();
current.receivedUnknownMessage(evt);
}
}
finally
{
console.logExit();
}
} //unknown message
//---------------- rejected a call
public void fireCallRejectedLocally(String reason, Message invite)
{
try
{
console.logEntry();
if (console.isDebugEnabled())
{
console.debug("locally rejected call. reason="
+ reason
+ "\ninvite message=" + invite);
}
CallRejectedEvent evt = new CallRejectedEvent(reason, invite);
Iterator iterator = listeners.iterator();
while (iterator.hasNext()) {
CommunicationsListener current =
(CommunicationsListener) iterator.next();
current.callRejectedLocally(
evt);
}
}
finally
{
console.logExit();
}
}
public void fireCallRejectedRemotely(String reason, Message invite)
{
try
{
console.logEntry();
if (console.isDebugEnabled())
{
console.debug("call rejected remotely. reason="
+ reason
+ "\ninvite message=" + invite);
}
CallRejectedEvent evt = new CallRejectedEvent(reason, invite);
Iterator iterator = listeners.iterator();
while (iterator.hasNext()) {
CommunicationsListener current =
(CommunicationsListener) iterator.next();
current.callRejectedRemotely(
evt);
}
}
finally
{
console.logExit();
}
}
//call rejected
//---------------- error occurred
public void fireCommunicationsError(Throwable throwable)
{
try
{
console.logEntry();
console.error(throwable);
CommunicationsErrorEvent evt = new CommunicationsErrorEvent(
throwable);
Iterator iterator = listeners.iterator();
while (iterator.hasNext()) {
CommunicationsListener current =
(CommunicationsListener) iterator.next();
current.communicationsErrorOccurred(evt);
}
}
finally
{
console.logExit();
}
} //error occurred
//============================= SIP LISTENER METHODS ==============================
public void processRequest(RequestEvent requestReceivedEvent)
{
try
{
console.logEntry();
Request request = requestReceivedEvent.getRequest();
if (console.isDebugEnabled())
{
console.debug("received request=" + request.getMethod());
}
ServerTransaction serverTransaction = requestReceivedEvent.
getServerTransaction();
if (serverTransaction == null)
{
try
{
serverTransaction = sipProvider.getNewServerTransaction(
request);
}
catch (TransactionAlreadyExistsException ex)
{
/*fireCommunicationsError(
new CommunicationsException(
"Failed to create a new server"
+ "transaction for an incoming request\n"
+ "(Next message contains the request)",
ex));
fireUnknownMessageReceived(request);*/
//let's not scare the user
console.error("Failed to create a new server"
+ "transaction for an incoming request\n"
+ "(Next message contains the request)",
ex
);
return;
}
catch (TransactionUnavailableException ex)
{
/**
* fireCommunicationsError(
* new CommunicationsException(
* "Failed to create a new server"
* + "transaction for an incoming request\n"
* + "(Next message contains the request)",
* ex));
* fireUnknownMessageReceived(request);*/
//let's not scare the user
console.error("Failed to create a new server"
+ "transaction for an incoming request\n"
+ "(Next message contains the request)",
ex
);
return;
}
}
Dialog dialog = serverTransaction.getDialog();
String method = request.getMethod();
//INVITE
if (method.equals(Request.INVITE))
{
console.debug("received INVITE");
if(serverTransaction.getDialog().getState() == null)
{
if(console.isDebugEnabled())
console.debug("request is an INVITE. Dialog state="
+serverTransaction.getDialog().getState());
callProcessing.processInvite(serverTransaction, request);
}
else
{
console.debug("request is a reINVITE. Dialog state="
+serverTransaction.getDialog().getState());
callProcessing.processReInvite(serverTransaction, request);
}
}
//ACK
else if (method.equals(Request.ACK))
{
if (serverTransaction != null
&& serverTransaction.getDialog().getFirstTransaction().
getRequest().getMethod().equals(Request.INVITE))
{
callProcessing.processAck(serverTransaction, request);
}
else
{
// just ignore
console.debug("ignoring ack");
}
}
//BYE
else if (method.equals(Request.BYE))
{
if (dialog.getFirstTransaction().getRequest().getMethod().
equals(
Request.INVITE))
{
callProcessing.processBye(serverTransaction, request);
}
}
//CANCEL
else if (method.equals(Request.CANCEL))
{
if (dialog.getFirstTransaction().getRequest().getMethod().
equals(
Request.INVITE))
{
callProcessing.processCancel(serverTransaction, request);
}
else
{
sendNotImplemented(serverTransaction, request);
fireUnknownMessageReceived(requestReceivedEvent.getRequest());
}
}
//REFER
else if (method.equals(Request.REFER))
{
console.debug("Received REFER request");
transferProcessing.processRefer(serverTransaction, request);
}
else if (request.getMethod().equals(Request.INFO))
{
/** @todo add proper request handling */
sendNotImplemented(serverTransaction, request);
fireUnknownMessageReceived(requestReceivedEvent.getRequest());
}
else if (method.equals(Request.MESSAGE))
{
fireMessageReceived(request);
}
else if (method.equals(Request.NOTIFY))
{
/** @todo add proper request handling */
// try {
// watcher.processNotification(request, serverTransaction.getBranchId());
// }
// catch (CommunicationsException e) {
// // TODO: handle exception
// }
sendNotImplemented(serverTransaction, request);
fireUnknownMessageReceived(requestReceivedEvent.getRequest());
}
else if (method.equals(Request.OPTIONS))
{
/** @todo add proper request handling */
sendNotImplemented(serverTransaction, request);
fireUnknownMessageReceived(requestReceivedEvent.getRequest());
}
else if (method.equals(Request.PRACK))
{
/** @todo add proper request handling */
sendNotImplemented(serverTransaction, request);
fireUnknownMessageReceived(requestReceivedEvent.getRequest());
}
else if (method.equals(Request.REGISTER))
{
/** @todo add proper request handling */
sendNotImplemented(serverTransaction, request);
fireUnknownMessageReceived(requestReceivedEvent.getRequest());
}
else if (method.equals(Request.SUBSCRIBE))
{
/** @todo add proper request handling */
//fireUnknownMessageReceived(requestReceivedEvent.getRequest());
}
else if (method.equals(Request.UPDATE))
{
/** @todo add proper request handling */
sendNotImplemented(serverTransaction, request);
fireUnknownMessageReceived(requestReceivedEvent.getRequest());
}
else
{
//We couldn't recognize the message
sendNotImplemented(serverTransaction, request);
fireUnknownMessageReceived(requestReceivedEvent.getRequest());
}
}
finally
{
console.logExit();
}
}
public void processTimeout(TimeoutEvent transactionTimeOutEvent)
{
try
{
console.logEntry();
Transaction transaction;
if (transactionTimeOutEvent.isServerTransaction())
{
transaction = transactionTimeOutEvent.getServerTransaction();
}
else
{
transaction = transactionTimeOutEvent.getClientTransaction();
}
Request request = transaction.getRequest();
String method = request.getMethod();
if (console.isDebugEnabled())
{
console.debug("received time out event: " + method);
}
if (method.equals(Request.REGISTER))
{
registerProcessing.processTimeout(transaction, request);
}
else if (method.equals(Request.INVITE))
{
callProcessing.processTimeout(transaction, request);
}
else
{
//Just show an error for now
console.error("TimeOut Error!:"
+ "Received a TimeoutEvent while waiting on a message"
+ "\n(Check Details to see the message that caused it)\n"
+ request.toString());
}
}
finally
{
console.logExit();
}
}
//-------------------- PROCESS RESPONSE
public void processResponse(ResponseEvent responseReceivedEvent)
{
try
{
console.logEntry();
Response response = responseReceivedEvent.getResponse();
String method = ( (CSeqHeader) response.getHeader(CSeqHeader.NAME)).
getMethod();
if (console.isDebugEnabled())
{
console.debug("received response=" + method);
}
ClientTransaction clientTransaction = responseReceivedEvent.
getClientTransaction();
if (clientTransaction == null)
{
console.debug("ignoring a transactionless response");
return;
}
if (response.getStatusCode() == Response.OK)
{
//REGISTER
if (method.equals(Request.REGISTER))
{
registerProcessing.processOK(clientTransaction, response);
}//INVITE
else if (method.equals(Request.INVITE))
{
callProcessing.processInviteOK(clientTransaction, response);
}//BYE
else if (method.equals(Request.BYE))
{
callProcessing.processByeOK(clientTransaction, response);
}//CANCEL
else if (method.equals(Request.CANCEL))
{
callProcessing.processCancelOK(clientTransaction, response);
}
}
//TRYING
else if (response.getStatusCode() == Response.TRYING
//process all provisional responses here
//reported by Les Roger Davis
|| response.getStatusCode() / 100 == 1)
{
if (method.equals(Request.INVITE))
{
callProcessing.processTrying(clientTransaction, response);
}
//We could also receive a TRYING response to a REGISTER req
//bug reports by
//Steven Lass <sltemp at comcast.net>
//Luis Vazquez <luis at teledata.com.uy>
else if(method.equals(Request.REGISTER))
{
//do nothing
}
else
{
fireUnknownMessageReceived(response);
}
}
//RINGING
else if (response.getStatusCode() == Response.RINGING)
{
if (method.equals(Request.INVITE))
{
callProcessing.processRinging(clientTransaction, response);
}
else
{
fireUnknownMessageReceived(response);
}
}
//NOT_FOUND
else if (response.getStatusCode() == Response.NOT_FOUND)
{
if (method.equals(Request.INVITE))
{
callProcessing.processNotFound(clientTransaction, response);
}
else
{
fireUnknownMessageReceived(response);
}
}
//NOT_IMPLEMENTED
else if (response.getStatusCode() == Response.NOT_IMPLEMENTED)
{
if (method.equals(Request.INVITE))
{
registerProcessing.processNotImplemented(clientTransaction,
response);
}
else if (method.equals(Request.REGISTER))
{
callProcessing.processNotImplemented(clientTransaction,
response);
}
else
{
fireUnknownMessageReceived(response);
}
}
//REQUEST_TERMINATED
else if (response.getStatusCode() == Response.REQUEST_TERMINATED)
{
callProcessing.processRequestTerminated(clientTransaction,
response);
}
//BUSY_HERE
else if (response.getStatusCode() == Response.BUSY_HERE)
{
if (method.equals(Request.INVITE))
{
callProcessing.processBusyHere(clientTransaction, response);
}
else
{
fireUnknownMessageReceived(response);
}
}
//401 UNAUTHORIZED
else if (response.getStatusCode() == Response.UNAUTHORIZED
|| response.getStatusCode() == Response.PROXY_AUTHENTICATION_REQUIRED)
{
if(method.equals(Request.INVITE))
callProcessing.processAuthenticationChallenge(clientTransaction, response);
else if(method.equals(Request.REGISTER))
registerProcessing.processAuthenticationChallenge(clientTransaction, response);
/* else if(method.equals(Request.SUBSCRIBE))
watcher.processAuthenticationChallenge(clientTransaction, response);*/
else
fireUnknownMessageReceived(response);
}
//Other Errors
else if ( //We'll handle all errors the same way so no individual handling
//is needed
//response.getStatusCode() == Response.NOT_ACCEPTABLE
//|| response.getStatusCode() == Response.SESSION_NOT_ACCEPTABLE
response.getStatusCode() / 100 == 4
)
{
if (method.equals(Request.INVITE))
{
callProcessing.processCallError(clientTransaction, response);
}
else
{
fireUnknownMessageReceived(response);
}
}
else if (response.getStatusCode() == Response.ACCEPTED)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.ADDRESS_INCOMPLETE)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.ALTERNATIVE_SERVICE)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.AMBIGUOUS)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.BAD_EVENT)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.BAD_EXTENSION)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.BAD_GATEWAY)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.BAD_REQUEST)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.BUSY_EVERYWHERE)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() ==
Response.CALL_IS_BEING_FORWARDED)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() ==
Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.DECLINE)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() ==
Response.DOES_NOT_EXIST_ANYWHERE)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.EXTENSION_REQUIRED)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.FORBIDDEN)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.GONE)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.INTERVAL_TOO_BRIEF)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.LOOP_DETECTED)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.MESSAGE_TOO_LARGE)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.METHOD_NOT_ALLOWED)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.MOVED_PERMANENTLY)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.MOVED_TEMPORARILY)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.MULTIPLE_CHOICES)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.NOT_ACCEPTABLE_HERE)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.PAYMENT_REQUIRED)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.QUEUED)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() ==
Response.REQUEST_ENTITY_TOO_LARGE)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.REQUEST_PENDING)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.REQUEST_TIMEOUT)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.REQUEST_URI_TOO_LONG)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.SERVER_INTERNAL_ERROR)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.SERVER_TIMEOUT)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.SERVICE_UNAVAILABLE)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() ==
Response.SESSION_NOT_ACCEPTABLE)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.SESSION_PROGRESS)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() ==
Response.TEMPORARILY_UNAVAILABLE)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.TOO_MANY_HOPS)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.UNDECIPHERABLE)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() ==
Response.UNSUPPORTED_MEDIA_TYPE)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() ==
Response.UNSUPPORTED_URI_SCHEME)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.USE_PROXY)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else if (response.getStatusCode() == Response.VERSION_NOT_SUPPORTED)
{
/** @todo add proper request handling */
fireUnknownMessageReceived(response);
}
else
{ //We couldn't recognise the message
fireUnknownMessageReceived(response);
}
}
finally
{
console.logExit();
}
} //process response
//--------
public String getLocalHostAddress()
{
try
{
console.logEntry();
String hostAddress = sipProp.getProperty("javax.sip.IP_ADDRESS");
if (hostAddress == null)
{
InetAddress localhost = addressManager.getLocalHost();
hostAddress = localhost.getHostAddress();
}
if (console.isDebugEnabled())
{
console.debug("returning addres=" + hostAddress);
}
return hostAddress;
}
finally
{
console.logExit();
}
}
protected void checkIfStarted() throws CommunicationsException
{
if (!isStarted)
{
console.error("attempt to use the stack while not started");
throw new CommunicationsException(
"The underlying SIP Stack had not been"
+ "properly initialised! Impossible to continue");
}
}
public void sendServerInternalError(int callID) throws
CommunicationsException
{
try
{
console.logEntry();
checkIfStarted();
callProcessing.sayInternalError(callID);
}
finally
{
console.logExit();
}
}
public String getAddress()
{
return "sip:" + this.getLocalUser() + "@" + this.getLocalHostAddress();
}
//======================================= SIMPLE ==========================================
/**
* Retrieves a Contact List from the specified URL.
* @param url the location where the list is to be retrieved from.
* @throws CommunicationsException if we fail to retrieve the list.
* @return ContactGroup the contact list retrieved from the specified URL
*/
}