Implements support for launch parameters

Implements support for handling SIP URIs as launch parameters
Adds a lock mechanism to prevent from running multiple instances of SIP Communicator
Adds a mechanism for a second instance of SC to pass its launch 
    parameters to a one that's already running.
Adds a DefaultSecurityAuthority class (in use by the systray and SIP URI handler)
cusax-fix
Emil Ivov 17 years ago
parent 45288c7024
commit 88a0036d18

@ -358,7 +358,7 @@
<replace file="${src}/net/java/sip/communicator/impl/version/NightlyBuildID.java"
token="build.id" value="${build.label}"/>
</target>
<!-- SIP Communicator Version -->
<target name="version" depends="-pre-version">
<!-- Recompile ant task classes-->
@ -378,7 +378,7 @@
<sip-communicator-version property="sip-communicator.version" />
<echo message="SIP Communicator version ${sip-communicator.version}" />
<echo message="SIP Communicator version ${sip-communicator.version}" />
</target>
<!--INIT-->
@ -418,7 +418,7 @@
<!--internal-target- prepare to run a single Service Impl Compatibility Kit -->
<!-- extract the simple Test class name. -->
<basename property="simple.test.names" file="${test.name}"/>
<echo message="single test prepared: ${simple.test.names}" />
<echo message="single test prepared: ${simple.test.names}" />
</target>
<!--internal-target- prepare to run all known Service Impl Compatibility Kit -->
@ -457,7 +457,7 @@
<!-- Tell the slick runner about TestSutes we've preregistered. -->
<sysproperty key="net.java.sip.communicator.slick.runner.TEST_LIST"
value="${simple.test.names}"/>
<!-- Tell java.util.logging about our logging preferences -->
<sysproperty key="java.util.logging.config.file"
value="${lib}/logging.properties"/>
@ -514,6 +514,12 @@
<target name="run" depends="-deploy-os-specific-bundles"
description="Starts felix and runs sip-comunicator gui (use latest build).">
<!-- we allow users to pass command line args using the "args" system
property. However we need to manually set tha prop to an empty
string here or otherwise the application would get an argument with
the value ${args}-->
<property name="args" value=""/>
<!-- forking prevents from debugging -->
<java classname="net.java.sip.communicator.launcher.SIPCommunicator"
fork="true"
@ -550,6 +556,9 @@
<env key="LD_LIBRARY_PATH" path="${ld.library.path}"/>
<env key="PATH" path="${path}"/>
<env key="DYLD_LIBRARY_PATH" path="${dyld.library.path}"/>
<!-- pass to SC args that have been specified by the user -->
<arg line="${args}"/>
</java>
</target>
@ -623,7 +632,7 @@
</target>
<!-- - - - - - - - - - - - - - BUNDLE BUILDING TARGETS - - - - - - - - - -->
<!-- - - - - - - - - - - - - - BUNDLE BUILDING TARGETS - - - - - - - - -->
<!--ALL BUNDLES-->
<target name="bundles"
depends="bundle-sc-launcher,bundle-util,bundle-configuration,bundle-configuration-slick,
@ -659,7 +668,8 @@
bundle-updatecheckplugin,
bundle-dict,bundle-plugin-dictaccregwizz,
bundle-plugin-simpleaccreg,bundle-plugin-generalconfig,
bundle-plugin-googletalkaccregwizz"/>
bundle-plugin-googletalkaccregwizz,bundle-argdelegation-service,
bundle-argdelegation"/>
<!--BUNDLE-SC-LAUNCHER-->
<target name="bundle-sc-launcher">
@ -754,7 +764,15 @@
</target>
<!--BUNDLE-UTIL-->
<target name="bundle-util">
<target name="bundle-util" depends="version">
<!-- Create a properties file that the arg handler could use
to determine SC's version -->
<echo file="${dest}/net/java/sip/communicator/util/launchutils/version.properties"
message="APPLICATION_NAME=SIP Communicator${line.separator}" />
<echo file="${dest}/net/java/sip/communicator/util/launchutils/version.properties"
message="APPLICATION_VERSION=${sip-communicator.version}${line.separator}"
append="true"/>
<!-- Create the util.jar-->
<jar compress="false" destfile="${bundles.dest}/util.jar"
manifest="${src}/net/java/sip/communicator/util/util.manifest.mf">
<zipfileset dir="${dest}/net/java/sip/communicator/util"
@ -1052,7 +1070,7 @@ javax.swing.event, javax.swing.border"/>
<zipfileset src="${lib.noinst}/commons-logging.jar" prefix=""/>
</jar>
</target>
<!-- BUNDLE-SSH -->
<target name="bundle-ssh">
<!-- Creates a bundle containing the SSH impl of the protocol provider.-->
@ -1407,7 +1425,7 @@ javax.swing.event, javax.swing.border"/>
<zipfileset src="${lib.noinst}/aclibico-2.1.jar" prefix=""/>
</jar>
</target>
<!-- BUNDLE-RSS-SLICK -->
<!-- Creates a bundle containing the slick for the Gibberish protocol
provider.-->
@ -1563,7 +1581,7 @@ javax.swing.event, javax.swing.border"/>
prefix="net/java/sip/communicator/impl/protocol/dict"/>
</jar>
</target>
<!-- BUNDLE-PLUGIN-DICTACCREGWIZZ -->
<target name="bundle-plugin-dictaccregwizz">
<!-- Creates a bundle for the plugin Dict Account Registration
@ -1574,7 +1592,7 @@ javax.swing.event, javax.swing.border"/>
prefix="net/java/sip/communicator/plugin/dictaccregwizz"/>
</jar>
</target>
<!--BUNDLE-UpdateCheckPlugin-->
<target name="bundle-updatecheckplugin">
<jar compress="false" destfile="${bundles.dest}/updatechecker.jar"
@ -1583,7 +1601,7 @@ javax.swing.event, javax.swing.border"/>
prefix="net/java/sip/communicator/plugin/updatechecker" />
</jar>
</target>
<!--BUNDLE-AutoAwayPlugin-->
<target name="bundle-plugin-autoaway">
<jar compress="false" destfile="${bundles.dest}/autoaway.jar"
@ -1625,7 +1643,7 @@ javax.swing.event, javax.swing.border"/>
<zipfileset src="${lib.noinst}/KeybindingUtil.jar" prefix=""/>
</jar>
</target>
<!--BUNDLE-PLUGIN-KeybindingChooser-->
<target name="bundle-plugin-keybindingChooser">
<jar compress="false" destfile="${bundles.dest}/keybindingChooser.jar"
@ -1685,7 +1703,7 @@ javax.swing.event, javax.swing.border"/>
</jar>
</target>
<!-- BUNDLE-JFontChooser -->
<target name="bundle-jfontchooserlib">
<!-- Creates a bundle containing the jfontchooser lib.-->
<jar compress="false" destfile="${bundles.dest}/jfontchooserlib.jar"
@ -1693,4 +1711,24 @@ javax.swing.event, javax.swing.border"/>
<zipfileset src="${lib.noinst}/jfontchooser-1.0.5.jar" prefix=""/>
</jar>
</target>
</project>
<!-- BUNDLE Arg Delegation Service -->
<target name="bundle-argdelegation-service">
<!-- Creates a bundle for the notifications.-->
<jar compress="false" destfile="${bundles.dest}/argdelegation-service.jar"
manifest="${src}/net/java/sip/communicator/service/argdelegation/argdelegation.manifest.mf">
<zipfileset dir="${dest}/net/java/sip/communicator/service/argdelegation/"
prefix="net/java/sip/communicator/service/argdelegation"/>
</jar>
</target>
<!-- BUNDLE Arg Delegation Implementation-->
<target name="bundle-argdelegation">
<!-- Creates a bundle for the notifications.-->
<jar compress="false" destfile="${bundles.dest}/argdelegation.jar"
manifest="${src}/net/java/sip/communicator/impl/argdelegation/argdelegation.manifest.mf">
<zipfileset dir="${dest}/net/java/sip/communicator/impl/argdelegation/"
prefix="net/java/sip/communicator/impl/argdelegation/"/>
</jar>
</target>
</project>

@ -41,7 +41,8 @@ org.osgi.framework.system.packages= org.osgi.framework; ; version=1.3.0, \
org.xml.sax.helpers; \
javax.crypto; \
javax.crypto.spec; \
javax.crypto.interfaces;
javax.crypto.interfaces; \
net.java.sip.communicator.util.launchutils
felix.auto.start.10= reference:file:lib/bundle/org.apache.felix.bundlerepository-1.0.0.jar \
reference:file:lib/bundle/org.apache.felix.servicebinder-0.9.0-SNAPSHOT.jar
@ -68,7 +69,8 @@ felix.auto.start.42= \
reference:file:sc-bundles/defaultresources.jar
felix.auto.start.45= \
reference:file:sc-bundles/ui-service.jar \
reference:file:sc-bundles/ui-service.jar \
reference:file:sc-bundles/argdelegation-service.jar \
reference:file:sc-bundles/version.jar \
reference:file:sc-bundles/version-impl.jar \
reference:file:sc-bundles/branding.jar
@ -93,8 +95,8 @@ felix.auto.start.50= \
reference:file:sc-bundles/protocol-dict.jar
felix.auto.start.55= \
reference:file:sc-bundles/meta-cl.jar
reference:file:sc-bundles/meta-cl.jar
felix.auto.start.60= \
reference:file:sc-bundles/history.jar \
@ -130,14 +132,19 @@ felix.auto.start.67= \
reference:file:sc-bundles/contactinfo.jar \
reference:file:sc-bundles/accountinfo.jar \
reference:file:sc-bundles/chatalerter.jar \
reference:file:sc-bundles/shutdown.jar \
reference:file:sc-bundles/autoaway.jar \
reference:file:sc-bundles/keybindingChooser.jar \
reference:file:sc-bundles/generalconfig.jar \
reference:file:sc-bundles/dictaccregwizz.jar
felix.auto.start.70= \
reference:file:sc-bundles/simpleaccreg.jar
reference:file:sc-bundles/simpleaccreg.jar
felix.auto.start.75= \
reference:file:sc-bundles/argdelegation.jar
felix.auto.start.80= \
reference:file:sc-bundles/shutdown.jar
# Uncomment the following lines if you want to run the architect viewer
# bundle.

@ -43,7 +43,7 @@ net.java.sip.communicator.util.FileHandler.level = FINEST
# Limit the message that are printed on the console to FINEST and above (all).
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.level = WARNING
java.util.logging.ConsoleHandler.formatter = net.java.sip.communicator.util.ScLogFormatter
@ -61,20 +61,7 @@ ymsg.network.level = INFO
net.sf.cindy.impl.level = INFO
# But we want everything coming from the sip-comm
net.java.sip.communicator.impl.level = INFO
net.java.sip.communicator.impl.protocol.level = INFO
net.java.sip.communicator.impl.shutdown.level = INFO
net.java.sip.communicator.impl.contactlist.level = INFO
net.java.sip.communicator.slick.level = INFO
net.java.sip.communicator.impl.level = INFO
net.java.sip.communicator.service.level = INFO
net.java.sip.communicator.util.level = INFO
net.java.sip.communicator.service.configuration.level = INFO
net.java.sip.communicator.impl.configuration.level = INFO
net.java.sip.communicator.impl.history.level = INFO
net.java.sip.communicator.impl.gui.level = INFO
net.java.sip.communicator.impl.protocol.zeroconf.jmdns.level = WARNING
net.java.sip.communicator.impl.media.level = WARNING
net.java.sip.communicator.level = WARNING
# For example, set the com.xyz.foo logger to only log SEVERE
# messages:

@ -2,19 +2,7 @@
# environment when running automated testing.
# A list of all tests that should be run by the test target of the project.
net.java.sip.communicator.slick.runner.TEST_LIST=ConfigurationServiceLick \
MetaContactListServiceLick \
NetworkAddressManagerServiceLick \
FileAccessServiceLick \
HistoryServiceLick \
SlicklessTests \
MsgHistoryServiceLick \
CallHistoryServiceLick \
JabberProtocolProviderSlick \
YahooProtocolProviderSlick \
MsnProtocolProviderSlick \
GibberishProtocolProviderServiceLick \
RssProtocolProviderServiceLick
net.java.sip.communicator.slick.runner.TEST_LIST=JabberProtocolProviderSlick
# MediaServiceLick \
# SipProtocolProviderServiceLick \

@ -0,0 +1,94 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.argdelegation;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.version.*;
import net.java.sip.communicator.util.launchutils.*;
import org.osgi.framework.*;
/**
* Activates the <tt>ArgDelegationService</tt> and registers a URI delegation
* peer with the util package arg manager so that we would be notified when the
* application receives uri arguments.
*
* @author Emil Ivov
*/
public class ArgDelegationActivator
implements BundleActivator
{
/**
* A reference to the bundle context that is currently in use.
*/
private static BundleContext bundleContext = null;
/**
* A reference to the delegation peer implementation that is currently
* handling uri arguments.
*/
private UriDelegationPeerImpl delegationPeer = null;
/**
* A reference to the <tt>UIService</tt> currently in use in
* SIP Communicator.
*/
private static UIService uiService = null;
/**
* Starts the arg delegation bundle and registers the delegationPeer with
* the util package URI manager.
*
* @param bc a reference to the currently active bundle context.
*/
@Override
public void start(BundleContext bc) throws Exception
{
bundleContext = bc;
delegationPeer = new UriDelegationPeerImpl(bc);
bc.addServiceListener(delegationPeer);
//register our instance of delegation peer.
LaunchArgHandler.getInstance().setDelegationPeer(delegationPeer);
}
/**
* Unsets the delegation peer instance that we set when we start this
* bundle.
*
* @param bc an instance of the currently valid bundle context.
*/
@Override
public void stop(BundleContext bc) throws Exception
{
uiService = null;
bc.removeServiceListener(delegationPeer);
delegationPeer = null;
LaunchArgHandler.getInstance().setDelegationPeer(null);
}
/**
* Returns a reference to an UIService implementation currently registered
* in the bundle context or null if no such implementation was found.
*
* @return a reference to an UIService implementation currently registered
* in the bundle context or null if no such implementation was found.
*/
public static UIService getUIService()
{
if(uiService == null)
{
ServiceReference versionServiceReference
= bundleContext.getServiceReference(
UIService.class.getName());
uiService = (UIService)bundleContext
.getService(versionServiceReference);
}
return uiService;
}
}

@ -0,0 +1,186 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.argdelegation;
import java.util.*;
import org.osgi.framework.*;
import net.java.sip.communicator.service.argdelegation.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.version.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.launchutils.*;
/**
* Implements the <tt>UriDelegationPeer</tt> interface from our argument handler
* utility. We use this handler to relay arguments to URI handlers that have
* been registered from other services such as the SIP provider for example.
*
* @author Emil Ivov
*/
public class UriDelegationPeerImpl
implements UriDelegationPeer, ServiceListener
{
private static final Logger logger =
Logger.getLogger(UriDelegationPeerImpl.class);
/**
* The list of uriHandlers that we are currently aware of.
*/
private Map<String, UriHandler> uriHandlers
= new Hashtable<String, UriHandler>();
/**
* Creates an instance of this peer and scans <tt>bundleContext</tt> for all
* existing <tt>UriHandler</tt>s
*
* @param bundleContext a reference to a currently valid instance of a
* bundle context.
*/
public UriDelegationPeerImpl(BundleContext bundleContext)
{
ServiceReference[] uriHandlerRefs = null;
synchronized (uriHandlers)
{
try
{
uriHandlerRefs = bundleContext.getServiceReferences(
UriHandler.class.getName(), null);
}
catch (InvalidSyntaxException exc)
{
// this shouldn't happen because we aren't using a filter
// but let's log just the same.
logger.info("An error occurred while retrieving UriHandlers",
exc);
return;
}
if(uriHandlerRefs == null)
{
//none URI handlers are registered at this point. Some might
//come later.
return;
}
for (ServiceReference uriHandlerRef : uriHandlerRefs)
{
UriHandler uriHandler = (UriHandler) bundleContext
.getService(uriHandlerRef);
uriHandlers.put(uriHandler.getProtocol(), uriHandler);
}
}
}
/**
* Listens for <tt>UriHandlers</tt> that are registered in the bundle
* context after we had started so that we could add them to the list
* of currently known handlers.
*
* @param event the event containing the newly (un)registered service.
*/
public void serviceChanged(ServiceEvent event)
{
synchronized (uriHandlers)
{
BundleContext bc = event.getServiceReference().getBundle()
.getBundleContext();
Object service = bc.getService(event.getServiceReference());
//we are only interested in UriHandler-s
if(!(service instanceof UriHandler) )
{
return;
}
if (event.getType() == ServiceEvent.MODIFIED
|| event.getType() == ServiceEvent.REGISTERED)
{
UriHandler uriHandler = (UriHandler) bc.getService(event
.getServiceReference());
uriHandlers.put(uriHandler.getProtocol(), uriHandler);
}
else if (event.getType() == ServiceEvent.UNREGISTERING)
{
UriHandler uriHandler = (UriHandler) bc.getService(event
.getServiceReference());
if(uriHandlers.get(uriHandler.getProtocol()) == uriHandler)
uriHandlers.remove(uriHandler.getProtocol());
}
}
}
/**
* Relays <tt>uirArg</tt> to the corresponding handler or shows an error
* message in case no handler has been registered for the corresponding
* protocol.
*
* @param uriArg the uri that we've been passed and that we'd like to
* delegate to the corresponding provider.
*/
public void handleUri(String uriArg)
{
logger.trace("Handling URI: " + uriArg);
//first parse the uri and determine the scheme/protocol
//the parsing is currently a bit oversimplified so we'd probably need
//to revisit it at some point.
int colonIndex = uriArg.indexOf(":");
if( colonIndex == -1)
{
//no scheme, we don't know how to handle the URI
ArgDelegationActivator.getUIService().getPopupDialog()
.showMessagePopupDialog(
"Could not determine how to handle: " + uriArg
+ ".\nNo protocol scheme found.",
"Error handling URI",
PopupDialog.ERROR_MESSAGE);
return;
}
String scheme = uriArg.substring(0, colonIndex);
UriHandler handler = uriHandlers.get(scheme);
//if handler is null we need to tell the user.
if(handler == null)
{
logger.trace("Couldn't open " + uriArg
+ "No handler found for protocol"+ scheme);
ArgDelegationActivator.getUIService().getPopupDialog()
.showMessagePopupDialog(
"\"" + scheme + "\" URIs are currently not supported.",
"Error handling URI",
PopupDialog.ERROR_MESSAGE);
return;
}
//we're all set. let's do the handling now.
try
{
handler.handleUri(uriArg);
}
//catch every possible exception
catch(Throwable thr)
{
ArgDelegationActivator.getUIService().getPopupDialog()
.showMessagePopupDialog(
"Error handling " + uriArg,
"Error handling URI",
PopupDialog.ERROR_MESSAGE);
logger.error("Failed to handle \""+ uriArg +"\"", thr);
}
}
}

@ -0,0 +1,13 @@
Bundle-Activator: net.java.sip.communicator.impl.argdelegation.ArgDelegationActivator
Bundle-Name: Argument Delegation
Bundle-Description: A bundle that delegates invocation arguments to register handler services
Bundle-Vendor: sip-communicator.org
Bundle-Version: 0.0.1
Import-Package: org.osgi.framework,
net.java.sip.communicator.util,
net.java.sip.communicator.util.launchutils,
net.java.sip.communicator.service.configuration,
net.java.sip.communicator.service.argdelegation,
net.java.sip.communicator.service.protocol,
net.java.sip.communicator.service.protocol.event,
net.java.sip.communicator.service.gui

@ -91,7 +91,7 @@ public class MclStorageManager
* A reference to the file containing the locally stored meta contact list.
*/
private File contactlistFile = null;
/**
* A reference to the failsafe transaction used with the contactlist file.
*/
@ -174,13 +174,13 @@ public class MclStorageManager
*/
private static final String META_CONTACT_DISPLAY_NAME_NODE_NAME
= "display-name";
/**
* The name of the XML node that contains meta contact detail.
*/
private static final String META_CONTACT_DETAIL_NAME_NODE_NAME
= "detail";
/**
* The name of the XML attribute that contains detail name.
*/
@ -190,7 +190,7 @@ public class MclStorageManager
* The name of the XML attribute that contains detail value.
*/
private static final String DETAIL_VALUE_ATTR_NAME = "value";
/**
* The name of the XML node that contains information of a proto contact
*/
@ -400,7 +400,7 @@ private void storeContactList0() throws IOException
} catch (IllegalStateException e) {
logger.error("the contactlist file is missing", e);
}
// really write the modification
OutputStream stream = new FileOutputStream(contactlistFile);
XMLUtils.indentedWriteXML(contactListDocument,
@ -573,14 +573,14 @@ void extractContactsForAccount(String accountID)
{
if(!isStarted())
return;
//we don't want to receive meta contact events triggerred by ourselves
//so we stop listening. it is possible but very unlikely that other
//events, not triggerred by us are received while we're off the channel
//but that would be a very bizzare case ..... I guess we got to live
//with the risk.
this.mclServiceImpl.removeMetaContactListListener(this);
try
{
Element root = findMetaContactGroupNode(
@ -591,12 +591,12 @@ void extractContactsForAccount(String accountID)
// If there is no root, there is definitely something wrong
// really broken file will create it again
logger.fatal("The contactlist file is recreated cause its broken");
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
contactListDocument = builder.newDocument();
initVirginDocument(mclServiceImpl, contactListDocument);
//write the contact list so that it is there for the parser
@ -608,11 +608,11 @@ void extractContactsForAccount(String accountID)
//parse the group node and extract all its child groups and contacts
processGroupXmlNode(mclServiceImpl, accountID, root
, null, null);
//now save the contact list in case it has changed
scheduleContactListStorage();
}
}catch(Throwable exc)
{
// catch everything because we MUST NOT disturb the thread
@ -779,7 +779,7 @@ private void processGroupXmlNode(
//contain any contacts matching the currently parsed account id.
if (protoContacts.size() < 1)
continue;
// Extract contact details.
Hashtable details = new Hashtable();
try
@ -787,7 +787,7 @@ private void processGroupXmlNode(
List detailsNodes = XMLUtils.findChildren(
(Element) currentMetaContactNode
, META_CONTACT_DETAIL_NAME_NODE_NAME);
for (int j = 0; j < detailsNodes.size(); j++)
for (int j = 0; j < detailsNodes.size(); j++)
{
Element e = (Element)detailsNodes.get(j);
String name = e.getAttribute(DETAIL_NAME_ATTR_NAME);
@ -795,7 +795,7 @@ private void processGroupXmlNode(
Object detailsObj = details.get(name);
if(detailsObj == null)
{
{
ArrayList ds = new ArrayList();
ds.add(value);
details.put(name, ds);
@ -808,7 +808,7 @@ private void processGroupXmlNode(
{
// catch any exception from loading contacts
// that will prevent loading the contact
logger.error("Cannot load details for contact node " +
logger.error("Cannot load details for contact node " +
currentMetaContactNode, ex);
}
@ -1203,7 +1203,7 @@ public void metaContactAdded(MetaContactEvent evt)
* @param evt the MetaContactListEvent containing the corresponding contact
*/
public void metaContactGroupAdded(MetaContactGroupEvent evt)
{
{
//if the group was created as an encapsulator of a non persistent proto
//group then we'll ignore it.
if (evt.getSourceProtoGroup() != null
@ -1449,7 +1449,7 @@ public void metaContactRenamed(MetaContactRenamedEvent evt)
+ evt.getSourceMetaContact(), ex);
}
}
/**
* Indicates that a MetaContact has been modified.
* @param evt the MetaContactModifiedEvent containing the corresponding contact
@ -1457,7 +1457,7 @@ public void metaContactRenamed(MetaContactRenamedEvent evt)
public void metaContactModified(MetaContactModifiedEvent evt)
{
String name = evt.getModificationName();
Element metaContactNode = findMetaContactNode(
evt.getSourceMetaContact().getMetaUID());
@ -1469,26 +1469,26 @@ public void metaContactModified(MetaContactModifiedEvent evt)
+ evt.getSourceMetaContact());
return;
}
Object oldValue = evt.getOldValue();
Object newValue = evt.getNewValue();
boolean isChanged = false;
if(oldValue == null && newValue != null)
{
// indicates add
if(!(newValue instanceof String))
return;
Element detailElement = contactListDocument.createElement(
META_CONTACT_DETAIL_NAME_NODE_NAME);
detailElement.setAttribute(DETAIL_NAME_ATTR_NAME, name);
detailElement.setAttribute(DETAIL_VALUE_ATTR_NAME,
detailElement.setAttribute(DETAIL_VALUE_ATTR_NAME,
(String)newValue);
metaContactNode.appendChild(detailElement);
isChanged = true;
}
@ -1506,7 +1506,7 @@ else if(oldValue != null && newValue == null)
, name);
ArrayList nodesToRemove = new ArrayList();
for (int i = 0; i < nodes.size(); i++)
for (int i = 0; i < nodes.size(); i++)
{
Element e = (Element)nodes.get(i);
if(valuesToRemove.contains(
@ -1515,8 +1515,8 @@ else if(oldValue != null && newValue == null)
nodesToRemove.add(e);
}
}
for (int i = 0; i < nodesToRemove.size(); i++)
for (int i = 0; i < nodesToRemove.size(); i++)
{
Element e = (Element)nodesToRemove.get(i);
metaContactNode.removeChild(e);
@ -1534,7 +1534,7 @@ else if(oldValue instanceof String)
, name);
Element elementToRemove = null;
for (int i = 0; i < nodes.size(); i++)
for (int i = 0; i < nodes.size(); i++)
{
Element e = (Element)nodes.get(i);
if(e.getAttribute(DETAIL_VALUE_ATTR_NAME).equals(oldValue))
@ -1543,12 +1543,12 @@ else if(oldValue instanceof String)
break;
}
}
if(elementToRemove == null)
return;
metaContactNode.removeChild(elementToRemove);
isChanged = true;
}
}
@ -1562,7 +1562,7 @@ else if(oldValue != null && newValue != null)
, name);
Element changedElement = null;
for (int i = 0; i < nodes.size(); i++)
for (int i = 0; i < nodes.size(); i++)
{
Element e = (Element)nodes.get(i);
if(e.getAttribute(DETAIL_VALUE_ATTR_NAME).equals(oldValue))
@ -1571,16 +1571,16 @@ else if(oldValue != null && newValue != null)
break;
}
}
if(changedElement == null)
return;
changedElement.setAttribute(DETAIL_VALUE_ATTR_NAME,
changedElement.setAttribute(DETAIL_VALUE_ATTR_NAME,
(String)newValue);
isChanged = true;
}
if(!isChanged)
return;

@ -329,7 +329,7 @@ public void registerExportedWindow(ExportedWindow window)
/**
* Unregisters the given <tt>ExportedWindow</tt> from the list of windows
* that could be accessed from other bundles.
*
*
* @param window the window to no longer be exported
*/
public void unregisterExportedWindow(ExportedWindow window)
@ -482,7 +482,7 @@ public Chat getChat(Contact contact)
/**
* Returns the <tt>Chat</tt> corresponding to the given <tt>ChatRoom</tt>.
*
*
* @param chatRoom the <tt>ChatRoom</tt> for which the searched chat is
* about.
* @return the <tt>Chat</tt> corresponding to the given <tt>ChatRoom</tt>.
@ -559,6 +559,25 @@ public ExportedWindow getAuthenticationWindow(
isUserNameEditable);
}
/**
* Returns a default implementation of the <tt>SecurityAuthority</tt>
* interface that can be used by non-UI components that would like to launch
* the registration process for a protocol provider. Initially this method
* was meant for use by the systray bundle and the protocol URI handlers.
*
* @param protocolProvider the <tt>ProtocolProviderService</tt> for which
* the authentication window is about.
*
* @return a default implementation of the <tt>SecurityAuthority</tt>
* interface that can be used by non-UI components that would like to launch
* the registration process for a protocol provider.
*/
public SecurityAuthority getDefaultSecurityAuthority(
ProtocolProviderService protocolProvider)
{
return new DefaultSecurityAuthority(protocolProvider);
}
/**
* Returns the LoginManager.
* @return the LoginManager
@ -683,7 +702,7 @@ else if (event.getType() == ServiceEvent.UNREGISTERING)
/**
* Returns the corresponding <tt>BorderLayout</tt> constraint from the given
* <tt>Container</tt> constraint.
*
*
* @param containerConstraints constraints defined in the <tt>Container</tt>
* @return the corresponding <tt>BorderLayout</tt> constraint from the given
* <tt>Container</tt> constraint.
@ -710,7 +729,7 @@ else if (containerConstraints.equals(Container.RIGHT))
return layoutConstraint;
}
private class DefaultPluginComponent implements PluginComponent
{
private Component component;

@ -61,7 +61,7 @@ public class MainFrame
private JPanel contactListPanel = new JPanel(new BorderLayout());
private JPanel mainPanel = new JPanel(new BorderLayout(0, 5));
private MainMenu menu;
private CallManager callManager;
@ -171,7 +171,7 @@ private void init()
this.getContentPane().add(northPanel, BorderLayout.NORTH);
this.getContentPane().add(mainPanel, BorderLayout.CENTER);
}
/**
* Sets frame size and position.
*/
@ -341,7 +341,7 @@ public void addProtocolSupportedOperationSets(
multiUserChat.addInvitationListener(multiUserChatManager);
multiUserChat.addInvitationRejectionListener(multiUserChatManager);
multiUserChat.addPresenceListener(multiUserChatManager);
this.getChatRoomsListPanel()
.getChatRoomsList()
.addChatServer(protocolProvider, multiUserChat);
@ -357,7 +357,7 @@ public Iterator getProtocolProviders()
{
return ((LinkedHashMap)protocolProviders.clone()).keySet().iterator();
}
/**
* Returns the protocol provider associated to the account given
* by the account user identifier.
@ -429,10 +429,10 @@ public int getProviderIndex(ProtocolProviderService protocolProvider)
public void addAccount(ProtocolProviderService protocolProvider)
{
if (!getStatusPanel().containsAccount(protocolProvider)) {
logger.trace("Add the following account to the status bar: "
+ protocolProvider.getAccountID().getAccountAddress());
this.getStatusPanel().addAccount(protocolProvider);
//request the focus in the contact list panel, which
@ -440,7 +440,7 @@ public void addAccount(ProtocolProviderService protocolProvider)
this.tabbedPane.getContactListPanel().getContactList()
.requestFocus();
}
if(!callManager.containsCallAccount(protocolProvider)
&& getTelephonyOpSet(protocolProvider) != null) {
callManager.addCallAccount(protocolProvider);
@ -503,10 +503,10 @@ public OperationSetPresence getProtocolPresenceOpSet(
{
OperationSet opSet
= protocolProvider.getOperationSet(OperationSetPresence.class);
if(opSet != null && opSet instanceof OperationSetPresence)
return (OperationSetPresence) opSet;
return null;
}
@ -521,13 +521,13 @@ public OperationSetPresence getProtocolPresenceOpSet(
*/
public OperationSetWebContactInfo getWebContactInfoOpSet(
ProtocolProviderService protocolProvider)
{
{
OperationSet opSet
= protocolProvider.getOperationSet(OperationSetWebContactInfo.class);
if(opSet != null && opSet instanceof OperationSetWebContactInfo)
return (OperationSetWebContactInfo) opSet;
return null;
}
@ -544,13 +544,13 @@ public OperationSetBasicTelephony getTelephonyOpSet(
{
OperationSet opSet
= protocolProvider.getOperationSet(OperationSetBasicTelephony.class);
if(opSet != null && opSet instanceof OperationSetBasicTelephony)
return (OperationSetBasicTelephony) opSet;
return null;
}
/**
* Returns the multi user chat operation set for the given protocol provider.
*
@ -564,10 +564,10 @@ public OperationSetMultiUserChat getMultiUserChatOpSet(
{
OperationSet opSet
= protocolProvider.getOperationSet(OperationSetMultiUserChat.class);
if(opSet != null && opSet instanceof OperationSetMultiUserChat)
return (OperationSetMultiUserChat) opSet;
return null;
}
@ -598,7 +598,7 @@ private class GUIContactPresenceStatusListener implements
{
/**
* Indicates that a contact has changed its status.
*
*
* @param evt the presence event containing information about the
* contact status change
*/
@ -716,7 +716,7 @@ public void run()
ConfigurationManager.setApplicationVisible(false);
}
}
public void windowClosed(WindowEvent e)
{
if(GuiActivator.getUIService().getExitOnMainWindowClose())
@ -738,7 +738,7 @@ public void windowClosed(WindowEvent e)
//System.exit(0);
}
}
}
}
/**
* Returns the class that manages user login.
@ -771,7 +771,7 @@ public ContactListPanel getContactListPanel()
{
return this.tabbedPane.getContactListPanel();
}
/**
* Returns the panel containing the chat rooms list.
* @return the panel containing the chat rooms list
@ -802,7 +802,7 @@ public void removeCallPanel(CallPanel callPanel)
// Should remove all participant panels explicetly, thus removing also
// all related dialogs (like dialpad for example).
callPanel.removeDialogs();
tabbedPane.remove(callPanel);
Component c = getSelectedTab();
@ -1180,7 +1180,7 @@ public void actionPerformed(ActionEvent e)
};
/**
*
*
* @param protocolProvider
* @param contactHandler
*/
@ -1194,7 +1194,7 @@ public void addProviderContactHandler(
/**
* Returns the <tt>ContactEventHandler</tt> registered for this protocol
* provider.
*
*
* @param protocolProvider the <tt>ProtocolProviderService</tt> for which
* we are searching a <tt>ContactEventHandler</tt>.
* @return the <tt>ContactEventHandler</tt> registered for this protocol
@ -1207,7 +1207,7 @@ public ContactEventHandler getContactHandler(
}
/**
*
*
* @param protocolProvider
* @return
*/
@ -1434,7 +1434,7 @@ public LogoBar()
/**
* Paints the logo bar.
*
*
* @param g the <tt>Graphics</tt> object used to paint the background
* image of this logo bar.
*/
@ -1538,7 +1538,7 @@ public void minimize()
{
this.setExtendedState(JFrame.ICONIFIED);
}
/**
* Implements <code>isVisible</code> in the UIService interface. Checks if
* the main application window is visible.
@ -1559,7 +1559,7 @@ public boolean isVisible()
else
return false;
}
/**
* Implements <code>setVisible</code> in the UIService interface. Shows or
* hides the main application window depending on the parameter
@ -1576,15 +1576,15 @@ public void setVisible(final boolean isVisible)
public void run()
{
if(isVisible)
{
MainFrame.this.addNativePlugins();
MainFrame.super.setVisible(isVisible);
MainFrame.super.toFront();
}
else
{
MainFrame.super.setVisible(isVisible);
}
{
MainFrame.this.addNativePlugins();
MainFrame.super.setVisible(isVisible);
MainFrame.super.toFront();
}
else
{
MainFrame.super.setVisible(isVisible);
}
}
});
}
@ -1592,7 +1592,7 @@ public void run()
/**
* Adds the given component with to the container corresponding to the
* given constraints.
*
*
* @param c the component to add
* @param constraints the constraints determining the container
*/
@ -1632,7 +1632,7 @@ else if (constraints.equals(BorderLayout.EAST))
/**
* Removes the given component from the container corresponding to the given
* constraints.
*
*
* @param c the component to remove
* @param constraints the constraints determining the container
*/

@ -0,0 +1,106 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.gui.main.login;
import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
/**
* Utility class that can be used in cases where components other than the main
* user interface may need to launch provider registration. At the time I am
* writing this, the <tt>DefaultSecurityAuthority</tt> is being used by the
* systray and
*
* @author Emil Ivov
*/
public class DefaultSecurityAuthority
implements SecurityAuthority
{
private boolean isUserNameEditable = false;
/**
* The provider that this authority would be responsible for.
*/
private ProtocolProviderService provider = null;
/**
* Creates this authority for a particular provider.
*/
public DefaultSecurityAuthority(ProtocolProviderService provider)
{
this.provider = provider;
}
/**
* Used to login to the protocol providers
*
* @param realm the realm that the credentials are needed for
* @param userCredentials the values to propose the user by default
* @return The Credentials associated with the speciefied realm
*/
public UserCredentials obtainCredentials(
String realm,
UserCredentials userCredentials)
{
return obtainCredentials( realm,
userCredentials,
SecurityAuthority.AUTHENTICATION_REQUIRED);
}
/**
* Used to login to the protocol providers
*
* @param realm the realm that the credentials are needed for
* @param userCredentials the values to propose the user by default
* @param reasonCode the reason for which we're asking for credentials
* @return The Credentials associated with the speciefied realm
*/
public UserCredentials obtainCredentials(
String realm,
UserCredentials userCredentials,
int reasonCode)
{
ExportedWindow loginWindow
= GuiActivator.getUIService()
.getAuthenticationWindow(provider,
realm,
userCredentials,
isUserNameEditable);
loginWindow.setVisible(true);
return userCredentials;
}
/**
* Sets the userNameEditable property, which should indicate to the
* implementations of this interface if the user name could be changed
* by user or not.
*
* @param isUserNameEditable indicates if the user name could be changed
* by user in the implementation of this interface.
*/
public void setUserNameEditable(boolean isUserNameEditable)
{
this.isUserNameEditable = isUserNameEditable;
}
/**
* Indicates if the user name is currently editable, i.e. could be
* changed by user or not.
*
* @return <tt>true</tt> if the user name could be changed and
* <tt>false</tt> otherwise.
*/
public boolean isUserNameEditable()
{
return isUserNameEditable;
}
}

@ -71,7 +71,7 @@ public class MessageHistoryServiceImpl
private ConfigurationService configService;
private MessageHistoryPropertyChangeListener msgHistoryPropListener;
private static ResourceManagementService resourcesService;
public HistoryService getHistoryService()
@ -96,7 +96,7 @@ public Collection findByStartDate(MetaContact contact, Date startDate)
Hashtable readers = getHistoryReaders(contact);
int recordsCount = countRecords(readers);
Iterator iter = readers.keySet().iterator();
while (iter.hasNext())
{
@ -141,7 +141,7 @@ public Collection findByEndDate(MetaContact contact, Date endDate)
Hashtable readers = getHistoryReaders(contact);
int recordsCount = countRecords(readers);
Iterator iter = readers.keySet().iterator();
while (iter.hasNext())
{
@ -186,7 +186,7 @@ public Collection findByPeriod(MetaContact contact, Date startDate, Date endDate
Hashtable readers = getHistoryReaders(contact);
int recordsCount = countRecords(readers);
Iterator iter = readers.keySet().iterator();
while (iter.hasNext())
{
@ -353,11 +353,11 @@ public Collection findFirstMessagesAfter(MetaContact contact, Date date,
}
LinkedList resultAsList = new LinkedList(result);
int toIndex = count;
if(toIndex > resultAsList.size())
toIndex = resultAsList.size();
return resultAsList.subList(0, toIndex);
}
@ -443,10 +443,10 @@ private History getHistory(Contact localContact, Contact remoteContact)
return retVal;
}
/**
* Returns the history by specified local contact
* (if is null the default is used)
* (if is null the default is used)
* and by the chat room
*
* @param room The chat room
@ -456,20 +456,20 @@ private History getHistory(Contact localContact, Contact remoteContact)
private History getHistoryForMultiChat(
Contact localContact,
ChatRoom room)
throws IOException
throws IOException
{
AccountID account = room.getParentProvider().getAccountID();
return this.getHistoryForMultiChat(
null,
null,
account.getAccountUniqueID(),
account.getService(),
room.getName());
}
/**
* Returns the history by specified local contact
* (if is null the default is used)
* (if is null the default is used)
* and by accountUniqueID, channel and server
* used by the multichat account.
*
@ -485,7 +485,7 @@ private History getHistoryForMultiChat(
String account,
String server,
String channel)
throws IOException
throws IOException
{
History retVal = null;
@ -494,8 +494,8 @@ private History getHistoryForMultiChat(
HistoryID historyId = HistoryID.createFromRawID(
new String[] { "messages",
localId,
account,
localId,
account,
channel + "@" + server });
if (this.historyService.isHistoryExisting(historyId))
@ -550,9 +550,9 @@ private Object convertHistoryRecordToMessageEvent(HistoryRecord hr, Contact cont
contact,
timestamp);
}
/**
* Used to convert HistoryRecord in ChatRoomMessageDeliveredEvent or
* Used to convert HistoryRecord in ChatRoomMessageDeliveredEvent or
* ChatRoomMessageReceivedEvent
* which are returned by the finder methods
*
@ -580,10 +580,10 @@ private Object convertHistoryRecordToMessageEvent(
}
else
timestamp = hr.getTimestamp();
// 5 is the index of the subject in the structure
String fromStr = hr.getPropertyValues()[5];
ChatRoomMember from = new ChatRoomMemberImpl(fromStr, room, null);
if(msg.isOutgoing)
@ -669,15 +669,15 @@ public void start(BundleContext bc)
configService = (ConfigurationService)
bundleContext.getService(refConfig);
// Check if the message history is enabled in the configuration
// Check if the message history is enabled in the configuration
// service, and if not do not register the service.
String isMessageHistoryEnabledPropertyString =
"net.java.sip.communicator.impl.msghistory.isMessageHistoryEnabled";
String isMessageHistoryEnabledString = configService.getString(
isMessageHistoryEnabledPropertyString);
if(isMessageHistoryEnabledString == null)
isMessageHistoryEnabledString =
isMessageHistoryEnabledString =
getResources().
getSettingsString(isMessageHistoryEnabledPropertyString);
@ -737,19 +737,19 @@ public void messageDelivered(MessageDeliveredEvent evt)
public void messageDeliveryFailed(MessageDeliveryFailedEvent evt)
{
}
// //////////////////////////////////////////////////////////////////////////
// ChatRoomMessageListener implementation methods
public void messageReceived(ChatRoomMessageReceivedEvent evt)
{
try
try
{
History history = this.getHistoryForMultiChat(
null,
null,
evt.getSourceChatRoom());
writeMessage(history, "in", evt.getSourceChatRoomMember(),
writeMessage(history, "in", evt.getSourceChatRoomMember(),
evt.getMessage(), evt.getTimestamp());
} catch (IOException e)
{
@ -759,13 +759,13 @@ public void messageReceived(ChatRoomMessageReceivedEvent evt)
public void messageDelivered(ChatRoomMessageDeliveredEvent evt)
{
try
try
{
History history = this.
getHistoryForMultiChat(
null,
null,
evt.getSourceChatRoom());
writeMessage(history, "out", evt.getMessage(), evt.getTimestamp());
} catch (IOException e)
{
@ -776,11 +776,11 @@ public void messageDelivered(ChatRoomMessageDeliveredEvent evt)
public void messageDeliveryFailed(ChatRoomMessageDeliveryFailedEvent evt)
{
}
/**
* Writes message to the history
* @param direction String direction of the message
* @param source The source Contact
* @param source The source Contact
* @param destination The destiantion Contact
* @param message Message message to be written
* @param messageTimestamp Date this is the timestamp when was message received
@ -791,14 +791,14 @@ private void writeMessage(String direction, Contact source,
{
try {
History history = this.getHistory(source, destination);
writeMessage(history, direction, message, messageTimestamp);
} catch (IOException e)
{
logger.error("Could not add message to history", e);
}
}
/**
* Writes message to the history
* @param history The history to which will write the message
@ -821,7 +821,7 @@ private void writeMessage(History history, String direction,
logger.error("Could not add message to history", e);
}
}
/**
* Writes message to the history
* @param history The history to which will write the message
@ -838,7 +838,7 @@ private void writeMessage(History history, String direction,
historyWriter.addRecord(new String[] { direction,
message.getContent(), message.getContentType(),
message.getEncoding(), message.getMessageUID(),
from.getContactAddress(),
from.getContactAddress(),
String.valueOf(messageTimestamp.getTime()) },
new Date()); // this date is when the history record is written
} catch (IOException e)
@ -846,7 +846,7 @@ private void writeMessage(History history, String direction,
logger.error("Could not add message to history", e);
}
}
// //////////////////////////////////////////////////////////////////////////
/**
@ -942,7 +942,7 @@ private void handleProviderAdded(ProtocolProviderService provider)
{
logger.trace("Service did not have a im op. set.");
}
OperationSetMultiUserChat opSetMultiUChat
= (OperationSetMultiUserChat) provider
.getSupportedOperationSets().get(
@ -950,7 +950,7 @@ private void handleProviderAdded(ProtocolProviderService provider)
if (opSetMultiUChat != null)
{
Iterator iter =
Iterator iter =
opSetMultiUChat.getCurrentlyJoinedChatRooms().iterator();
while(iter.hasNext())
@ -958,7 +958,7 @@ private void handleProviderAdded(ProtocolProviderService provider)
ChatRoom room = (ChatRoom)iter.next();
room.addMessageListener(this);
}
opSetMultiUChat.addPresenceListener(this);
}
else
@ -984,7 +984,7 @@ private void handleProviderRemoved(ProtocolProviderService provider)
{
opSetIm.removeMessageListener(this);
}
OperationSetMultiUserChat opSetMultiUChat
= (OperationSetMultiUserChat) provider
.getSupportedOperationSets().get(
@ -992,9 +992,9 @@ private void handleProviderRemoved(ProtocolProviderService provider)
if (opSetMultiUChat != null)
{
Iterator iter =
Iterator iter =
opSetMultiUChat.getCurrentlyJoinedChatRooms().iterator();
while(iter.hasNext())
{
ChatRoom room = (ChatRoom)iter.next();
@ -1002,7 +1002,7 @@ private void handleProviderRemoved(ProtocolProviderService provider)
}
}
}
/**
* Called to notify interested parties that a change in our presence in
* a chat room has occured. Changes may include us being kicked, join,
@ -1012,7 +1012,7 @@ private void handleProviderRemoved(ProtocolProviderService provider)
*/
public void localUserPresenceChanged(LocalUserChatRoomPresenceChangeEvent evt)
{
if(evt.getEventType() ==
if(evt.getEventType() ==
LocalUserChatRoomPresenceChangeEvent.LOCAL_USER_JOINED)
{
if (!evt.getChatRoom().isSystem())
@ -1119,7 +1119,7 @@ public Collection findByPeriod(MetaContact contact, Date startDate,
Hashtable readers = getHistoryReaders(contact);
int recordsCount = countRecords(readers);
Iterator iter = readers.keySet().iterator();
while (iter.hasNext())
{
@ -1167,7 +1167,7 @@ public Collection findByKeyword(MetaContact contact, String keyword,
Hashtable readers = getHistoryReaders(contact);
int recordsCount = countRecords(readers);
Iterator iter = readers.keySet().iterator();
while (iter.hasNext())
{
@ -1215,7 +1215,7 @@ public Collection findByKeywords(MetaContact contact, String[] keywords,
Hashtable readers = getHistoryReaders(contact);
int recordsCount = countRecords(readers);
Iterator iter = readers.keySet().iterator();
while (iter.hasNext())
{
@ -1269,22 +1269,22 @@ private Hashtable getHistoryReaders(MetaContact contact)
}
return readers;
}
/**
* Total count of records for supplied history readers will read through
*
*
* @param readers hashtable with pairs contact <-> history reader
* @return the number of searched messages
* @throws UnsupportedOperationException
* @throws UnsupportedOperationException
* Thrown if an exception occurs during the execution of the
* query, such as internal IO error.
*/
public int countRecords(Hashtable readers)
{
int result = 0;
Enumeration readersEnum = readers.elements();
while (readersEnum.hasMoreElements())
{
HistoryReader r = (HistoryReader)readersEnum.nextElement();
@ -1293,9 +1293,9 @@ public int countRecords(Hashtable readers)
return result;
}
/**
* Returns all the messages exchanged in the supplied
* Returns all the messages exchanged in the supplied
* chat room after the given date
*
* @param room The chat room
@ -1310,7 +1310,7 @@ public Collection findByStartDate(ChatRoom room, Date startDate)
try
{
// get the readers for this room
HistoryReader reader =
HistoryReader reader =
this.getHistoryForMultiChat(null, room).getReader();
// add the progress listeners
@ -1328,12 +1328,12 @@ public Collection findByStartDate(ChatRoom room, Date startDate)
{
logger.error("Could not read history", e);
}
return result;
}
/**
* Returns all the messages exchanged
* Returns all the messages exchanged
* in the supplied chat room before the given date
*
* @param room The chat room
@ -1348,7 +1348,7 @@ public Collection findByEndDate(ChatRoom room, Date endDate)
try
{
// get the readers for this room
HistoryReader reader =
HistoryReader reader =
this.getHistoryForMultiChat(null, room).getReader();
// add the progress listeners
@ -1371,7 +1371,7 @@ public Collection findByEndDate(ChatRoom room, Date endDate)
}
/**
* Returns all the messages exchanged
* Returns all the messages exchanged
* in the supplied chat room between the given dates
*
* @param room The chat room
@ -1387,7 +1387,7 @@ public Collection findByPeriod(ChatRoom room, Date startDate, Date endDate)
try
{
// get the readers for this room
HistoryReader reader =
HistoryReader reader =
this.getHistoryForMultiChat(null, room).getReader();
// add the progress listeners
@ -1405,12 +1405,12 @@ public Collection findByPeriod(ChatRoom room, Date startDate, Date endDate)
{
logger.error("Could not read history", e);
}
return result;
}
/**
* Returns all the messages exchanged
* Returns all the messages exchanged
* in the supplied chat room between the given dates and having the given
* keywords
*
@ -1421,7 +1421,7 @@ public Collection findByPeriod(ChatRoom room, Date startDate, Date endDate)
* @return Collection of MessageReceivedEvents or MessageDeliveredEvents
* @throws RuntimeException
*/
public Collection findByPeriod(ChatRoom room,
public Collection findByPeriod(ChatRoom room,
Date startDate, Date endDate, String[] keywords)
throws RuntimeException
{
@ -1429,7 +1429,7 @@ public Collection findByPeriod(ChatRoom room,
}
/**
* Returns all the messages exchanged
* Returns all the messages exchanged
* in the supplied chat room between the given dates and having the given
* keywords
*
@ -1449,7 +1449,7 @@ public Collection findByPeriod(ChatRoom room, Date startDate, Date endDate,
try
{
// get the readers for this room
HistoryReader reader =
HistoryReader reader =
this.getHistoryForMultiChat(null, room).getReader();
// add the progress listeners
@ -1468,12 +1468,12 @@ public Collection findByPeriod(ChatRoom room, Date startDate, Date endDate,
{
logger.error("Could not read history", e);
}
return result;
}
/**
* Returns all the messages exchanged
* Returns all the messages exchanged
* in the supplied room having the given keyword
*
* @param room The Chat room
@ -1488,7 +1488,7 @@ public Collection findByKeyword(ChatRoom room, String keyword)
}
/**
* Returns all the messages exchanged
* Returns all the messages exchanged
* in the supplied chat room having the given keyword
*
* @param room The chat room
@ -1497,7 +1497,7 @@ public Collection findByKeyword(ChatRoom room, String keyword)
* @return Collection of MessageReceivedEvents or MessageDeliveredEvents
* @throws RuntimeException
*/
public Collection findByKeyword(ChatRoom room, String keyword,
public Collection findByKeyword(ChatRoom room, String keyword,
boolean caseSensitive)
throws RuntimeException
{
@ -1505,7 +1505,7 @@ public Collection findByKeyword(ChatRoom room, String keyword,
try
{
// get the readers for this room
HistoryReader reader =
HistoryReader reader =
this.getHistoryForMultiChat(null, room).getReader();
// add the progress listeners
@ -1529,7 +1529,7 @@ public Collection findByKeyword(ChatRoom room, String keyword,
}
/**
* Returns all the messages exchanged
* Returns all the messages exchanged
* in the supplied chat room having the given keywords
*
* @param room The chat room
@ -1544,7 +1544,7 @@ public Collection findByKeywords(ChatRoom room, String[] keywords)
}
/**
* Returns all the messages exchanged
* Returns all the messages exchanged
* in the supplied chat room having the given keywords
*
* @param room The chat room
@ -1553,7 +1553,7 @@ public Collection findByKeywords(ChatRoom room, String[] keywords)
* @return Collection of MessageReceivedEvents or MessageDeliveredEvents
* @throws RuntimeException
*/
public Collection findByKeywords(ChatRoom room, String[] keywords,
public Collection findByKeywords(ChatRoom room, String[] keywords,
boolean caseSensitive)
throws RuntimeException
{
@ -1561,7 +1561,7 @@ public Collection findByKeywords(ChatRoom room, String[] keywords,
try
{
// get the readers for this room
HistoryReader reader =
HistoryReader reader =
this.getHistoryForMultiChat(null, room).getReader();
// add the progress listeners
@ -1580,12 +1580,12 @@ public Collection findByKeywords(ChatRoom room, String[] keywords,
{
logger.error("Could not read history", e);
}
return result;
}
/**
* Returns the supplied number of recent messages exchanged
* Returns the supplied number of recent messages exchanged
* in the supplied chat room
*
* @param room The chat room
@ -1597,12 +1597,12 @@ public Collection findLast(ChatRoom room, int count)
throws RuntimeException
{
TreeSet result = new TreeSet(new ChatRoomMessageEventComparator());
try
{
// get the readers for this room
HistoryReader reader =
this.getHistoryForMultiChat(null, room).getReader();
HistoryReader reader =
this.getHistoryForMultiChat(null, room).getReader();
Iterator recs = reader.findLast(count);
while (recs.hasNext())
{
@ -1616,7 +1616,7 @@ public Collection findLast(ChatRoom room, int count)
{
logger.error("Could not read history", e);
}
LinkedList resultAsList = new LinkedList(result);
int startIndex = resultAsList.size() - count;
@ -1643,7 +1643,7 @@ public Collection findFirstMessagesAfter(ChatRoom room, Date date, int count)
try
{
HistoryReader reader =
HistoryReader reader =
this.getHistoryForMultiChat(null, room).getReader();
Iterator recs = reader.findFirstRecordsAfter(date, count);
while (recs.hasNext())
@ -1660,11 +1660,11 @@ public Collection findFirstMessagesAfter(ChatRoom room, Date date, int count)
}
LinkedList resultAsList = new LinkedList(result);
int toIndex = count;
if(toIndex > resultAsList.size())
toIndex = resultAsList.size();
return resultAsList.subList(0, toIndex);
}
@ -1685,7 +1685,7 @@ public Collection findLastMessagesBefore(ChatRoom room, Date date, int count)
try
{
HistoryReader reader =
HistoryReader reader =
this.getHistoryForMultiChat(null, room).getReader();
Iterator recs = reader.findLastRecordsBefore(date, count);
while (recs.hasNext())
@ -1709,7 +1709,7 @@ public Collection findLastMessagesBefore(ChatRoom room, Date date, int count)
return resultAsList.subList(startIndex, resultAsList.size());
}
public static ResourceManagementService getResources()
{
if (resourcesService == null)
@ -1719,8 +1719,8 @@ public static ResourceManagementService getResources()
if(serviceReference == null)
return null;
resourcesService = (ResourceManagementService)
resourcesService = (ResourceManagementService)
MessageHistoryActivator.bundleContext
.getService(serviceReference);
}
@ -1742,7 +1742,7 @@ private class SearchProgressWrapper
double accumulatedRatio = 0;
double currentProgress = 0;
double lastHistoryProgress = 0;
// used for more precise calculations with double values
int raiser = 1000;
@ -1750,12 +1750,12 @@ private class SearchProgressWrapper
{
this.listener = listener;
}
private void setCurrentValues(HistoryReader currentReader, int allRecords)
{
this.allRecords = allRecords;
this.reader = currentReader;
currentReaderProgressRatio =
currentReaderProgressRatio =
(double)currentReader.countRecords()/allRecords * raiser;
accumulatedRatio += currentReaderProgressRatio;
}
@ -1779,15 +1779,15 @@ public void progressChanged(ProgressEvent evt)
*/
private int getProgressMapping(ProgressEvent evt)
{
double tmpHistoryProgress =
double tmpHistoryProgress =
currentReaderProgressRatio * evt.getProgress();
currentProgress += tmpHistoryProgress - lastHistoryProgress;
if(evt.getProgress() == HistorySearchProgressListener.PROGRESS_MAXIMUM_VALUE)
{
lastHistoryProgress = 0;
// this is the last one and the last event fire the max
// there will be looses in currentProgress due to the devision
if((int)accumulatedRatio == raiser)
@ -1796,7 +1796,7 @@ private int getProgressMapping(ProgressEvent evt)
}
else
lastHistoryProgress = tmpHistoryProgress;
return (int)currentProgress;
}
@ -1804,7 +1804,7 @@ private int getProgressMapping(ProgressEvent evt)
* clear the values
*/
void clear()
{
{
allRecords = 0;
currentProgress = 0;
lastHistoryProgress = 0;
@ -1866,9 +1866,9 @@ else if(o2 instanceof MessageReceivedEvent)
return date1.compareTo(date2);
}
}
/**
* Used to compare ChatRoomMessageDeliveredEvent
* Used to compare ChatRoomMessageDeliveredEvent
* or ChatRoomMessageReceivedEvent
* and to be ordered in TreeSet according their timestamp
*/
@ -1879,7 +1879,7 @@ public int compare(Object o1, Object o2)
{
Date date1 = null;
Date date2 = null;
if(o1 instanceof ChatRoomMessageDeliveredEvent)
date1 = ((ChatRoomMessageDeliveredEvent)o1).getTimestamp();
else if(o1 instanceof ChatRoomMessageReceivedEvent)
@ -1897,7 +1897,7 @@ else if(o2 instanceof ChatRoomMessageReceivedEvent)
return date1.compareTo(date2);
}
}
/**
* Simple ChatRoomMember implementation.
*/
@ -1908,7 +1908,7 @@ class ChatRoomMemberImpl
private String name;
private ChatRoomMemberRole role;
public ChatRoomMemberImpl(String name, ChatRoom chatRoom,
public ChatRoomMemberImpl(String name, ChatRoom chatRoom,
ChatRoomMemberRole role)
{
this.chatRoom = chatRoom;
@ -1941,7 +1941,7 @@ public ChatRoomMemberRole getRole()
return role;
}
}
/**
* Handles <tt>PropertyChangeEvent</tt> triggered from the modification of
* the isMessageHistoryEnabled property.

@ -155,6 +155,14 @@ public Call createCall(Contact callee) throws OperationFailedException
private synchronized CallSipImpl createOutgoingCall(Address calleeAddress)
throws OperationFailedException
{
if(!protocolProvider.isRegistered())
{
throw new OperationFailedException(
"The protocol provider should be registered "
+"before placing an outgoing call.",
OperationFailedException.PROVIDER_NOT_REGISTERED);
}
// create the invite request
Request invite = createInviteRequest(calleeAddress);

@ -27,7 +27,8 @@ public class ProtocolProviderFactorySipImpl
/**
* The table that we store our accounts in.
*/
private Hashtable registeredAccounts = new Hashtable();
private Hashtable<AccountID, ServiceRegistration> registeredAccounts
= new Hashtable<AccountID, ServiceRegistration>();
/**
* Constructs a new instance of the ProtocolProviderFactorySipImpl.
@ -63,9 +64,9 @@ public ServiceReference getProviderForAccount(AccountID accountID)
* @return a copy of the llist containing all accounts currently installed
* in the protocol provider.
*/
public ArrayList getRegisteredAccounts()
public ArrayList<AccountID> getRegisteredAccounts()
{
return new ArrayList(registeredAccounts.keySet());
return new ArrayList<AccountID>(registeredAccounts.keySet());
}
/**
@ -153,7 +154,7 @@ public AccountID installAccount( String userIDStr,
* the modified account.
* @param accountProperties a set of protocol (or implementation) specific
* properties defining the new account.
*
*
* @throws java.lang.NullPointerException if any of the arguments is null.
*/
public void modifyAccount( ProtocolProviderService protocolProvider,
@ -235,7 +236,7 @@ public void modifyAccount( ProtocolProviderService protocolProvider,
+ ex.getMessage());
}
}
/**
* Initializes and creates an account corresponding to the specified
* accountProperties and registers the resulting ProtocolProvider in the

@ -312,6 +312,9 @@ public class ProtocolProviderServiceSipImpl
*/
private ProtocolIconSipImpl protocolIcon;
/**
* The presence status set supported by this provider
*/
private SipStatusEnum sipStatusEnum;
/**
@ -2107,7 +2110,7 @@ else if(proxyTransport.equalsIgnoreCase(ListeningPoint.TLS))
* so that it would receives all messages in a transaction initiated by a
* <tt>method</tt> request. If any previous processors exist for the same
* method, they will be replaced by this one.
*
*
* @param method a String representing the SIP method that we're registering
* the processor for (e.g. INVITE, REGISTER, or SUBSCRIBE).
* @param methodProcessor a <tt>MethodProcessor</tt> implementation that
@ -2143,7 +2146,7 @@ public void registerMethodProcessor(String method,
* Unregisters <tt>methodProcessor</tt> from the <tt>methorProcessors</tt>
* table so that it won't receive further messages in a transaction
* initiated by a <tt>method</tt> request.
*
*
* @param method the name of the method whose processor we'd like to
* unregister.
* @param methodProcessor

@ -10,6 +10,7 @@
import org.osgi.framework.*;
import net.java.sip.communicator.service.configuration.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.netaddr.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
@ -26,15 +27,18 @@ public class SipActivator
private Logger logger = Logger.getLogger(SipActivator.class.getName());
private ServiceRegistration sipPpFactoryServReg = null;
static BundleContext bundleContext = null;
static BundleContext bundleContext = null;
private static ConfigurationService configurationService = null;
private static NetworkAddressManagerService networkAddressManagerService
= null;
= null;
private static MediaService mediaService = null;
private static VersionService versionService = null;
private static UIService uiService = null;
private static ProtocolProviderFactorySipImpl sipProviderFactory = null;
private static UriHandlerSipImpl uriHandler = null;
/**
* Called when this bundle is started so the Framework can perform the
* bundle-specific activities necessary to start this bundle.
@ -63,6 +67,8 @@ public void start(BundleContext context) throws Exception
sipProviderFactory,
hashtable);
uriHandler = new UriHandlerSipImpl(sipProviderFactory);
logger.debug("SIP Protocol Provider Factory ... [REGISTERED]");
}
@ -148,7 +154,7 @@ public static MediaService getMediaService()
}
return mediaService;
}
/**
* Returns a reference to a VersionService implementation currently registered
* in the bundle context or null if no such implementation was found.
@ -169,6 +175,26 @@ public static VersionService getVersionService()
return versionService;
}
/**
* Returns a reference to the UIService implementation currently registered
* in the bundle context or null if no such implementation was found.
*
* @return a reference to a UIService implementation currently registered
* in the bundle context or null if no such implementation was found.
*/
public static UIService getUIService()
{
if(uiService == null)
{
ServiceReference uiServiceReference
= bundleContext.getServiceReference(
UIService.class.getName());
uiService = (UIService)bundleContext
.getService(uiServiceReference);
}
return uiService;
}
/**
* Called when this bundle is stopped so the Framework can perform the
* bundle-specific activities necessary to stop the bundle.

@ -0,0 +1,185 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.sip;
import java.net.*;
import java.text.*;
import java.util.*;
import java.util.logging.Level;
import javax.sip.*;
import javax.sip.address.*;
import javax.sip.header.*;
import javax.sip.message.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
/**
* Allows SIP communicator to create SIP accounts without a registrar. We use
* this class as a replacement of the SipRegistrarConnection for accounts that
* do not have a configured registrar.
*
* @author Emil Ivov
*/
public class SipRegistrarlessConnection
extends SipRegistrarConnection
{
private static final Logger logger =
Logger.getLogger(SipRegistrarlessConnection.class);
/**
* A reference to the sip provider that created us.
*/
private ProtocolProviderServiceSipImpl sipProvider = null;
/**
* Keeps our current registration state.
*/
private RegistrationState currentRegistrationState
= RegistrationState.UNREGISTERED;
/**
* Creates a new instance of this class.
*
* @param sipProviderCallback a reference to the
* ProtocolProviderServiceSipImpl instance that created us.
*
*/
public SipRegistrarlessConnection(
ProtocolProviderServiceSipImpl sipProviderCallback)
{
this.sipProvider = sipProviderCallback;
}
/**
* Simply sets the state of the connection to REGISTERED without doing
* anything else.
*
* @throws OperationFailedException never thrown
*/
@Override
void register()
throws OperationFailedException
{
setRegistrationState(RegistrationState.REGISTERED,
RegistrationStateChangeEvent.REASON_USER_REQUEST,
null);
}
/**
* Simply sets the state of the connection to UNREGISTERED without doing
* anything else.
*
* @throws OperationFailedException never thrown.
*/
@Override
public void unregister() throws OperationFailedException
{
setRegistrationState(RegistrationState.UNREGISTERED,
RegistrationStateChangeEvent.REASON_USER_REQUEST,
null);
}
/**
* Returns the state of this connection.
*
* @return a RegistrationState instance indicating the state of our
* registration with the corresponding registrar.
*/
@Override
public RegistrationState getRegistrationState()
{
return currentRegistrationState;
}
/**
* Sets our registration state to <tt>newState</tt> and dispatches an event
* through the protocol provider service impl.
* <p>
* @param newState a reference to the RegistrationState that we're currently
* detaining.
* @param reasonCode one of the REASON_XXX error codes specified in
* {@link RegistrationStateChangeEvent}.
* @param reason a reason String further explaining the reasonCode.
*/
@Override
public void setRegistrationState(RegistrationState newState,
int reasonCode,
String reason)
{
if( currentRegistrationState.equals(newState) )
{
return;
}
RegistrationState oldState = currentRegistrationState;
this.currentRegistrationState = newState;
sipProvider.fireRegistrationStateChanged(
oldState, newState, reasonCode, reason);
}
/**
* Returns the address of this connection's registrar.
*
* @return the InetAddress of our registrar server.
*/
@Override
public InetAddress getRegistrarAddress()
{
try
{
return InetAddress.getByAddress("2001:1890:1112:1::20",
new byte[]{(byte) 20, (byte) 01, (byte) 18, (byte) 90,
(byte) 11, (byte) 11, (byte) 12, (byte) 00,
(byte) 01, (byte) 00, (byte) 00, (byte) 00,
(byte) 00, (byte) 00, (byte) 00, (byte) 20});
} catch (UnknownHostException ex)
{
logger.error("Failed to generate a dummy registrar addr", ex);
return null;
}
}
/**
* Returns the listening point that should be used for communication with our
* current registrar.
*
* @return the listening point that should be used for communication with our
* current registrar.
*/
@Override
public ListeningPoint getRegistrarListeningPoint()
{
return sipProvider.getDefaultListeningPoint();
}
/**
* Returns a string representation of this connection instance
* instance including information that would permit to distinguish it among
* other sip listeners when reading a log file.
* <p>
* @return a string representation of this operation set.
*/
@Override
public String toString()
{
String className = getClass().getName();
try
{
className = className.substring(className.lastIndexOf('.') + 1);
}
catch (Exception ex)
{
// we don't want to fail in this method because we've messed up
//something with indexes, so just ignore.
}
return className + "-[dn=" + sipProvider.getOurDisplayName()
+" addr="+sipProvider.getOurSipAddress() + "]";
}
}

@ -0,0 +1,524 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.sip;
import java.text.*;
import java.util.*;
import org.osgi.framework.*;
import net.java.sip.communicator.impl.systray.*;
import net.java.sip.communicator.service.argdelegation.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
/**
* The sip implementation of the URI handler. This class handles sip URIs by
* trying to establish a call to them.
*
* @author Emil Ivov
*/
public class UriHandlerSipImpl
implements UriHandler,
ServiceListener
{
private static final Logger logger =
Logger.getLogger(UriHandlerSipImpl.class);
/**
* The protocol provider factory that created us.
*/
private ProtocolProviderFactory protoFactory = null;
/**
* A reference to the OSGi registration we create with this handler.
*/
private ServiceRegistration ourServiceRegistration = null;
/**
* The object that we are using to synchronize our service registration.
*/
private Object registrationLock = new Object();
/**
* Creates an instance of this uri handler, so that it would start handling
* URIs by passing them to the providers registered by <tt>protoFactory</tt>.
*
* @param parentProvider the provider that created us.
*
* @throws NullPointerException if <tt>protoFactory</tt> is <tt>null</tt>.
*/
protected UriHandlerSipImpl(ProtocolProviderFactory protoFactory)
throws NullPointerException
{
if(protoFactory == null)
{
throw new NullPointerException(
"The ProtocolProviderFactory that a UriHandler is created with "
+ " cannot be null.");
}
this.protoFactory = protoFactory;
//we listen for service events so that we can disable ourselves in
//case our protocol factory decides to leave.
SipActivator.bundleContext.addServiceListener(this);
registerHandlerService();
}
/**
* Registers this UriHandler with the bundle context so that it could
* start handling URIs
*/
private void registerHandlerService()
{
synchronized(registrationLock)
{
if (ourServiceRegistration != null)
{
// ... we are already registered (this is probably
// happening during startup)
return;
}
Hashtable<String, String> registrationProperties
= new Hashtable<String, String>();
registrationProperties.put(UriHandler.PROTOCOL_PROPERTY,
getProtocol());
ourServiceRegistration = SipActivator.bundleContext
.registerService(UriHandler.class.getName(), this,
registrationProperties);
}
}
/**
* Unregisters this UriHandler from the bundle context.
*/
private void unregisterHandlerService()
{
synchronized(registrationLock)
{
ourServiceRegistration.unregister();
ourServiceRegistration = null;
}
}
/**
* Returns the protocol that this handler is responsible for or "sip" in
* other words.
*
* @return the "sip" string to indicate that this handler is responsible
* for handling "sip" uris.
*/
public String getProtocol()
{
return "sip";
}
/**
* Parses the specified URI and creates a call with the currently active
* telephony operation set.
*
* @param uri the SIP URI that we have to call.
*/
public void handleUri(String uri)
{
ProtocolProviderService provider;
try
{
provider = selectHandlingProvider(uri);
}
catch (OperationFailedException exc)
{
// The operation has been canceled by the user. Bail out.
logger.trace("User canceled handling of uri " + uri);
return;
}
//if provider is null then we need to tell the user to create an account
if(provider == null)
{
showErrorMessage(
"You need to configure at least one "
+ "SIP" +" account \n"
+"to be able to call " + uri,
null);
return;
}
OperationSetBasicTelephony telephonyOpSet
= (OperationSetBasicTelephony) provider
.getOperationSet(OperationSetBasicTelephony.class);
try
{
telephonyOpSet.createCall(uri);
}
catch (OperationFailedException exc)
{
//make sure that we prompt for registration only if it is really
//required by the provider.
if(exc.getErrorCode()
== OperationFailedException.PROVIDER_NOT_REGISTERED)
{
promptForRegistration(uri, provider);
}
showErrorMessage("Failed to create a call to " + uri, exc);
}
catch (ParseException exc)
{
showErrorMessage(
uri + " does not appear to be a valid SIP address",
exc);
}
}
/**
* Informs the user that they need to be registered before placing calls
* and asks them whether they would like us to do it for them.
*
* @param uri the uri that the user would like us to call after registering.
* @param provider the provider that we may have to reregister.
*/
private void promptForRegistration(String uri,
ProtocolProviderService provider)
{
int answer = SipActivator.getUIService()
.getPopupDialog().showConfirmPopupDialog(
"You need to be online in order to make a call and your "
+ "account is currently offline. Do want to connect now?",
"Account is currently offline",
PopupDialog.YES_NO_OPTION);
if(answer == PopupDialog.YES_OPTION)
{
new ProtocolRegistrationThread(uri, provider).start();
}
}
/**
* The point of implementing a service listener here is so that we would
* only register our own uri handling service and thus only handle URIs
* while the factory is available as an OSGi service. We remove ourselves
* when our factory unregisters its service reference.
*
* @param event the OSGi <tt>ServiceEvent</tt>
*/
public void serviceChanged(ServiceEvent event)
{
Object sourceService = SipActivator.bundleContext
.getService(event.getServiceReference());
//ignore anything but our protocol factory.
if( ! (sourceService instanceof ProtocolProviderFactorySipImpl)
|| (sourceService != protoFactory))
{
return;
}
if(event.getType() == ServiceEvent.REGISTERED)
{
//our factory has just been registered as a service ...
registerHandlerService();
}
else if(event.getType() == ServiceEvent.UNREGISTERING)
{
//our factory just died - seppuku.
unregisterHandlerService();
}
else if(event.getType() == ServiceEvent.MODIFIED)
{
//we don't care.
}
}
/**
* Uses the <tt>UIService</tt> to show an error <tt>message</tt> and log
* and <tt>exception</tt>.
*
* @param message the message that we'd like to show to the user.
* @param exc the exception that we'd like to log
*/
private void showErrorMessage(String message, Exception exc)
{
SipActivator.getUIService().getPopupDialog().showMessagePopupDialog(
message,
"Failed to create call!",
PopupDialog.ERROR_MESSAGE);
logger.error(message, exc);
}
/**
* We use this class when launching a provider registration by ourselves in
* order to track for provider registration states and retry uri handling,
* once the provider is registered.
*
*/
private class ProtocolRegistrationThread
extends Thread
implements SecurityAuthority,
RegistrationStateChangeListener
{
private boolean isUserNameEditable = false;
private ProtocolProviderService handlerProvider = null;
/**
* The URI that we'd need to re-call.
*/
private String uri = null;
/**
* Configures this thread register our parent provider and re-attempt
* connection to the specified <tt>uri</tt>.
*
* @param uri the uri that we need to handle.
* @param handlerProvider the provider that we are going to make
* register and that we are going to use to handle the <tt>uri</tt>.
*/
public ProtocolRegistrationThread(
String uri,
ProtocolProviderService handlerProvider)
{
super("UriHandlerProviderRegistrationThread:uri=" + uri);
this.uri = uri;
this.handlerProvider = handlerProvider;
}
/**
* Used to login to the protocol providers
*
* @param realm the realm that the credentials are needed for
* @param userCredentials the values to propose the user by default
* @return The Credentials associated with the speciefied realm
*/
public UserCredentials obtainCredentials(
String realm,
UserCredentials userCredentials)
{
return obtainCredentials( realm,
userCredentials,
SecurityAuthority.AUTHENTICATION_REQUIRED);
}
/**
* Used to login to the protocol providers
*
* @param realm the realm that the credentials are needed for
* @param userCredentials the values to propose the user by default
* @param reasonCode the reason for which we're asking for credentials
* @return The Credentials associated with the speciefied realm
*/
public UserCredentials obtainCredentials(
String realm,
UserCredentials userCredentials,
int reasonCode)
{
ExportedWindow loginWindow
= SystrayActivator.getUIService()
.getAuthenticationWindow(handlerProvider,
realm,
userCredentials,
isUserNameEditable);
loginWindow.setVisible(true);
return userCredentials;
}
/**
* Sets the userNameEditable property, which should indicate to the
* implementations of this interface if the user name could be changed
* by user or not.
*
* @param isUserNameEditable indicates if the user name could be changed
* by user in the implementation of this interface.
*/
public void setUserNameEditable(boolean isUserNameEditable)
{
this.isUserNameEditable = isUserNameEditable;
}
/**
* Indicates if the user name is currently editable, i.e. could be
* changed by user or not.
*
* @return <tt>true</tt> if the user name could be changed and
* <tt>false</tt> otherwise.
*/
public boolean isUserNameEditable()
{
return isUserNameEditable;
}
/**
* Starts the registration process, ads this class as a registration
* listener and then tries to rehandle the uri this thread was initiaded
* with.
*/
@Override
public void run()
{
handlerProvider.addRegistrationStateChangeListener(this);
try
{
handlerProvider.register(this);
}
catch (OperationFailedException exc)
{
logger.error("Failed to manually register provider.");
logger.warn(exc.getMessage(), exc);
}
}
/**
* If the parent provider passes into the registration state, the method
* re-handles the URI that this thread was initiated with. The method
* would only rehandle the uri if the event shows successful
* registration. It would ignore intermediate states such as
* REGISTERING. Disconnection and failure events would simply cause this
* listener to remove itself from the list of registration listeners.
*
* @param evt the <tt>RegistrationStateChangeEvent</tt> that this
* thread was initiated with.
*/
public void registrationStateChanged(RegistrationStateChangeEvent evt)
{
if (evt.getNewState() == RegistrationState.REGISTERED)
{
Thread uriRehandleThread = new Thread()
{
public void run()
{
handleUri(uri);
}
};
uriRehandleThread.setName("UriRehandleThread:uri="+uri);
uriRehandleThread.start();
}
//we're only interested in a single event so we stop listening
//(unless this was a REGISTERING notification)
if(evt.getNewState() == RegistrationState.REGISTERING)
return;
handlerProvider.removeRegistrationStateChangeListener(this);
}
}
/**
* Returns the default provider that we are supposed to handle URIs through
* or null if there aren't any. Depending on the implementation this
* method may require user intervention so make sure you don't rely on
* a quick outcome when calling it.
*
* @param uri the uri that we'd like to handle with the provider that we are
* about to select.
*
* @return the provider that we should handle URIs through.
*
* @throws OperationFailedException with code <tt>OPERATION_CANCELED</tt>
* if the users.
*/
public ProtocolProviderService selectHandlingProvider(String uri)
throws OperationFailedException
{
ArrayList<AccountID> registeredAccounts
= protoFactory.getRegisteredAccounts();
//if we don't have any providers - return null.
if(registeredAccounts.size() == 0)
{
return null;
}
//if we only have one provider - select it
if(registeredAccounts.size() == 1)
{
ServiceReference providerReference
= protoFactory.getProviderForAccount(registeredAccounts.get(0));
ProtocolProviderService provider = (ProtocolProviderService)
SipActivator.getBundleContext().getService(providerReference);
return provider;
}
//otherwise - ask the user.
ArrayList<ProviderComboBoxEntry> providers
= new ArrayList<ProviderComboBoxEntry>();
for (AccountID accountID : registeredAccounts)
{
ServiceReference providerReference
= protoFactory.getProviderForAccount(accountID);
ProtocolProviderService provider = (ProtocolProviderService)
SipActivator.getBundleContext().getService(providerReference);
providers.add( new ProviderComboBoxEntry( provider ) );
}
Object result = SipActivator.getUIService().getPopupDialog()
.showInputPopupDialog(
"Please select the account that you would like \n"
+ "to use to call "
+ uri,
"Account Selection",
PopupDialog.OK_CANCEL_OPTION,
providers.toArray(),
providers.get(0));
if( result == null)
{
throw new OperationFailedException(
"Operation cancelled",
OperationFailedException.OPERATION_CANCELED);
}
return ((ProviderComboBoxEntry)result).provider;
}
/**
* A class that we use to wrap providers before showing them to the user
* through a selection popup dialog from the UIService.
*/
private class ProviderComboBoxEntry
{
public ProtocolProviderService provider;
public ProviderComboBoxEntry(ProtocolProviderService provider)
{
this.provider = provider;
}
/**
* Returns a human readable <tt>String</tt> representing the
* provider encapsulated by this class.
*
* @return a human readable string representing the provider.
*/
@Override
public String toString()
{
return provider.getAccountID().getAccountAddress();
}
}
}

@ -8,6 +8,8 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.configuration,
net.java.sip.communicator.util,
net.java.sip.communicator.util.xml,
net.java.sip.communicator.service.argdelegation,
net.java.sip.communicator.service.gui,
net.java.sip.communicator.service.configuration.event,
net.java.sip.communicator.service.resources,
net.java.sip.communicator.service.protocol,

@ -19,19 +19,17 @@
* continue its execution during this operation.
*
* @author Nicolas Chamouard
* @author Emil Ivov
*/
public class ProviderRegistration
extends Thread
implements SecurityAuthority
{
/**
* The protocol provider to whom we want to register
*/
private ProtocolProviderService protocolProvider;
private boolean isUserNameEditable = false;
/**
* The logger for this class.
*/
@ -53,8 +51,10 @@ public ProviderRegistration(ProtocolProviderService protocolProvider)
*/
public void run()
{
try {
protocolProvider.register(this);
try
{
protocolProvider.register(SystrayActivator.getUIService()
.getDefaultSecurityAuthority(protocolProvider));
}
catch (OperationFailedException ex)
{
@ -86,69 +86,4 @@ else if (errorCode == OperationFailedException
}
}
}
/**
* Used to login to the protocol providers
*
* @param realm the realm that the credentials are needed for
* @param userCredentials the values to propose the user by default
* @param reasonCode the reason for which we're asking for credentials
* @return The Credentials associated with the speciefied realm
*/
public UserCredentials obtainCredentials(
String realm,
UserCredentials userCredentials,
int reasonCode)
{
ExportedWindow loginWindow
= SystrayActivator.getUIService()
.getAuthenticationWindow(protocolProvider,
realm,
userCredentials,
isUserNameEditable);
loginWindow.setVisible(true);
return userCredentials;
}
/**
* Used to login to the protocol providers
*
* @param realm the realm that the credentials are needed for
* @param userCredentials the values to propose the user by default
* @return The Credentials associated with the speciefied realm
*/
public UserCredentials obtainCredentials(
String realm,
UserCredentials userCredentials)
{
return obtainCredentials( realm,
userCredentials,
SecurityAuthority.AUTHENTICATION_REQUIRED);
}
/**
* Sets the userNameEditable property, which should indicate to the
* implementations of this interface if the user name could be changed by
* user or not.
*
* @param isUserNameEditable indicates if the user name could be changed by
* user in the implementation of this interface.
*/
public void setUserNameEditable(boolean isUserNameEditable)
{
this.isUserNameEditable = isUserNameEditable;
}
/**
* Indicates if the user name is currently editable, i.e. could be changed
* by user or not.
*
* @return <code>true</code> if the user name could be changed,
* <code>false</code> - otherwise.
*/
public boolean isUserNameEditable()
{
return isUserNameEditable;
}
}

@ -9,25 +9,28 @@
import java.awt.*;
import java.io.*;
import net.java.sip.communicator.util.launchutils.*;
import org.apache.felix.main.*;
/**
* Starts the SIP Communicator.
*
*
* @author Yana Stamcheva
* @author Lubomir Marinov
* @author Emil Ivov
*/
public class SIPCommunicator
{
private static final String PNAME_SC_HOME_DIR_LOCATION =
public static final String PNAME_SC_HOME_DIR_LOCATION =
"net.java.sip.communicator.SC_HOME_DIR_LOCATION";
private static final String PNAME_SC_HOME_DIR_NAME =
public static final String PNAME_SC_HOME_DIR_NAME =
"net.java.sip.communicator.SC_HOME_DIR_NAME";
/**
* Starts the SIP Communicator.
*
*
* @param args
*/
public static void main(String[] args)
@ -68,6 +71,51 @@ else if (osName.startsWith("Windows"))
return;
}
//first - pass the arguments to our arg handler
LaunchArgHandler argHandler = LaunchArgHandler.getInstance();
int argHandlerRes = argHandler.handleArgs(args);
if ( argHandlerRes == LaunchArgHandler.ACTION_EXIT
|| argHandlerRes == LaunchArgHandler.ACTION_ERROR)
{
System.exit(argHandler.getErrorCode());
}
//lock our config di so that we would only have a single instance of
//sip communicator, no matter how many times we start it (use mainly
//for handling sip: uris after starting the application)
if ( argHandlerRes != LaunchArgHandler.ACTION_CONTINUE_MULTIINSTANCE )
{
SipCommunicatorLock lock = new SipCommunicatorLock();
int lockResult = lock.tryLock(args);
if( lockResult == SipCommunicatorLock.LOCK_ERROR )
{
System.err.print("Failed to lock SIP Communicator's "
+"configuration directory.\n"
+"Try launching with the --multiple param.");
System.exit(SipCommunicatorLock.LOCK_ERROR);
}
else if(lockResult == SipCommunicatorLock.ALREADY_STARTED)
{
System.err.print(
"SIP Communicator is already running and will "
+"handle your parameters (if any).\n"
+"Launch with the --multiple param to override this "
+"behaviour.");
//we exit with succes because for the user that's what it is.
System.exit(SipCommunicatorLock.SUCCESS);
}
else if(lockResult == SipCommunicatorLock.SUCCESS)
{
//Successfully locked, continue as normal.
}
}
//there was no error, continue;
Main.main(args);
}
@ -75,13 +123,12 @@ else if (osName.startsWith("Windows"))
* Sets the system properties net.java.sip.communicator.SC_HOME_DIR_LOCATION
* and net.java.sip.communicator.SC_HOME_DIR_NAME (if they aren't already
* set) in accord with the OS conventions specified by the name of the OS.
*
*
* @param osName the name of the OS according to which the SC_HOME_DIR_*
* properties are to be set
*/
private static void setScHomeDir(String osName)
{
/*
* Though we'll be setting the SC_HOME_DIR_* property values depending
* on the OS running the application, we have to make sure we are

@ -0,0 +1,35 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.service.argdelegation;
/**
* This interface is meant to be implemented by all bundles that wish to handle
* URIs passed as invocation arguments.
*
* @author Emil Ivov <emcho at sip-communicator.org>
*/
public interface UriHandler
{
/**
* The name of the property that we use in the service registration
* properties to store a protocol name when registering <tt>UriHandler</tt>s
*/
public static final String PROTOCOL_PROPERTY = "ProtocolName";
/**
* Returns the protocol that this handler is responsible for.
*/
public String getProtocol();
/**
* Handles/opens the URI.
*
* @param uri the URI that the handler has to open.
*/
public void handleUri(String uri);
}

@ -0,0 +1,5 @@
Bundle-Name: Argument Delegation Service
Bundle-Description: A service that allows bundles to register as handlers for specific command line arguments
Bundle-Vendor: sip-communicator.org
Bundle-Version: 0.0.1
Export-Package: net.java.sip.communicator.service.argdelegation

@ -23,22 +23,22 @@
* The <tt>UIService</tt> provides also methods that would allow to other
* modules to control the visibility, size and position of the main application
* window. Some of these methods are: setVisible, minimize, maximize, resize,
* move, etc.
* move, etc.
* <p>
* A way to show different types of simple windows is provided to allow other
* modules to show different simple messages, like warning or error messages.
* In order to show a simple warning message, a module should invoke the
* In order to show a simple warning message, a module should invoke the
* getPopupDialog method and then one of the showXXX methods, which corresponds
* best to the required dialog.
* best to the required dialog.
* <p>
* Certain components within the GUI, like "AddContact" window for example,
* could be also shown from outside the ui. To make one of
* these component exportable, the <tt>UIService</tt> implementation should attach
* to it an <tt>WindowID</tt>. A window then could be shown, by invoking
* <code>getExportedWindow(WindowID)</code> and then
* <code>getExportedWindow(WindowID)</code> and then
* <code>show</code>. The <tt>WindowID</tt> above should be obtained from
* <code>getSupportedExportedWindows</code>.
*
*
* @author Yana Stamcheva
*/
public interface UIService
@ -47,52 +47,52 @@ public interface UIService
* Returns TRUE if the application is visible and FALSE otherwise.
* This method is meant to be used by the systray service in order to
* detect the visibility of the application.
*
*
* @return <code>true</code> if the application is visible and
* <code>false</code> otherwise.
*
*
* @see #setVisible(boolean)
*/
public boolean isVisible();
/**
* Shows or hides the main application window depending on the value of
* parameter <code>visible</code>. Meant to be used by the systray when it
* needs to show or hide the application.
*
*
* @param visible if <code>true</code>, shows the main application window;
* otherwise, hides the main application window.
*
*
* @see #isVisible()
*/
public void setVisible(boolean visible);
/**
* Minimizes the main application window.
*/
public void minimize();
/**
* Mawimizes the main application window.
*/
public void maximize();
/**
* Restores the main application window.
*/
public void restore();
/**
* Resizes the main application window with the given width and height.
*
*
* @param width The new width.
* @param height The new height.
*/
public void resize(int width, int height);
/**
* Moves the main application window to the given coordinates.
*
*
* @param x The x coordinate.
* @param y The y coordinate.
*/
@ -103,29 +103,29 @@ public interface UIService
* application by simply closing the main application window (by clicking
* the X button or pressing Alt-F4). When set to FALSE the main application
* window will be only hidden.
*
*
* @param exitOnClose When TRUE, the user could exit the
* application by simply closing the main application window (by clicking
* the X button or pressing Alt-F4). When set to FALSE the main application
* window will be only hidden.
*/
public void setExitOnMainWindowClose(boolean exitOnClose);
/**
* Returns TRUE if the application could be exited by closing the main
* application window, otherwise returns FALSE.
*
*
* @return Returns TRUE if the application could be exited by closing the
* main application window, otherwise returns FALSE
*/
public boolean getExitOnMainWindowClose();
/**
* Returns an exported window given by the <tt>WindowID</tt>.
* This could be for example the "Add contact" window or any other window
* within the application. The <tt>windowID</tt> should be one of the
* WINDOW_XXX obtained by the <tt>getSupportedExportedWindows</tt> method.
*
*
* @param windowID One of the WINDOW_XXX WindowID-s.
* @throws IllegalArgumentException if the specified <tt>windowID</tt>
* is not recognized by the implementation (note that implementations
@ -135,20 +135,20 @@ public interface UIService
*/
public ExportedWindow getExportedWindow(WindowID windowID)
throws IllegalArgumentException;
/**
* Returns a configurable popup dialog, that could be used to show either
* a warning message, error message, information message, etc. or to prompt
* user for simple one field input or to question the user.
*
*
* @return a <code>PopupDialog</code>.
* @see PopupDialog
*/
public PopupDialog getPopupDialog();
/**
* Returns the <tt>Chat</tt> corresponding to the given <tt>Contact</tt>.
*
*
* @param contact the <tt>Contact</tt> for which the searched chat is about.
* @return the <tt>Chat</tt> corresponding to the given <tt>Contact</tt>.
*/
@ -156,7 +156,7 @@ public ExportedWindow getExportedWindow(WindowID windowID)
/**
* Returns the <tt>Chat</tt> corresponding to the given <tt>ChatRoom</tt>.
*
*
* @param chatRoom the <tt>ChatRoom</tt> for which the searched chat is
* about.
* @return the <tt>Chat</tt> corresponding to the given <tt>ChatRoom</tt>.
@ -165,18 +165,18 @@ public ExportedWindow getExportedWindow(WindowID windowID)
/**
* Returns the selected <tt>Chat</tt>.
*
*
* @return the selected <tt>Chat</tt>.
*/
public Chat getCurrentChat();
/**
* Returns an <tt>ExportableComponent</tt> that corresponds to an
* authentication window for the given protocol provider and user
* inromation. Initially this method is meant to be used by the
* <tt>SystrayService</tt> in order to show a login window when user tries
* to connect using the systray menu.
*
*
* @param protocolProvider the <tt>ProtocolProviderService</tt> for which
* the authentication window is about.
* @param realm the realm
@ -193,6 +193,22 @@ public ExportedWindow getAuthenticationWindow(
UserCredentials userCredentials,
boolean isUserNameEditable);
/**
* Returns a default implementation of the <tt>SecurityAuthority</tt>
* interface that can be used by non-UI components that would like to launch
* the registration process for a protocol provider. Initially this method
* was meant for use by the systray bundle and the protocol URI handlers.
*
* @param protocolProvider the <tt>ProtocolProviderService</tt> for which
* the authentication window is about.
*
* @return a default implementation of the <tt>SecurityAuthority</tt>
* interface that can be used by non-UI components that would like to launch
* the registration process for a protocol provider.
*/
public SecurityAuthority getDefaultSecurityAuthority(
ProtocolProviderService protocolProvider);
/**
* Returns an iterator over a set of windowID-s. Each <tt>WindowID</tt>
* points to a window in the current UI implementation. Each
@ -201,25 +217,25 @@ public ExportedWindow getAuthenticationWindow(
* bundles that would like to have access to some windows in the gui
* - for example the "Add contact" window, the "Settings" window, the
* "Chat window", etc.
*
* @return Iterator An iterator to a set containing WindowID-s
*
* @return Iterator An iterator to a set containing WindowID-s
* representing all exported windows supported by the current UI
* implementation.
*/
public Iterator getSupportedExportedWindows();
/**
* Chechks if a window with the given <tt>WindowID</tt> is contained in the
* current UI implementation.
*
*
* @param windowID one of the <tt>WindowID</tt>-s, defined in the
* <tt>ExportedWindow</tt> interface.
* <tt>ExportedWindow</tt> interface.
* @return <code>true</code> if the component with the given
* <tt>WindowID</tt> is contained in the current UI implementation,
* <code>false</code> otherwise.
*/
public boolean isExportedWindowSupported(WindowID windowID);
/**
* Returns the <tt>WizardContainer</tt> for the current
* UIService implementation. The <tt>WizardContainer</tt>
@ -228,7 +244,7 @@ public ExportedWindow getAuthenticationWindow(
* s. Each of these wizards is made for a given protocol and should provide
* a sequence of user interface forms through which the user could
* registrate a new account.
*
*
* @return Returns the <tt>AccountRegistrationWizardContainer</tt> for the
* current UIService implementation.
*/
@ -238,12 +254,12 @@ public ExportedWindow getAuthenticationWindow(
* Returns an iterator over a set containing containerID-s pointing to
* containers supported by the current UI implementation. Each containerID
* in the set is one of the CONTAINER_XXX constants. The method is meant to
* be used by plugins or bundles that would like to add components to the
* be used by plugins or bundles that would like to add components to the
* user interface. Before adding any component they should use this method
* to obtain all possible places, which could contain external components,
* like different menus, toolbars, etc.
*
* @return Iterator An iterator to a set containing containerID-s
*
* @return Iterator An iterator to a set containing containerID-s
* representing all containers supported by the current UI implementation.
*/
public Iterator getSupportedContainers();
@ -251,9 +267,9 @@ public ExportedWindow getAuthenticationWindow(
/**
* Chechks if the container with the given <tt>Container</tt> is supported
* from the current UI implementation.
*
* @param containderID One of the CONTAINER_XXX Container-s.
* @return <code>true</code> if the contaner with the given
*
* @param containderID One of the CONTAINER_XXX Container-s.
* @return <code>true</code> if the contaner with the given
* <tt>Container</tt> is supported from the current UI implementation,
* <code>false</code> otherwise.
*/

@ -121,11 +121,16 @@ public class OperationFailedException
*/
public static final int AUTHENTICATION_CANCELED = 15;
/**
* Indicates that the operation has been canceled by the user.
*/
public static final int OPERATION_CANCELED = 16;
/**
* The error code of the exception
*/
private int errorCode = GENERAL_ERROR;
/**
* Creates an exception with the specified error message and error code.
* @param message A message containing details on the error that caused the

@ -133,12 +133,12 @@ public abstract class ProtocolProviderFactory
* resource property.
*/
public static final String RESOURCE = "RESOURCE";
/**
* The name of the property under which we store resource priority.
*/
public static final String RESOURCE_PRIORITY = "RESOURCE_PRIORITY";
/**
* The name of the property under which we store the boolean value
* indicating if the user name should be automatically changed if the
@ -146,44 +146,44 @@ public abstract class ProtocolProviderFactory
* implementations.
*/
public static final String AUTO_CHANGE_USER_NAME = "AUTO_CHANGE_USER_NAME";
/**
* The name of the property under which we store the boolean value
* indicating if a password is required. Initially this property is meant to
* be used by IRC implementations.
*/
public static final String NO_PASSWORD_REQUIRED = "NO_PASSWORD_REQUIRED";
/**
* The name of the property under which we store if the presence is enabled.
*/
public static final String IS_PRESENCE_ENABLED = "IS_PRESENCE_ENABLED";
/**
* The name of the property under which we store if the p2p mode for SIMPLE
* should be forced.
*/
public static final String FORCE_P2P_MODE = "FORCE_P2P_MODE";
/**
* The name of the property under which we store the offline contact polling
* period for SIMPLE.
*/
public static final String POLLING_PERIOD = "POLLING_PERIOD";
public static final String POLLING_PERIOD = "POLLING_PERIOD";
/**
* The name of the property under which we store the chosen default
* subscription expiration value for SIMPLE.
*/
public static final String SUBSCRIPTION_EXPIRATION
= "SUBSCRIPTION_EXPIRATION";
/**
* Indicates if the server address has been validated.
*/
public static final String SERVER_ADDRESS_VALIDATED
= "SERVER_ADDRESS_VALIDATED";
/**
* Indicates if the proxy address has been validated.
*/
@ -240,7 +240,7 @@ public abstract AccountID installAccount(String userID,
* the modified account.
* @param accountProperties a set of protocol (or implementation) specific
* properties defining the new account.
*
*
* @throws java.lang.NullPointerException if any of the arguments is null.
*/
public abstract void modifyAccount(
@ -254,7 +254,7 @@ public abstract void modifyAccount(
* @return a copy of the list containing the <tt>AccountID</tt>s of all
* accounts currently registered in this protocol provider.
*/
public abstract ArrayList getRegisteredAccounts();
public abstract ArrayList<AccountID> getRegisteredAccounts();
/**
* Returns the ServiceReference for the protocol provider corresponding to
@ -531,7 +531,7 @@ protected void loadStoredAccounts(BundleContext bundleContext)
Base64.decode(storedPropertyValue));
}
}
if(storedPropertyValue != null)
accountProperties.put(propertyName, storedPropertyValue);
}
@ -558,7 +558,7 @@ protected void loadStoredAccounts(BundleContext bundleContext)
*
* @param accountProperties a set of protocol (or implementation)
* specific properties defining the new account.
*
*
* @return the AccountID of the newly loaded account
*/
protected abstract AccountID loadAccount( Map accountProperties);

@ -0,0 +1,404 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.util.launchutils;
import java.util.*;
import net.java.sip.communicator.util.*;
import java.io.*;
/**
* The <tt>LauncherArgHandler</tt> class handles invocation arguments that have
* been passed to us when running SIP Communicator. The class supports a fixed
* set of options and also allows for registration of delegates.
*
* @author Emil Ivov <emcho at sip-communicator.org>
*/
public class LaunchArgHandler
{
private static final Logger logger =
Logger.getLogger(LaunchArgHandler.class);
/**
* The name of the property that contains the location of the SC
* configuration directory.
*/
private static final String PNAME_SC_HOME_DIR_LOCATION =
"net.java.sip.communicator.SC_HOME_DIR_LOCATION";
/**
* The name of the property that contains the name of the SC configuration
* directory.
*/
private static final String PNAME_SC_HOME_DIR_NAME =
"net.java.sip.communicator.SC_HOME_DIR_NAME";
/**
* Returned by the <tt>handleArgs</tt> methods when the arguments that have
* been parsed do not require for SIP Communicator to be started and the
* Launcher is supposed to exit. That could happen when "SIP Communicator"
* is launched with a --version argument for example or when trying to
* run the application after an instance was already launched.
*/
public static final int ACTION_EXIT = 0;
/**
* Returned by the <tt>handleArgs</tt> methods when all arguments have been
* parsed and the SIP Communicator launch can continue.
*/
public static final int ACTION_CONTINUE = 1;
/**
* Returned by the <tt>handleArgs</tt> method when parsing the arguments
* has failed or if no arguments were passed and an instance of SC was
* already launched. If this is the code returned by handleArgs, then the
* <tt>getErrorCode</tt> method would return an error code indicating what
* the error was.
*/
public static final int ACTION_ERROR = 2;
/**
* Returned by the <tt>handleArgs</tt> methods when all arguments have been
* successfully parsed and one of them indicates that the user has requested
* a multi instance launch.
*/
public static final int ACTION_CONTINUE_MULTIINSTANCE = 3;
/**
* The error code returned when we couldn't parse one of the options.
*/
public static final int ERROR_CODE_UNKNOWN_ARG = 1;
/**
* The error code returned when we try to launch SIP Communicator while
* there is already a running instance and there were no arguments that we
* forward to that instance.
*/
public static final int ERROR_CODE_ALREADY_STARTED = 2;
/**
* The error code that we return when we fail to create a directory that has
* been specified with the -c|--config option.
*/
public static final int ERROR_CODE_CREATE_DIR_FAILED = 3;
/**
* The property name containing the name of the application
* (e.g. SIP Communicator)
*/
private static final String PNAME_APPLICATION_NAME = "APPLICATION_NAME";
/**
* The property name containing the current version.
*/
private static final String PNAME_VERSION = "APPLICATION_VERSION";
/**
* The name of the file containing version properties for use with the
* argument handler.
*/
private static final String VERSION_PROPERTIES = "version.properties";
/**
* The errorCode identifying the error that occurred last time
* <tt>handleArgs</tt> was called.
*/
private int errorCode = 0;
/**
* A reference to the instance of the
*/
private UriArgManager uriArgManager = new UriArgManager();
/**
* The singleton instance of this handler.
*/
private static LaunchArgHandler argHandler = null;
private Properties versionProperties = new Properties();
/**
* Creates the sole instance of this class;
*/
private LaunchArgHandler()
{
try
{
versionProperties.load(
getClass().getResourceAsStream(VERSION_PROPERTIES));
}
catch(IOException exc)
{
//no need to worry the user, so only print if we're in FINEST
logger.trace("Couldn't open version.properties");
}
}
/**
* Creates a singleton instance of the LauncherArgHandler if necessary and
* returns a reference to it.
*
* @return the singleton instance of the LauncherArgHandler.
*/
public static LaunchArgHandler getInstance()
{
if(argHandler == null)
{
argHandler = new LaunchArgHandler();
}
return argHandler;
}
/**
* Does the actual argument handling.
*
* @param args the arguments the way we have received them from the main()
* method.
*
* @return one of the ACTION_XXX fields defined here, intended to indicate
* to the caller they action that they are supposed as a result of the arg
* handling.
*/
public int handleArgs(String[] args)
{
int returnAction = ACTION_CONTINUE;
for(int i = 0; i < args.length; i++)
{
logger.trace("handling arg " + i);
if (args[i].equals("--version") || args[i].equals("-v"))
{
handleVersionArg();
//we're supposed to exit after printing version info
returnAction = ACTION_EXIT;
break;
}
else if (args[i].equals("--help") || args[i].equals("-h"))
{
handleHelpArg();
//we're supposed to exit after printing the help message
returnAction = ACTION_EXIT;
break;
}
else if (args[i].equals("--debug") || args[i].equals("-d"))
{
handleDebugArg(args[i]);
continue;
}
else if (args[i].startsWith("--config="))
{
returnAction = handleConfigArg(args[i]);
if(returnAction == ACTION_ERROR)
break;
else
continue;
}
else if (args[i].equals("-c"))
{
//make sure we have at least one more argument left.
if( i == args.length - 1)
{
System.out.println("The \"-c\" option expects a directory parameter.");
returnAction = ACTION_ERROR;
break;
}
handleConfigArg(args[++i]);
continue;
}
else if (args[i].equals("--multiple") || args[i].equals("-m"))
{
handleMultipleArg(args[i]);
continue;
}
//if this is the last arg and it's not an option then it's probably
//an URI
else if ( i == args.length - 1
&& !args[i].startsWith("-"))
{
handleUri(args[i]);
}
else
{
handleUnknownArg(args[i]);
errorCode = ERROR_CODE_UNKNOWN_ARG;
returnAction = ACTION_ERROR;
break;
}
}
return returnAction;
}
/**
* Passes <tt>uriArg</tt> to our uri manager for handling.
*
* @param arg the uri that we'd like to pass to
*/
private void handleUri(String uri)
{
logger.trace("Handling uri "+ uri);
uriArgManager.handleUri(uri);
}
/**
* Instructs SIP Communicator to print logging messages to the console.
*/
private void handleDebugArg(String arg)
{
System.out.println("Option " + arg + " is not yet implemented!");
}
/**
* Instructs SIP Communicator to allow for more than a single running
* instance.
*/
private void handleMultipleArg(String arg)
{
System.out.println("Option " + arg + " is not yet implemented!");
}
/**
* Instructs SIP Communicator to allow for more than a single running
* instance.
*
* @return either ACTION_ERROR or ACTION_CONTINUE depending on whether or
* not parsing the option went fine.
*/
private int handleConfigArg(String configArg)
{
if (configArg.startsWith("--config="))
{
configArg = configArg.substring("--config=".length());
}
File configDir = new File(configArg);
configDir.mkdirs();
if(!configDir.isDirectory())
{
System.out.println("Failed to create directory " + configArg);
errorCode = ERROR_CODE_CREATE_DIR_FAILED;
return ACTION_ERROR;
}
System.setProperty(PNAME_SC_HOME_DIR_LOCATION, configDir.getParent());
System.setProperty(PNAME_SC_HOME_DIR_NAME, configDir.getName());
return ACTION_CONTINUE;
}
/**
* Prints the name and the version of this application. This method uses the
* version.properties file which is created by ant during the build process.
* If this file does not exist the method would print a default name and
* version string.
*/
private void handleVersionArg()
{
String name = getApplicationName();
String version = getVersion();
if (name == null || name.trim().length() == 0)
{
name = "SIP Communicator";
}
if (version == null || version.trim().length() == 0)
{
version = "build.by.SVN";
}
System.out.println(name + " " + version);
}
/**
* Returns the version of the SIP Communicator instance that we are
* currently running.
*
* @return a String containing the version of the SC instance we are
* currently running.
*/
private String getVersion()
{
String version = versionProperties.getProperty(PNAME_VERSION);
return version == null
? "build.by.SVN"
: version;
}
/**
* Returns the name of the application. That should be SIP Communicator
* most of the time but who knows ..
*
* @return the name of the application (i.e. SIP Communicator until we
* change our name some day.)
*/
private String getApplicationName()
{
String name = versionProperties.getProperty(PNAME_APPLICATION_NAME);
return name == null
? "SIP Communicator"
: name;
}
/**
* Prints an error message and then prints the help message.
*/
public void handleUnknownArg(String arg)
{
System.out.println("Unknown argument: " + arg);
handleHelpArg();
}
/**
* Prints a help message containing usage instructions and descriptions of
* all options currently supported by SIP Communicator.
*/
public void handleHelpArg()
{
handleVersionArg();
System.out.println("Usage: sip-communicator [OPTIONS] [uri-to-call]");
System.out.println("");
System.out.println(" -c, --config=DIR use DIR for config files");
System.out.println(" -d, --debug print debugging messages to stdout");
System.out.println(" -h, --help display this help message and exit");
System.out.println(" -m, --multiple do not ensure single instance");
System.out.println(" -v, --version display the current version and exit");
}
/**
* Returns an error code that could help identify an error when
* <tt>handleArgs</tt> returns ACTION_ERROR or 0 if everything went fine.
*
* @return an error code that could help identify an error when
* <tt>handleArgs</tt> returns ACTION_ERROR or 0 if everything went fine.
*/
public int getErrorCode()
{
return errorCode;
}
/**
* Sets the <tt>delegationPeer</tt> that would be handling all URIs passed
* as command line arguments to SIP Communicator.
*
* @param delegationPeer the <tt>delegationPeer</tt> that should handle URIs
* or <tt>null</tt> if we'd like to unset a previously set peer.
*/
public void setDelegationPeer(UriDelegationPeer delegationPeer)
{
this.uriArgManager.setDelegationPeer(delegationPeer);
}
}

@ -0,0 +1,784 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.util.launchutils;
import java.io.*;
import java.net.*;
import java.util.*;
import net.java.sip.communicator.launcher.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.launchutils.*;
/**
* This class is used to prevent from running multiple instances of SIP
* Communicator. The class binds a socket somewhere on the localhost domain and
* records its socket address in the SIP Communicator configuration directory.
*
* All following instances of SIP Communicator (and hence this class) will look
* for this record in the configuration directory and try to connect to the
* original instance through the socket address in there.
*
* @author Emil Ivov
*/
public class SipCommunicatorLock extends Thread
{
private static final Logger logger = Logger
.getLogger(SipCommunicatorLock.class);
/**
* Indicates that something went wrong. More information will probably be
* available in the console ... if anyone cares at all.
*/
public static final int LOCK_ERROR = 300;
/**
* Returned by the soft start method to indicate that we have successfully
* started and locked the configuration directory.
*/
public static final int SUCCESS = 0;
/**
* Returned by the soft start method to indicate that an instance of SIP
* Communicator has been already started and we should exit. This return
* code also indicates that all arguments were passed to that new instance.
*/
public static final int ALREADY_STARTED = 301;
/**
* The name of the file that we use to store the address and port that this
* lock is bound on.
*/
private static final String LOCK_FILE_NAME = ".lock";
/**
* The name of the property that we use to store the address that we bind on
* in this class.
*/
private static final String PNAME_LOCK_ADDRESS = "lockAddress";
/**
* The name of the property that we use to store the address that we bind on
* in this class.
*/
private static final String PNAME_LOCK_PORT = "lockPort";
/**
* The header preceding each of the arguments that we toss around between
* instances of SIP Communicator
*/
private static final String ARGUMENT = "Argument";
/**
* The name of the header that contains the number of arguments that we send
* from one instance to another.
*/
private static final String ARG_COUNT = "Arg-Count";
/**
* The name of the header that contains any error messages resulting from
* remote argument handling.
*/
private static final String ERROR_ARG = "ERROR";
/**
* The carriage return, line feed sequence (\r\n).
*/
private static final String CRLF = "\r\n";
/**
* The number of milliseconds that we should wait for a remote SC instance
* to come back to us.
*/
private long LOCK_COMMUNICATION_DELAY = 50;
/**
* The socket that we use for cross instance lock and communication.
*/
private ServerSocket instanceServerSocket = null;
/**
* Tries to lock the configuration directory. If lock-ing is not possible
* because a previous instance is already running, then it transmits the
* list of args to that running instance.
* <p>
* There are three possible outcomes of this method. 1. We lock
* successfully; 2. We fail to lock because another instance of SIP
* Communicator is already running; 3. We fail to lock for some unknown
* error. Each of these cases is represented by an error code returned as a
* result.
*
* @param args
* the array of arguments that we are to submit in case an
* instance of SIP Communicator has already been started.
*
* @return an error or success code indicating the outcome of the lock
* operation.
*/
public int tryLock(String[] args)
{
// first check whether we have a file.
File lockFile = getLockFile();
if (lockFile.exists())
{
InetSocketAddress lockAddress = readLockFile(lockFile);
if (lockAddress != null)
{
// we have a valid lockAddress and hence possibly an already
// running instance of SC. Try to communicate with it.
if (interInstanceConnect(lockAddress, args) == SUCCESS)
{
return ALREADY_STARTED;
}
}
// our lockFile is probably stale and left from a previous instance.
// or an instance that is still running but is not responding.
lockFile.delete();
}
// if we get here then this means that we should go for a real lock
// initialization
// create a new socket,
// right the bind address in the file
try
{
lockFile.createNewFile();
}
catch (IOException e)
{
logger.error("Failed to create lock file", e);
}
lockFile.deleteOnExit();
return lock(lockFile);
}
/**
* Locks the configuration directory by binding our lock socket and
* recording the lock file into the configuration directory. Returns SUCCESS
* if everything goes well and ERROR if something fails. This method does
* not return the ALREADY_RUNNING code as it is assumed that this has
* already been checked before calling this method.
*
* @param lockFile
* the file that we should use to lock the configuration
* directory.
*
* @return the SUCCESS or ERROR codes defined by this class.
*/
private int lock(File lockFile)
{
InetAddress lockAddress = getRandomBindAddress();
if (lockAddress == null)
{
return LOCK_ERROR;
}
int port = getRandomPortNumber();
InetSocketAddress serverSocketAddress = new InetSocketAddress(
lockAddress, port);
writeLockFile(lockFile, serverSocketAddress);
startLockServer(serverSocketAddress);
return SUCCESS;
}
/**
* Creates and binds a socket on <tt>lockAddress</tt> and then starts a
* <tt>LockServer</tt> instance so that we would start interacting with
* other instances of SIP Communicator that are trying to start.
*
* @return the <tt>ERROR</tt> code if something goes wrong and
* <tt>SUCCESS</tt> otherwise.
*/
private int startLockServer(InetSocketAddress localAddress)
{
try
{
// check config directory
instanceServerSocket = new ServerSocket();
}
catch (IOException exc)
{
// Just checked the impl and this doesn't seem to ever be thrown
// .... ignore ...
logger.error("Couldn't create server socket", exc);
return LOCK_ERROR;
}
try
{
instanceServerSocket.bind(localAddress, 16);// Why 16? 'cos I say
// so.
}
catch (IOException exc)
{
logger.error("Couldn't create server socket", exc);
return LOCK_ERROR;
}
LockServer lockServ = new LockServer(instanceServerSocket);
lockServ.start();
return SUCCESS;
}
/**
* Returns a randomly chosen socket address using a loopback interface (or
* another one in case the loopback is not available) that we should bind
* on.
*
* @return an InetAddress (most probably a loopback) that we can use to bind
* our semaphore socket on.
*/
private InetAddress getRandomBindAddress()
{
NetworkInterface loopback;
try
{
// find a loopback interface
Enumeration<NetworkInterface> interfaces;
try
{
interfaces = NetworkInterface.getNetworkInterfaces();
}
catch (SocketException exc)
{
// I don't quite understand why this would happen ...
logger.error(
"Failed to obtain a list of the local interfaces.",
exc);
return null;
}
loopback = null;
while (interfaces.hasMoreElements())
{
NetworkInterface iface = interfaces.nextElement();
if (iface.isLoopback())
{
loopback = iface;
break;
}
}
// if we didn't find a loopback (unlikely but possible)
// return the first available interface on this machine
if (loopback == null)
{
loopback = NetworkInterface.getNetworkInterfaces()
.nextElement();
}
}
catch (SocketException exc)
{
// I don't quite understand what could possibly cause this ...
logger.error("Could not find the loopback interface", exc);
return null;
}
// get the first address on the loopback.
InetAddress addr = loopback.getInetAddresses().nextElement();
return addr;
}
/**
* Returns a random port number that we can use to bind a socket on.
*
* @return a random port number that we can use to bind a socket on.
*/
private int getRandomPortNumber()
{
return (int) (Math.random() * 64509) + 1025;
}
/**
* Parses the <tt>lockFile</tt> into a standard Properties Object and
* verifies it for completeness. The method also tries to validate the
* contents of <tt>lockFile</tt> and asserts presence of all properties
* mandated by this version.
*
* @param lockFile
* the file that we are to parse.
*
* @return the <tt>SocketAddress</tt> that we should use to communicate with
* a possibly already running version of SIP Communicator.
*/
private InetSocketAddress readLockFile(File lockFile)
{
Properties lockProperties = new Properties();
try
{
lockProperties.load(new FileInputStream(lockFile));
}
catch (Exception exc)
{
logger.error("Failed to read lock properties.", exc);
return null;
}
String lockAddressStr = lockProperties.getProperty(PNAME_LOCK_ADDRESS);
if (lockAddressStr == null)
{
logger.error("Lock file contains no lock address.");
return null;
}
String lockPort = lockProperties.getProperty(PNAME_LOCK_PORT);
if (lockPort == null)
{
logger.error("Lock file contains no lock port.");
return null;
}
InetAddress lockAddress = findLocalAddress(lockAddressStr);
if (lockAddress == null)
{
logger.error(lockAddressStr + " is not a valid local address.");
return null;
}
int port;
try
{
port = Integer.parseInt(lockPort);
}
catch (NumberFormatException exc)
{
logger.error(lockPort + " is not a valid port number.", exc);
return null;
}
InetSocketAddress lockSocketAddress = new InetSocketAddress(
lockAddress, port);
return lockSocketAddress;
}
/**
* Records our <tt>lockAddress</tt> into <tt>lockFile</tt> using the
* standard properties format.
*
* @param lockFile
* the file that we should store the address in.
* @param lockAddress
* the address that we have to record.
*
* @return <tt>SUCCESS</tt> upon success and <tt>ERROR</tt> if we fail to
* store the file.
*/
private int writeLockFile(File lockFile, InetSocketAddress lockAddress)
{
Properties lockProperties = new Properties();
lockProperties.setProperty(PNAME_LOCK_ADDRESS, lockAddress.getAddress()
.getHostAddress());
lockProperties.setProperty(PNAME_LOCK_PORT, Integer
.toString(lockAddress.getPort()));
try
{
lockProperties.store(new FileOutputStream(lockFile),
"SIP Communicator lock file. This file will be automatically"
+ "removed when execution of SIP Communicator terminates.");
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
logger.error("Failed to create lock file.", e);
return LOCK_ERROR;
}
return SUCCESS;
}
/**
* Returns a reference to the file that we should be using to lock SIP
* Communicator's home directory, whether it exists or not.
*
* @return a reference to the file that we should be using to lock SIP
* Communicator's home directory.
*/
private File getLockFile()
{
String homeDirLocation = System
.getProperty(SIPCommunicator.PNAME_SC_HOME_DIR_LOCATION);
String homeDirName = System
.getProperty(SIPCommunicator.PNAME_SC_HOME_DIR_NAME);
String fileSeparator = System.getProperty("file.separator");
String fullLockFileName = homeDirLocation + fileSeparator + homeDirName
+ fileSeparator + LOCK_FILE_NAME;
return new File(fullLockFileName);
}
/**
* Returns an <tt>InetAddress</tt> instance corresponding to
* <tt>addressStr</tt> or <tt>null</tt> if no such address exists on the
* local interfaces.
*
* @param addressStr
* the address string that we are trying to resolve into an
* <tt>InetAddress</tt>
*
* @return an <tt>InetAddress</tt> instance corresponding to
* <tt>addressStr</tt> or <tt>null</tt> if none of the local
* interfaces has such an address.
*/
private InetAddress findLocalAddress(String addressStr)
{
Enumeration<NetworkInterface> ifaces;
try
{
ifaces = NetworkInterface.getNetworkInterfaces();
}
catch (SocketException exc)
{
logger.error(
"Could not extract the list of local intefcaces.",
exc);
return null;
}
// loop through local interfaces
while (ifaces.hasMoreElements())
{
NetworkInterface iface = ifaces.nextElement();
Enumeration<InetAddress> addreses = iface.getInetAddresses();
// loop iface addresses
while (addreses.hasMoreElements())
{
InetAddress addr = addreses.nextElement();
if (addr.getHostAddress().equals(addressStr))
return addr;
}
}
return null;
}
/**
* Initializes a client TCP socket, connects if to <tt>sockAddr</tt> and
* sends all <tt>args</tt> to it.
*
* @param sockAddr the address that we are to connect to.
* @param args the args that we need to send to <tt>sockAddr</tt>.
*
* @return <tt>SUCCESS</tt> upond success and <tt>ERROR</tt> if anything
* goes wrong.
*/
private int interInstanceConnect(InetSocketAddress sockAddr, String[] args)
{
try
{
Socket interInstanceSocket = new Socket(sockAddr.getAddress(),
sockAddr.getPort());
LockClient lockClient = new LockClient(interInstanceSocket);
lockClient.start();
PrintStream printStream = new PrintStream(interInstanceSocket
.getOutputStream());
printStream.print(ARG_COUNT + "=" + args.length + CRLF);
for (int i = 0; i < args.length; i++)
{
printStream.print(ARGUMENT + "=" + args[i] + CRLF);
}
lockClient.waitForReply(LOCK_COMMUNICATION_DELAY);
//NPEs are handled in catch so no need to check whether or not we
//actually have a reply.
String serverReadArgCountStr = lockClient.message
.substring((ARG_COUNT + "=").length());
int serverReadArgCount = Integer.parseInt(serverReadArgCountStr);
logger.debug("Server read " + serverReadArgCount + " args.");
if(serverReadArgCount != args.length)
return LOCK_ERROR;
printStream.flush();
printStream.close();
interInstanceSocket.close();
}
//catch IOExceptions, NPEs and NumberFormatExceptions here.
catch (Exception e)
{
logger.debug("Failed to connect to a running sc instance.");
return LOCK_ERROR;
}
return SUCCESS;
}
/**
* We use this thread to communicate with an already running instance of SIP
* Communicator. This thread will listen for a reply to a message that we've
* sent to the other instance. We will wait for this message for a maximum
* of <tt>runDuration</tt> milliseconds and then consider the remote
* instance dead.
*/
private class LockClient extends Thread
{
/**
* The <tt>String</tt> that we've read from the socketInputStream
*/
public String message = null;
/**
* The socket that this <tt>LockClient</tt> is created to read from.
*/
private Socket interInstanceSocket = null;
/**
* Creates a <tt>LockClient</tt> that should read whatever data we
* receive on <tt>sockInputStream</tt>.
*
* @param commSocket
* the socket that this client should be reading from.
*/
public LockClient(Socket commSocket)
{
super(LockClient.class.getName());
setDaemon(true);
this.interInstanceSocket = commSocket;
}
/**
* Blocks until a reply has been received or until run<tt>Duration</tt>
* milliseconds had passed.
*
* @param runDuration the number of seconds to wait for a reply from
* the remote instance
*/
public void waitForReply(long runDuration)
{
try
{
synchronized(this)
{
//return if we have already received a message.
if(message != null)
return;
wait(runDuration);
}
logger.debug("Done waiting. Will close socket");
interInstanceSocket.close();
}
catch (Exception exception)
{
logger.error("Failed to close our inter instance input stream",
exception);
}
}
/**
* Simply collects everything that we read from the InputStream that
* this <tt>InterInstanceCommunicationClient</tt> was created with.
*/
public void run()
{
try
{
BufferedReader lineReader = new BufferedReader(
new InputStreamReader(interInstanceSocket
.getInputStream()));
//we only need to read a single line and then bail out.
message = lineReader.readLine();
logger.debug("Message is " + message);
synchronized(this)
{
notifyAll();
}
}
catch (IOException exc)
{
// does not necessarily mean something is wrong. Could be
// that we got tired of waiting and want to quit.
logger.info("An IOException is thrown while reading sock", exc);
}
}
}
/**
* We start this thread when running SIP Communicator as a means of
* notifying others that this is
*/
private class LockServer extends Thread
{
private boolean keepAccepting = true;
/**
* The socket that we use for cross instance lock and communication.
*/
private ServerSocket lockSocket = null;
/**
* Creates an instance of this <tt>LockServer</tt> wrapping the
* specified <tt>serverSocket</tt>. It is expected that the serverSocket
* will be already bound and ready to accept.
*
* @param serverSocket
* the serverSocket that we should use for inter instance
* communication.
*/
public LockServer(ServerSocket serverSocket)
{
super(LockServer.class.getName());
setDaemon(true);
this.lockSocket = serverSocket;
}
public void run()
{
try
{
while (keepAccepting)
{
Socket instanceSocket = lockSocket.accept();
new LockServerConnectionProcessor(instanceSocket).start();
}
}
catch (Exception exc)
{
logger.warn("Someone tried ", exc);
}
}
}
/**
* We use this thread to handle individual messages in server side inter
* instance communication.
*/
private class LockServerConnectionProcessor extends Thread
{
/**
* The socket that we will be using to communicate with the fellow SIP
* Communicator instance..
*/
private Socket connectionSocket = null;
/**
* Creates an instance of <tt>LockServerConnectionProcessor</tt> that
* would handle parameters received through the
* <tt>connectionSocket</tt>.
*
* @param connectedSocket
* the socket that we will be using to read arguments from
* the remote SIP Communicator instance.
*/
public LockServerConnectionProcessor(Socket connectionSocket)
{
this.connectionSocket = connectionSocket;
}
/**
* Starts reading messages arriving through the connection socket.
*/
public void run()
{
InputStream is;
PrintWriter printer;
try
{
is = connectionSocket.getInputStream();
printer = new PrintWriter(connectionSocket
.getOutputStream());
}
catch (IOException exc)
{
logger.warn("Failed to read arguments from another SC instance",
exc);
return;
}
ArrayList<String> argsList = new ArrayList<String>();
logger.debug("Handling incoming connection");
int argCount = 1024;
try
{
while (true)
{
BufferedReader lineReader = new BufferedReader(
new InputStreamReader(is));
String line = lineReader.readLine();
logger.debug(line);
if (line.startsWith(ARG_COUNT))
{
argCount = Integer.parseInt(line
.substring((ARG_COUNT + "=").length()));
}
else if (line.startsWith(ARGUMENT))
{
String arg = line.substring((ARGUMENT + "=").length());
argsList.add(arg);
}
else
{
// ignore unknown headers.
}
if (argCount <= argsList.size())
break;
}
// first tell the remote application that everything went OK
// and end the connection so that it could exit
printer.print(ARG_COUNT + "=" + argCount + CRLF);
printer.close();
connectionSocket.close();
// now let's handle what we've got
String[] args = new String[argsList.size()];
LaunchArgHandler.getInstance().handleArgs(
argsList.toArray(args));
}
catch (IOException exc)
{
logger.info("An IOException is thrown while "
+ "processing remote args", exc);
printer.print(ERROR_ARG + "=" + exc.getMessage());
}
}
}
}

@ -0,0 +1,84 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license. See terms of license at gnu.org.
*/
package net.java.sip.communicator.util.launchutils;
import java.util.*;
import net.java.sip.communicator.util.*;
/**
* The <tt>UriArgManager</tt> implements an utility for handling URIs that have
* been passed as command line arguments. The class maintains a list of
* registered delegates that do the actual URI handling. The UriArgDelegator
* is previewed for use with SIP Communicator argdelegation service. It would
* therefore record all URIs until the corresponding DelegationPeer has been
* registered with the UriArgManager.
*
* @author Emil Ivov
*/
class UriArgManager
{
private static final Logger logger = Logger.getLogger(UriArgManager.class);
/**
* The delegation peer that we pass arguments to. This peer is going to
* get set only after Felix starts and all its services have been properly
* loaded.
*/
private UriDelegationPeer uriDelegationPeer = null;
/**
* We use this list to store arguments that we have been asked to handle
* before we had a registered delegation peer.
*/
private List<String> recordedArgs = new LinkedList<String>();
/**
* Passes the <tt>uriArg</tt> to the uri delegation peer or, in case
* no peer is currently registered, stores it and keeps it until one
* appears.
*
* @param uriArg the uri argument that we'd like to delegate to our peer.
*/
protected void handleUri(String uriArg)
{
synchronized(recordedArgs)
{
if(uriDelegationPeer == null)
{
recordedArgs.add(uriArg);
return;
}
}
uriDelegationPeer.handleUri(uriArg);
}
/**
* Sets a delegation peer that we can now use to pass arguments to and
* makes it handle all arguments that have been already registered.
*
* @param delegationPeer the delegation peer that we can use to deliver
* command line URIs to.
*/
public void setDelegationPeer(UriDelegationPeer delegationPeer)
{
synchronized(recordedArgs)
{
logger.trace("Someone set a delegationPeer. "
+"Will dispatch "+ recordedArgs.size() +" args");
this.uriDelegationPeer = delegationPeer;
for (String arg : recordedArgs)
{
logger.trace("Dispatching arg: " + arg);
uriDelegationPeer.handleUri(arg);
}
recordedArgs.clear();
}
}
}

@ -0,0 +1,26 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.util.launchutils;
/**
* The <tt>UriDelegationPeer</tt> is used as a mechanism to pass arguments from
* the UriArgManager which resides in "launcher space" to our argument
* delegation service implementation that lives as an osgi bundle. An instance
* of this peer is created from within the argument delegation service impl
* and is registered with the UriArgManager.
*
* @author Emil Ivov
*/
public interface UriDelegationPeer
{
/**
* Handles <tt>uriArg</tt> in whatever way it finds fit.
*
* @param uriArg the uri argument that this delegate has to handle.
*/
public void handleUri(String uriArg);
}
Loading…
Cancel
Save