aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastien Vincent <seb@jitsi.org>2010-09-29 11:15:10 +0000
committerSebastien Vincent <seb@jitsi.org>2010-09-29 11:15:10 +0000
commit3d77efb36f85e00b0a1df6ba5a612b9beffd326a (patch)
tree810927921b242dc7ae5351ae7cb236320e5cd5d6
parent502471520721b867ff7fd37ab4497699b20764fa (diff)
downloadjitsi-3d77efb36f85e00b0a1df6ba5a612b9beffd326a.zip
jitsi-3d77efb36f85e00b0a1df6ba5a612b9beffd326a.tar.gz
jitsi-3d77efb36f85e00b0a1df6ba5a612b9beffd326a.tar.bz2
Initial commit to support provisioning. It provides the DHCP provisioning discovery method, the provisioning URL can also be retrieved from configuration.
-rw-r--r--build.xml33
-rw-r--r--lib/felix.client.run.properties5
-rw-r--r--lib/installer-exclude/dhcp4java-1.00.jarbin0 -> 48971 bytes
-rw-r--r--src/net/java/sip/communicator/impl/netaddr/NetworkAddressManagerServiceImpl.java1
-rw-r--r--src/net/java/sip/communicator/impl/provdisc/dhcp/DHCPProvisioningDiscover.java252
-rw-r--r--src/net/java/sip/communicator/impl/provdisc/dhcp/ProvisioningDiscoveryDHCPActivator.java106
-rw-r--r--src/net/java/sip/communicator/impl/provdisc/dhcp/ProvisioningDiscoveryServiceDHCPImpl.java109
-rw-r--r--src/net/java/sip/communicator/impl/provdisc/dhcp/dhcp.provdisc.manifest.mf11
-rw-r--r--src/net/java/sip/communicator/plugin/provisioning/ProvisioningPluginActivator.java800
-rw-r--r--src/net/java/sip/communicator/plugin/provisioning/provisioning.manifest.mf17
-rw-r--r--src/net/java/sip/communicator/service/protocol/media/MediaAwareCall.java1
-rw-r--r--src/net/java/sip/communicator/service/provdisc/AbstractProvisioningDiscoveryService.java92
-rw-r--r--src/net/java/sip/communicator/service/provdisc/ProvisioningDiscoveryService.java58
-rw-r--r--src/net/java/sip/communicator/service/provdisc/event/DiscoveryEvent.java49
-rw-r--r--src/net/java/sip/communicator/service/provdisc/event/DiscoveryListener.java25
-rw-r--r--src/net/java/sip/communicator/service/provdisc/provdisc.manifest.mf7
-rw-r--r--src/net/java/sip/communicator/util/swing/AuthenticationWindow.java7
17 files changed, 1569 insertions, 4 deletions
diff --git a/build.xml b/build.xml
index b86de32..7c8eee6 100644
--- a/build.xml
+++ b/build.xml
@@ -931,7 +931,9 @@
bundle-replacement,bundle-youtube,bundle-dailymotion,bundle-smiley,
bundle-vimeo,bundle-vbox7,bundle-metacafe,bundle-flickr,bundle-hulu,
bundle-twitpic,bundle-directimage,bundle-bliptv,bundle-viddler,
- bundle-plugin-chatconfig,bundle-certificate"/>
+ bundle-plugin-chatconfig,bundle-certificate,
+ bundle-provdisc,bundle-provdisc-dhcp,
+ bundle-provisioning"/>
<!--BUNDLE-SC-LAUNCHER-->
<target name="bundle-sc-launcher">
@@ -2526,6 +2528,35 @@ org.apache.http.util"/>
</jar>
</target>
+ <!-- BUNDLE-PROVDISC-->
+ <target name="bundle-provdisc">
+ <!-- Creates a bundle containing the provisioning discovery service.-->
+ <jar compress="false" destfile="${bundles.dest}/provdisc.jar"
+ manifest="${src}/net/java/sip/communicator/service/provdisc/provdisc.manifest.mf">
+ <zipfileset dir="${dest}/net/java/sip/communicator/service/provdisc"
+ prefix="net/java/sip/communicator/service/provdisc"/>
+ </jar>
+ </target>
+
+ <!--BUNDLE-PROVDISC-DHCP -->
+ <target name="bundle-provdisc-dhcp">
+ <jar compress="false" destfile="${bundles.dest}/provdisc-dhcp.jar"
+ manifest="${src}/net/java/sip/communicator/impl/provdisc/dhcp/dhcp.provdisc.manifest.mf">
+ <zipfileset dir="${dest}/net/java/sip/communicator/impl/provdisc/dhcp"
+ prefix="net/java/sip/communicator/impl/provdisc/dhcp" />
+ <zipfileset src="${lib.noinst}/dhcp4java-1.00.jar"/>
+ </jar>
+ </target>
+
+ <!--BUNDLE-PROVISIONING -->
+ <target name="bundle-provisioning">
+ <jar compress="false" destfile="${bundles.dest}/provisioning.jar"
+ manifest="${src}/net/java/sip/communicator/plugin/provisioning/provisioning.manifest.mf">
+ <zipfileset dir="${dest}/net/java/sip/communicator/plugin/provisioning"
+ prefix="net/java/sip/communicator/plugin/provisioning" />
+ </jar>
+ </target>
+
<target name="bundle-certificate">
<jar compress="false" destfile="${bundles.dest}/certificate.jar"
manifest="${src}/net/java/sip/communicator/impl/certificate/certificate.manifest.mf">
diff --git a/lib/felix.client.run.properties b/lib/felix.client.run.properties
index f1907d9..6425738 100644
--- a/lib/felix.client.run.properties
+++ b/lib/felix.client.run.properties
@@ -38,8 +38,10 @@ felix.auto.start.30= \
felix.auto.start.40= \
reference:file:sc-bundles/configuration.jar \
+ reference:file:sc-bundles/provdisc.jar \
reference:file:sc-bundles/resourcemanager.jar \
reference:file:sc-bundles/jfontchooserlib.jar \
+ reference:file:sc-bundles/netaddr.jar \
reference:file:sc-bundles/browserlauncher.jar
felix.auto.start.42= \
@@ -52,9 +54,11 @@ felix.auto.start.45= \
reference:file:sc-bundles/version.jar \
reference:file:sc-bundles/version-impl.jar \
reference:file:sc-bundles/branding.jar \
+ reference:file:sc-bundles/provdisc-dhcp.jar \
reference:file:sc-bundles/certificate.jar
felix.auto.start.49= \
+ reference:file:sc-bundles/provisioning.jar \
reference:file:sc-bundles/bouncycastle.jar \
reference:file:sc-bundles/zrtp4j.jar \
reference:file:sc-bundles/protocol.jar \
@@ -81,7 +85,6 @@ felix.auto.start.52= \
reference:file:sc-bundles/protocol-yahoo.jar \
reference:file:sc-bundles/protocol-gibberish.jar \
reference:file:sc-bundles/protocol-ssh.jar \
- reference:file:sc-bundles/netaddr.jar \
reference:file:sc-bundles/reconnectplugin.jar \
reference:file:sc-bundles/protocol-zeroconf.jar \
reference:file:sc-bundles/protocol-irc.jar \
diff --git a/lib/installer-exclude/dhcp4java-1.00.jar b/lib/installer-exclude/dhcp4java-1.00.jar
new file mode 100644
index 0000000..516897b
--- /dev/null
+++ b/lib/installer-exclude/dhcp4java-1.00.jar
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/netaddr/NetworkAddressManagerServiceImpl.java b/src/net/java/sip/communicator/impl/netaddr/NetworkAddressManagerServiceImpl.java
index 042a7d8..3515643 100644
--- a/src/net/java/sip/communicator/impl/netaddr/NetworkAddressManagerServiceImpl.java
+++ b/src/net/java/sip/communicator/impl/netaddr/NetworkAddressManagerServiceImpl.java
@@ -163,7 +163,6 @@ public class NetworkAddressManagerServiceImpl
}
else
{
-
//no point in making sure that the localHostFinderSocket is
//initialized.
//better let it through a NullPointerException.
diff --git a/src/net/java/sip/communicator/impl/provdisc/dhcp/DHCPProvisioningDiscover.java b/src/net/java/sip/communicator/impl/provdisc/dhcp/DHCPProvisioningDiscover.java
new file mode 100644
index 0000000..6c593f8
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/provdisc/dhcp/DHCPProvisioningDiscover.java
@@ -0,0 +1,252 @@
+/*
+ * 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.provdisc.dhcp;
+
+import java.net.*;
+import java.util.*;
+
+import net.java.sip.communicator.service.provdisc.event.*;
+import net.java.sip.communicator.service.netaddr.*;
+import net.java.sip.communicator.util.*;
+
+import org.dhcp4java.*;
+
+/**
+ * Class that will perform DHCP provisioning discovery.
+ *
+ * @author Sebastien Vincent
+ */
+public class DHCPProvisioningDiscover
+ implements Runnable
+{
+ /**
+ * Logger.
+ */
+ private final Logger logger
+ = Logger.getLogger(DHCPProvisioningDiscover.class);
+
+ /**
+ * UDP socket.
+ */
+ private DatagramSocket socket = null;
+
+ /**
+ * Listening port of the client. Note that the socket will send packet to
+ * DHCP server on port - 1.
+ */
+ private int port = 6768;
+
+ /**
+ * Option code of the specific provisioning option.
+ */
+ private byte option = (byte)120;
+
+ /**
+ * DHCP timeout (in milliseconds).
+ */
+ private static final int DHCP_TIMEOUT = 5000;
+
+ /**
+ * List of <tt>ProvisioningListener</tt> that will be notified when
+ * a provisioning URL is retrieved.
+ */
+ private List<DiscoveryListener> listeners =
+ new ArrayList<DiscoveryListener>();
+
+ /**
+ * Constructor.
+ *
+ * @param port port on which we will bound and listen for DHCP response
+ * @param option code of the specific provisioning option
+ * @throws Exception if anything goes wrong during initialization
+ */
+ public DHCPProvisioningDiscover(int port, byte option) throws Exception
+ {
+ this.port = port;
+ this.option = option;
+ socket = new DatagramSocket(port);
+
+ /* set timeout so that we will not blocked forever if we
+ * have no response from DHCP server
+ */
+ socket.setSoTimeout(DHCP_TIMEOUT);
+ }
+
+ /**
+ * It sends a DHCPINFORM message from all interfaces and wait for a
+ * response. Thread stops after first successful answer that contains
+ * specific option and thus the provisioning URL.
+ *
+ * @return provisioning URL
+ */
+ public String discoverProvisioningURL()
+ {
+ DHCPPacket inform = new DHCPPacket();
+ byte macAddress[] = null;
+ byte zeroIPAddress[] = {0x00, 0x00, 0x00, 0x00};
+ byte broadcastIPAddr[] = {(byte)255, (byte)255, (byte)255, (byte)255};
+ DHCPOption dhcpOpts[] = new DHCPOption[1];
+ int xid = new Random().nextInt();
+
+ try
+ {
+
+ inform.setOp(DHCPConstants.BOOTREQUEST);
+ inform.setHtype(DHCPConstants.HTYPE_ETHER);
+ inform.setHlen((byte) 6);
+ inform.setHops((byte) 0);
+ inform.setXid(xid);
+ inform.setSecs((short) 0);
+ inform.setFlags((short) 0);
+ inform.setYiaddr(InetAddress.getByAddress(zeroIPAddress));
+ inform.setSiaddr(InetAddress.getByAddress(zeroIPAddress));
+ inform.setGiaddr(InetAddress.getByAddress(zeroIPAddress));
+ inform.setChaddr(macAddress);
+ inform.setDhcp(true);
+ inform.setDHCPMessageType(DHCPConstants.DHCPINFORM);
+
+ dhcpOpts[0] = new DHCPOption(
+ DHCPConstants.DHO_DHCP_PARAMETER_REQUEST_LIST,
+ new byte[] {option});
+
+ inform.setOptions(dhcpOpts);
+
+ Enumeration<NetworkInterface> en =
+ NetworkInterface.getNetworkInterfaces();
+
+ while(en.hasMoreElements())
+ {
+ NetworkInterface iface = en.nextElement();
+
+ Enumeration<InetAddress> enAddr = iface.getInetAddresses();
+ while(enAddr.hasMoreElements())
+ {
+ InetAddress addr = enAddr.nextElement();
+
+ /* just take IPv4 address */
+ if(addr instanceof Inet4Address)
+ {
+ NetworkAddressManagerService netaddr =
+ ProvisioningDiscoveryDHCPActivator.
+ getNetworkAddressManagerService();
+
+ if(!addr.isLoopbackAddress())
+ {
+ macAddress = netaddr.getHardwareAddress(iface);
+ DHCPPacket p = inform.clone();
+
+ p.setCiaddr(addr);
+ p.setChaddr(macAddress);
+
+ byte msg[] = inform.serialize();
+ DatagramPacket pkt = new DatagramPacket(msg,
+ msg.length,
+ InetAddress.getByAddress(broadcastIPAddr),
+ port - 1);
+
+ socket.send(pkt);
+ msg = null;
+ pkt = null;
+ p = null;
+ }
+ }
+ }
+ }
+
+ /* now see if we receive DHCP ACK response and if it contains
+ * our custom option
+ */
+ boolean found = false;
+
+ try
+ {
+ DatagramPacket pkt2 = new DatagramPacket(new byte[1500], 1500);
+
+ while(!found)
+ {
+ /* we timeout after 5 seconds if no DHCP response are
+ * received
+ */
+ socket.receive(pkt2);
+ DHCPPacket dhcp = DHCPPacket.getPacket(pkt2);
+
+ if(dhcp.getXid() != xid)
+ {
+ continue;
+ }
+
+ DHCPOption optProvisioning = dhcp.getOption(option);
+
+ /* notify */
+ if(optProvisioning != null)
+ {
+ found = true;
+ return new String(optProvisioning.getValue());
+ }
+ }
+ }
+ catch(SocketTimeoutException est)
+ {
+ logger.warn("Timeout, no DHCP answer received", est);
+ }
+ }
+ catch(Exception e)
+ {
+ logger.warn("Exception occurred during DHCP discover", e);
+ }
+
+ return null;
+ }
+
+ /**
+ * Thread entry point. It runs <tt>discoverProvisioningURL</tt> in a
+ * separate thread.
+ */
+ public void run()
+ {
+ String url = discoverProvisioningURL();
+
+ if(url != null)
+ {
+ /* as we run in an asynchronous manner, notify the listener */
+ DiscoveryEvent evt = new DiscoveryEvent(this, url);
+
+ for(DiscoveryListener listener : listeners)
+ {
+ listener.notifyProvisioningURL(evt);
+ }
+ }
+ }
+
+ /**
+ * Add a listener that will be notified when the
+ * <tt>discoverProvisioningURL</tt> has finished.
+ *
+ * @param listener <tt>ProvisioningListener</tt> to add
+ */
+ public void addDiscoveryListener(DiscoveryListener listener)
+ {
+ if(!listeners.contains(listener))
+ {
+ listeners.add(listener);
+ }
+ }
+
+ /**
+ * Add a listener that will be notified when the
+ * <tt>discoverProvisioningURL</tt> has finished.
+ *
+ * @param listener <tt>ProvisioningListener</tt> to add
+ */
+ public void removeDiscoveryListener(DiscoveryListener listener)
+ {
+ if(listeners.contains(listener))
+ {
+ listeners.remove(listener);
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/provdisc/dhcp/ProvisioningDiscoveryDHCPActivator.java b/src/net/java/sip/communicator/impl/provdisc/dhcp/ProvisioningDiscoveryDHCPActivator.java
new file mode 100644
index 0000000..01ba693
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/provdisc/dhcp/ProvisioningDiscoveryDHCPActivator.java
@@ -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.provdisc.dhcp;
+
+import org.osgi.framework.*;
+
+import net.java.sip.communicator.service.provdisc.*;
+import net.java.sip.communicator.service.netaddr.*;
+import net.java.sip.communicator.util.*;
+
+/**
+ * Implements <tt>BundleActivator</tt> for the DHCP provisioning bundle.
+ *
+ * @author Sebastien Vincent
+ */
+public class ProvisioningDiscoveryDHCPActivator
+ implements BundleActivator
+{
+ /**
+ * <tt>Logger</tt> used by this <tt>DHCPProvisioningDiscoveryActivator</tt>
+ * instance for logging output.
+ */
+ private final Logger logger
+ = Logger.getLogger(ProvisioningDiscoveryDHCPActivator.class);
+
+ /**
+ * DHCP provisioning service.
+ */
+ private static ProvisioningDiscoveryServiceDHCPImpl provisioningService =
+ new ProvisioningDiscoveryServiceDHCPImpl();
+
+ /**
+ * A reference to the currently valid {@link NetworkAddressManagerService}.
+ */
+ private static NetworkAddressManagerService
+ networkAddressManagerService = null;
+
+ /**
+ * Bundle context from OSGi.
+ */
+ private static BundleContext bundleContext = null;
+
+ /**
+ * Starts the DHCP provisioning service
+ *
+ * @param bundleContext the <tt>BundleContext</tt> as provided by the OSGi
+ * framework.
+ * @throws Exception if anything goes wrong
+ */
+ public void start(BundleContext bundleContext)
+ throws Exception
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("DHCP provisioning discovery Service [STARTED]");
+
+ bundleContext.registerService(
+ ProvisioningDiscoveryService.class.getName(),
+ provisioningService,
+ null);
+
+ ProvisioningDiscoveryDHCPActivator.bundleContext = bundleContext;
+
+ if (logger.isDebugEnabled())
+ logger.debug("DHCP provisioning discovery Service [REGISTERED]");
+ }
+
+ /**
+ * Stops the DHCP provisioning service.
+ *
+ * @param bundleContext the <tt>BundleContext</tt> as provided by the OSGi
+ * framework.
+ * @throws Exception if anything goes wrong
+ */
+ public void stop(BundleContext bundleContext) throws Exception
+ {
+ ProvisioningDiscoveryDHCPActivator.bundleContext = null;
+
+ if (logger.isInfoEnabled())
+ logger.info("DHCP provisioning discovery Service ...[STOPPED]");
+ }
+
+ /**
+ * Returns a reference to a NetworkAddressManagerService implementation
+ * currently registered in the bundle context or null if no such
+ * implementation was found.
+ *
+ * @return a currently valid implementation of the
+ * NetworkAddressManagerService .
+ */
+ public static NetworkAddressManagerService getNetworkAddressManagerService()
+ {
+ if(networkAddressManagerService == null)
+ {
+ ServiceReference confReference
+ = bundleContext.getServiceReference(
+ NetworkAddressManagerService.class.getName());
+ networkAddressManagerService = (NetworkAddressManagerService)
+ bundleContext.getService(confReference);
+ }
+ return networkAddressManagerService;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/provdisc/dhcp/ProvisioningDiscoveryServiceDHCPImpl.java b/src/net/java/sip/communicator/impl/provdisc/dhcp/ProvisioningDiscoveryServiceDHCPImpl.java
new file mode 100644
index 0000000..121a218
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/provdisc/dhcp/ProvisioningDiscoveryServiceDHCPImpl.java
@@ -0,0 +1,109 @@
+/*
+ * 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.provdisc.dhcp;
+
+import net.java.sip.communicator.service.provdisc.*;
+import net.java.sip.communicator.service.provdisc.event.*;
+import net.java.sip.communicator.util.*;
+
+/**
+ * Class that uses DHCP to retrieve provisioning URL. Basically it sends a
+ * DHCPINFORM message with a custom option code in parameters list.
+ *
+ * Note that DHCP server have to understand this option and thus configured to
+ * answer with a HTTP/HTTPS URL.
+ *
+ * @author Sebastien Vincent
+ */
+public class ProvisioningDiscoveryServiceDHCPImpl
+ extends AbstractProvisioningDiscoveryService
+ implements DiscoveryListener
+{
+ /**
+ * Logger.
+ */
+ private final Logger logger
+ = Logger.getLogger(ProvisioningDiscoveryServiceDHCPImpl.class);
+
+ /**
+ * DHCP provisioning discover object.
+ */
+ private DHCPProvisioningDiscover discover = null;
+
+ /**
+ * Name of the method used to retrieve provisioning URL.
+ */
+ private static final String METHOD_NAME = "DHCP";
+
+ /**
+ * Get the name of the method name used to retrieve provisioning URL.
+ *
+ * @return method name
+ */
+ public String getMethodName()
+ {
+ return METHOD_NAME;
+ }
+
+ /**
+ * Constructor.
+ */
+ public ProvisioningDiscoveryServiceDHCPImpl()
+ {
+ try
+ {
+ discover = new DHCPProvisioningDiscover(6768, (byte)120);
+ discover.addDiscoveryListener(this);
+ }
+ catch(Exception e)
+ {
+ logger.warn("Cannot create DHCP client socket", e);
+ }
+ }
+
+ /**
+ * Launch a discovery for a provisioning URL. This method is synchronous and
+ * may block for some time. Note that you don't have to call
+ * <tt>startDiscovery</tt> method prior to this one to retrieve URL.
+ *
+ * @return provisioning URL
+ */
+ public String discoverURL()
+ {
+ if(discover != null)
+ {
+ return discover.discoverProvisioningURL();
+ }
+
+ return null;
+ }
+
+ /**
+ * Launch a discovery for a provisioning URL by sending a DHCP Inform
+ * with parameter list option containing a custom option code.
+ *
+ * This method is asynchronous, the response will be notified to any
+ * <tt>ProvisioningListener</tt> registered.
+ */
+ public void startDiscovery()
+ {
+ if(discover != null)
+ {
+ new Thread(discover).start();
+ }
+ }
+
+ /**
+ * Notify the provisioning URL.
+ *
+ * @param event provisioning event
+ */
+ public void notifyProvisioningURL(DiscoveryEvent event)
+ {
+ fireDiscoveryEvent(event);
+ }
+} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/provdisc/dhcp/dhcp.provdisc.manifest.mf b/src/net/java/sip/communicator/impl/provdisc/dhcp/dhcp.provdisc.manifest.mf
new file mode 100644
index 0000000..6663e51
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/provdisc/dhcp/dhcp.provdisc.manifest.mf
@@ -0,0 +1,11 @@
+Bundle-Activator: net.java.sip.communicator.impl.provdisc.dhcp.ProvisioningDiscoveryDHCPActivator
+Bundle-Name: DHCP provisioning discovery
+Bundle-Description: A bundle providing support for DHCP provisioning discovery
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1
+System-Bundle: yes
+Import-Package: org.osgi.framework,
+ net.java.sip.communicator.service.provdisc,
+ net.java.sip.communicator.service.provdisc.event,
+ net.java.sip.communicator.service.netaddr,
+ net.java.sip.communicator.util
diff --git a/src/net/java/sip/communicator/plugin/provisioning/ProvisioningPluginActivator.java b/src/net/java/sip/communicator/plugin/provisioning/ProvisioningPluginActivator.java
new file mode 100644
index 0000000..23143be
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/provisioning/ProvisioningPluginActivator.java
@@ -0,0 +1,800 @@
+/*
+ * 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.plugin.provisioning;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+import javax.net.ssl.*;
+import javax.swing.*;
+
+import net.java.sip.communicator.service.configuration.*;
+import net.java.sip.communicator.service.credentialsstorage.*;
+import net.java.sip.communicator.service.certificate.*;
+import net.java.sip.communicator.service.netaddr.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.provdisc.*;
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.util.swing.*;
+
+import org.osgi.framework.*;
+
+/**
+ * Activator the provisioning system. It will gather provisioning URL depending
+ * on the configuration (DHCP, manual, ...), retrieve configuration file and
+ * push properties to the <tt>ConfigurationService</tt>.
+ */
+public class ProvisioningPluginActivator
+ implements BundleActivator
+{
+ /**
+ * Logger of this class
+ */
+ private static final Logger logger
+ = Logger.getLogger(ProvisioningPluginActivator.class);
+
+ /**
+ * The current BundleContext.
+ */
+ private static BundleContext bundleContext = null;
+
+ /**
+ * Name of the provisioning URL in the configuration service.
+ */
+ private static final String PROPERTY_PROVISIONING_URL
+ = "net.java.sip.communicator.plugin.provisioning.URL";
+
+ /**
+ * Name of the username for the HTTP authentication.
+ */
+ private static final String PROPERTY_HTTP_USERNAME
+ = "net.java.sip.communicator.plugin.provisioning.auth.http.USERNAME";
+
+ /**
+ * Name of the password for the HTTP authentication.
+ */
+ private static final String PROPERTY_HTTP_PASSWORD
+ = "net.java.sip.communicator.plugin.provisioning.auth.http";
+
+ /**
+ * Name of the provisioning username in the configuration service
+ * authentication).
+ */
+ private static final String PROPERTY_PROVISIONING_USERNAME
+ = "net.java.sip.communicator.plugin.provisioning.auth.access.USERNAME";
+
+ /**
+ * Name of the provisioning password in the configuration service (HTTP
+ * authentication).
+ */
+ private static final String PROPERTY_PROVISIONING_PASSWORD
+ = "net.java.sip.communicator.plugin.provisioning.auth.access";
+
+ /**
+ * Name of the property that contains the provisioning method (i.e. DHCP,
+ * DNS, manual, ...).
+ */
+ private static final String PROVISIONING_METHOD_PROP
+ = "net.java.sip.communicator.plugin.provisioning.METHOD";
+
+ /**
+ * A reference to the ConfigurationService implementation instance that
+ * is currently registered with the bundle context.
+ */
+ private static ConfigurationService configurationService = null;
+
+ /**
+ * A reference to the CredentialsStorageService implementation instance
+ * that is registered with the bundle context.
+ */
+ private static CredentialsStorageService credentialsService = null;
+
+ /**
+ * The service we use to interact with user for SSL certificate stuff.
+ */
+ private static CertificateVerificationService certVerification = null;
+
+ /**
+ * A reference to the NetworkAddressManagerService implementation instance
+ * that is registered with the bundle context.
+ */
+ private static NetworkAddressManagerService netaddrService = null;
+
+ /**
+ * User credentials to access URL (protected by HTTP authentication) if any.
+ */
+ private static UserCredentials userCredentials = null;
+
+ /**
+ * User credentials that user have to provide to the provisioning server
+ * if any.
+ */
+ private static UserCredentials provCredentials = null;
+
+ /**
+ * HTTP method to request a page.
+ */
+ private String method = "POST";
+
+ /**
+ * Starts this bundle
+ *
+ * @param bundleContext BundleContext
+ * @throws Exception if anything goes wrong during the start of the bundle
+ */
+ public void start(BundleContext bundleContext) throws Exception
+ {
+ String url = null;
+
+ if (logger.isDebugEnabled())
+ logger.debug("Provisioning discovery [STARTED]");
+
+ ProvisioningPluginActivator.bundleContext = bundleContext;
+
+ String method = getConfigurationService().getString(
+ PROVISIONING_METHOD_PROP);
+
+ if(method == null || method.equals("NONE"))
+ {
+ return;
+ }
+
+ ServiceReference serviceReferences[] = bundleContext.
+ getServiceReferences(ProvisioningDiscoveryService.class.getName(),
+ null);
+
+ /* search the provisioning discovery implementation that correspond to
+ * the method name
+ */
+ if(serviceReferences != null)
+ {
+ for(ServiceReference ref : serviceReferences)
+ {
+ ProvisioningDiscoveryService provdisc =
+ (ProvisioningDiscoveryService)bundleContext.getService(ref);
+
+ if(provdisc.getMethodName().equals(method))
+ {
+ /* may block for sometime depending on the method used */
+ url = provdisc.discoverURL();
+ break;
+ }
+ }
+ }
+
+ if(url == null)
+ {
+ /* try to see if provisioning URL is stored in properties */
+ url = getConfigurationService().getString(
+ PROPERTY_PROVISIONING_URL);
+ }
+
+ if(url != null)
+ {
+ File file = retrieveConfigurationFile(url);
+
+ if(file != null)
+ {
+ updateConfiguration(file);
+
+ /* store the provisioning URL in local configuration in case
+ * the provisioning discovery failed (DHCP/DNS unavailable, ...)
+ */
+ getConfigurationService().setProperty(
+ PROPERTY_PROVISIONING_URL, url);
+ }
+ }
+
+ if (logger.isDebugEnabled())
+ logger.debug("Provisioning discovery [REGISTERED]");
+ }
+
+ /**
+ * Stops this bundle
+ *
+ * @param bundleContext BundleContext
+ * @throws Exception if anything goes wrong during the stop of the bundle
+ */
+ public void stop(BundleContext bundleContext) throws Exception
+ {
+ ProvisioningPluginActivator.bundleContext = null;
+
+ if (logger.isDebugEnabled())
+ logger.debug("Provisioning discovery [STOPPED]");
+ }
+
+ /**
+ * Configure HTTP connection to provide HTTP authentication and SSL
+ * truster.
+ *
+ * @param url provisioning URL
+ * @param connection the <tt>URLConnection</tt>
+ */
+ private void configureHTTPConnection(URL url, HttpURLConnection connection)
+ {
+ try
+ {
+ connection.setRequestMethod(method);
+
+ if(method.equals("POST"))
+ {
+ connection.setRequestProperty("Content-Type",
+ "application/x-www-form-urlencoded");
+ }
+
+ if(connection instanceof HttpsURLConnection)
+ {
+ CertificateVerificationService vs =
+ getCertificateVerificationService();
+
+ int port = url.getPort();
+
+ /* if we do not specify port in the URL (http://domain.org:port)
+ * we have to set up the default port of HTTP (80) or
+ * HTTPS (443).
+ */
+ if(port == -1)
+ {
+ if(url.getProtocol().equals("http"))
+ {
+ port = 80;
+ }
+ else if(url.getProtocol().equals("https"))
+ {
+ port = 443;
+ }
+ }
+
+ ((HttpsURLConnection)connection).setSSLSocketFactory(
+ vs.getSSLContext(
+ url.getHost(), port).getSocketFactory());
+ }
+ }
+ catch (Exception e)
+ {
+ logger.warn("Failed to initialize secure connection", e);
+ }
+
+ Authenticator.setDefault(new Authenticator()
+ {
+ protected PasswordAuthentication getPasswordAuthentication()
+ {
+ // if there is something save return it
+ ConfigurationService config = getConfigurationService();
+ CredentialsStorageService credStorage =
+ getCredentialsStorageService();
+
+ String uName
+ = (String) config.getProperty(
+ PROPERTY_HTTP_USERNAME);
+
+ if(uName != null)
+ {
+ String pass = credStorage.loadPassword(
+ PROPERTY_HTTP_PASSWORD);
+
+ if(pass != null)
+ return new PasswordAuthentication(uName,
+ pass.toCharArray());
+ }
+
+ if(userCredentials != null)
+ {
+ return new PasswordAuthentication(
+ userCredentials.getUserName(),
+ userCredentials.getPassword());
+ }
+ else
+ {
+ return null;
+ }
+ }
+ });
+ }
+
+ /**
+ * Handle authentication with the provisioning server.
+ */
+ private void handleProvisioningAuth()
+ {
+ ConfigurationService configService = getConfigurationService();
+ CredentialsStorageService credService =
+ getCredentialsStorageService();
+
+ String username = configService.getString(
+ PROPERTY_PROVISIONING_USERNAME);
+ String password = credService.loadPassword(
+ PROPERTY_PROVISIONING_PASSWORD);
+
+ if(username != null && password != null)
+ {
+ /* we have already the credentials stored so return them */
+ provCredentials = new UserCredentials();
+ provCredentials.setUserName(username);
+ provCredentials.setPassword(password.toCharArray());
+ provCredentials.setPasswordPersistent(true);
+ return;
+ }
+
+ AuthenticationWindow authWindow = new AuthenticationWindow(
+ "provisioning", true, null);
+
+ authWindow.setVisible(true);
+
+ if(!authWindow.isCanceled())
+ {
+ provCredentials = new UserCredentials();
+ provCredentials.setUserName(authWindow.getUserName());
+ provCredentials.setPassword(authWindow.getPassword());
+ provCredentials.setPasswordPersistent(authWindow.isRememberPassword());
+
+ if(provCredentials.getUserName() == null)
+ {
+ provCredentials = null;
+ }
+ }
+ else
+ {
+ provCredentials = null;
+ }
+ }
+
+ /**
+ * Retrieve configuration file from provisioning URL.
+ * This method is blocking until configuration file is retrieved from the
+ * network or if an exception happen
+ *
+ * @param url provisioning URL
+ * @return provisioning file downloaded
+ */
+ private File retrieveConfigurationFile(String url)
+ {
+ File tmpFile = null;
+
+ try
+ {
+ String arg = null;
+ String args[] = null;
+ final File temp = File.createTempFile("provisioning",
+ ".properties");
+
+ tmpFile = temp;
+
+ if(url.contains("?"))
+ {
+ /* do not handle URL of type http://domain/index.php? (no
+ * parameters)
+ */
+ if((url.indexOf('?') + 1) != url.length())
+ {
+ arg = url.substring(url.indexOf('?') + 1);
+ args = arg.split("&");
+ }
+ url = url.substring(0, url.indexOf('?'));
+ }
+
+ URL u = new URL(url);
+ URLConnection uc = u.openConnection();
+ OutputStreamWriter out = null;
+
+ if(uc instanceof HttpURLConnection)
+ {
+ configureHTTPConnection(u, (HttpURLConnection)uc);
+ ((HttpURLConnection)uc).setInstanceFollowRedirects(false);
+ uc.setDoInput(true);
+ uc.setDoOutput(true);
+ out = new OutputStreamWriter(uc.getOutputStream());
+
+ /* send out (via GET or POST) */
+ StringBuffer content = new StringBuffer();
+ InetAddress ipaddr = getNetworkAddressManagerService().
+ getLocalHost(InetAddress.getByName(u.getHost()));
+
+ if(args != null && args.length > 0)
+ {
+ for(String s : args)
+ {
+ if(s.equals("username"))
+ {
+ if(provCredentials == null)
+ {
+ handleProvisioningAuth();
+ }
+
+ if(provCredentials == null)
+ {
+ return null;
+ }
+
+ content.append("username=" +
+ URLEncoder.encode(
+ provCredentials.getUserName(),
+ "UTF-8"));
+ }
+ else if(s.equals("password"))
+ {
+ if(provCredentials == null)
+ {
+ handleProvisioningAuth();
+ }
+
+ if(provCredentials == null)
+ {
+ return null;
+ }
+
+ content.append("&password=" +
+ URLEncoder.encode(
+ provCredentials.
+ getPasswordAsString(),
+ "UTF-8"));
+ }
+ else if(s.equals("osname"))
+ {
+ content.append("&osname=" + URLEncoder.encode(
+ System.getProperty("os.name"), "UTF-8"));
+ }
+ else if(s.equals("build"))
+ {
+ content.append("&build=" + URLEncoder.encode(
+ System.getProperty("sip-communicator.version"),
+ "UTF-8"));
+ }
+ else if(s.equals("ipaddr"))
+ {
+ content.append("&ipaddr=" + URLEncoder.encode(
+ ipaddr.getHostAddress(), "UTF-8"));
+ }
+ else if(s.equals("hwaddr"))
+ {
+ String hwaddr = null;
+
+ if(ipaddr != null)
+ {
+ /* find the hardware address of the interface
+ * that has this IP address
+ */
+ Enumeration<NetworkInterface> en =
+ NetworkInterface.getNetworkInterfaces();
+
+ while(en.hasMoreElements())
+ {
+ NetworkInterface iface = en.nextElement();
+
+ Enumeration<InetAddress> enInet =
+ iface.getInetAddresses();
+
+ while(enInet.hasMoreElements())
+ {
+ InetAddress inet = enInet.nextElement();
+
+ if(inet.equals(ipaddr))
+ {
+ byte hw[] =
+ getNetworkAddressManagerService().
+ getHardwareAddress(iface);
+ StringBuffer buf =
+ new StringBuffer();
+
+ for(byte h : hw)
+ {
+ int hi = h >= 0 ? h : h + 256;
+ String t = new String(
+ (hi <= 0xf) ? "0" : "");
+ t += Integer.toHexString(hi);
+ buf.append(t);
+ buf.append("-");
+ }
+
+ buf.deleteCharAt(buf.length() - 1);
+
+ hwaddr = buf.toString();
+ content.append("&hwaddr=" +
+ URLEncoder.encode(
+ hwaddr, "UTF-8"));
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ out.write(content.toString());
+ out.flush();
+
+ int responseCode = ((HttpURLConnection)uc).getResponseCode();
+
+ if(responseCode == HttpURLConnection.HTTP_UNAUTHORIZED)
+ {
+ AuthenticationWindow authWindow = new AuthenticationWindow(
+ u.getHost(), true, null);
+
+ authWindow.setVisible(true);
+
+ userCredentials = new UserCredentials();
+ userCredentials.setUserName(authWindow.getUserName());
+ userCredentials.setPassword(authWindow.getPassword());
+ userCredentials.setPasswordPersistent(
+ authWindow.isRememberPassword());
+
+ if(userCredentials.getUserName() == null)
+ {
+ userCredentials = null;
+ }
+ else
+ {
+ tmpFile.delete();
+ return retrieveConfigurationFile(url);
+ }
+ }
+ else if(responseCode == HttpURLConnection.HTTP_MOVED_PERM ||
+ responseCode == HttpURLConnection.HTTP_MOVED_TEMP)
+ {
+ String loc =
+ ((HttpURLConnection)uc).getHeaderField("Location");
+
+ if(loc != null && (loc.startsWith("http://") ||
+ loc.startsWith("https://")))
+ {
+ tmpFile.delete();
+ /* TODO detect loops */
+ return retrieveConfigurationFile(loc);
+ }
+ }
+ else if(responseCode == HttpURLConnection.HTTP_OK)
+ {
+ if(userCredentials != null &&
+ userCredentials.getUserName() != null &&
+ userCredentials.isPasswordPersistent())
+ {
+ // if save password is checked save the pass
+ getConfigurationService().setProperty(
+ PROPERTY_HTTP_USERNAME,
+ userCredentials.getUserName());
+ getCredentialsStorageService().storePassword(
+ PROPERTY_HTTP_PASSWORD,
+ userCredentials.getPasswordAsString());
+ }
+
+ if(provCredentials != null &&
+ provCredentials.getUserName() != null &&
+ provCredentials.isPasswordPersistent())
+ {
+ getConfigurationService().setProperty(
+ PROPERTY_PROVISIONING_USERNAME,
+ provCredentials.getUserName());
+ getCredentialsStorageService().storePassword(
+ PROPERTY_PROVISIONING_PASSWORD,
+ provCredentials.getPasswordAsString());
+ }
+ }
+ }
+ else
+ {
+ return null;
+ }
+
+ InputStream in = uc.getInputStream();
+
+ // Chain a ProgressMonitorInputStream to the
+ // URLConnection's InputStream
+ final ProgressMonitorInputStream pin
+ = new ProgressMonitorInputStream(null, u.toString(), in);
+
+ // Set the maximum value of the ProgressMonitor
+ ProgressMonitor pm = pin.getProgressMonitor();
+ pm.setMaximum(uc.getContentLength());
+
+ final BufferedOutputStream bout
+ = new BufferedOutputStream(new FileOutputStream(temp));
+
+ try
+ {
+ int read = -1;
+ byte[] buff = new byte[1024];
+
+ while((read = pin.read(buff)) != -1)
+ {
+ bout.write(buff, 0, read);
+ }
+
+ pin.close();
+ bout.flush();
+ bout.close();
+ out.close();
+
+ return temp;
+ }
+ catch (Exception e)
+ {
+ logger.error("Error saving", e);
+
+ try
+ {
+ pin.close();
+ bout.close();
+ out.close();
+ }
+ catch (Exception e1)
+ {
+ }
+
+ return null;
+ }
+ }
+ catch (Exception e)
+ {
+ if (logger.isInfoEnabled())
+ logger.info("Error retrieving provisioning file!", e);
+ tmpFile.delete();
+ return null;
+ }
+ }
+
+ /**
+ * Update configuration with properties retrieved from provisioning URL.
+ *
+ * @param file provisioning file
+ */
+ private void updateConfiguration(final File file)
+ {
+ Properties fileProps = new Properties();
+ InputStream in = null;
+
+ try
+ {
+ in = new BufferedInputStream(new FileInputStream(file));
+ fileProps.load(in);
+
+ Iterator<Map.Entry<Object, Object> > it
+ = fileProps.entrySet().iterator();
+
+ while(it.hasNext())
+ {
+ Map.Entry<Object, Object> entry = it.next();
+
+ String key = (String)entry.getKey();
+ Object value = entry.getValue();
+
+ if(value instanceof String)
+ {
+ if(((String)value).equals("${null}"))
+ {
+ getConfigurationService().removeProperty(key);
+ continue;
+ }
+ }
+
+ /* password => credentials storage service */
+ if(key.endsWith(".PASSWORD"))
+ {
+ getCredentialsStorageService().storePassword(
+ key.substring(0, key.lastIndexOf(".")),
+ (String)value);
+ }
+ else
+ {
+ getConfigurationService().setProperty(key, value);
+ }
+ }
+
+ /* save the "new" configuration */
+ getConfigurationService().storeConfiguration();
+ try
+ {
+ getConfigurationService().reloadConfiguration();
+ }
+ catch(Exception e)
+ {
+ logger.error("Cannot reload configuration");
+ }
+ }
+ catch(IOException e)
+ {
+ logger.warn("Error during load of provisioning file");
+ }
+ finally
+ {
+ try
+ {
+ in.close();
+ file.delete();
+ }
+ catch(IOException e)
+ {
+ }
+ }
+ }
+
+ /**
+ * Return the certificate verification service impl.
+ * @return the CertificateVerification service.
+ */
+ private static CertificateVerificationService
+ getCertificateVerificationService()
+ {
+ if(certVerification == null)
+ {
+ ServiceReference certVerifyReference
+ = bundleContext.getServiceReference(
+ CertificateVerificationService.class.getName());
+ if(certVerifyReference != null)
+ certVerification
+ = (CertificateVerificationService)bundleContext.getService(
+ certVerifyReference);
+ }
+
+ return certVerification;
+ }
+
+ /**
+ * Returns a reference to a ConfigurationService implementation currently
+ * registered in the bundle context or null if no such implementation was
+ * found.
+ *
+ * @return a currently valid implementation of the ConfigurationService.
+ */
+ public static ConfigurationService getConfigurationService()
+ {
+ if (configurationService == null)
+ {
+ ServiceReference confReference
+ = bundleContext.getServiceReference(
+ ConfigurationService.class.getName());
+ configurationService
+ = (ConfigurationService)bundleContext.getService(confReference);
+ }
+ return configurationService;
+ }
+
+ /**
+ * Returns a reference to a CredentialsStorageService implementation
+ * currently registered in the bundle context or null if no such
+ * implementation was found.
+ *
+ * @return a currently valid implementation of the
+ * CredentialsStorageService.
+ */
+ public static CredentialsStorageService getCredentialsStorageService()
+ {
+ if (credentialsService == null)
+ {
+ ServiceReference credentialsReference
+ = bundleContext.getServiceReference(
+ CredentialsStorageService.class.getName());
+ credentialsService
+ = (CredentialsStorageService) bundleContext
+ .getService(credentialsReference);
+ }
+ return credentialsService;
+ }
+
+ /**
+ * Returns a reference to a NetworkAddressManagerService implementation
+ * currently registered in the bundle context or null if no such
+ * implementation was found.
+ *
+ * @return a currently valid implementation of the
+ * NetworkAddressManagerService.
+ */
+ public static NetworkAddressManagerService getNetworkAddressManagerService()
+ {
+ if (netaddrService == null)
+ {
+ ServiceReference netaddrReference
+ = bundleContext.getServiceReference(
+ NetworkAddressManagerService.class.getName());
+ netaddrService
+ = (NetworkAddressManagerService) bundleContext
+ .getService(netaddrReference);
+ }
+ return netaddrService;
+ }
+}
diff --git a/src/net/java/sip/communicator/plugin/provisioning/provisioning.manifest.mf b/src/net/java/sip/communicator/plugin/provisioning/provisioning.manifest.mf
new file mode 100644
index 0000000..826ce8c
--- /dev/null
+++ b/src/net/java/sip/communicator/plugin/provisioning/provisioning.manifest.mf
@@ -0,0 +1,17 @@
+Bundle-Activator: net.java.sip.communicator.plugin.provisioning.ProvisioningPluginActivator
+Bundle-Name: ProvisioningPlugin
+Bundle-Description: A bundle that implements the Provisioning Plugin Package.
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1
+System-Bundle: yes
+Import-Package: org.osgi.framework,
+ net.java.sip.communicator.service.configuration,
+ net.java.sip.communicator.service.credentialsstorage,
+ net.java.sip.communicator.service.protocol,
+ net.java.sip.communicator.service.provdisc,
+ net.java.sip.communicator.service.certificate,
+ net.java.sip.communicator.service.netaddr,
+ net.java.sip.communicator.util,
+ net.java.sip.communicator.util.swing,
+ javax.net.ssl,
+ javax.swing,
diff --git a/src/net/java/sip/communicator/service/protocol/media/MediaAwareCall.java b/src/net/java/sip/communicator/service/protocol/media/MediaAwareCall.java
index 62d862d..49999c6 100644
--- a/src/net/java/sip/communicator/service/protocol/media/MediaAwareCall.java
+++ b/src/net/java/sip/communicator/service/protocol/media/MediaAwareCall.java
@@ -147,6 +147,7 @@ public abstract class MediaAwareCall<
* also we can obtain the reason for the <tt>CallPeerChangeEvent</tt> if
* any. Use the event as cause for the call state change event..
*/
+ @SuppressWarnings("unchecked")
private void removeCallPeer(CallPeerChangeEvent evt)
{
T callPeer = (T)evt.getSourceCallPeer();
diff --git a/src/net/java/sip/communicator/service/provdisc/AbstractProvisioningDiscoveryService.java b/src/net/java/sip/communicator/service/provdisc/AbstractProvisioningDiscoveryService.java
new file mode 100644
index 0000000..b5712fb
--- /dev/null
+++ b/src/net/java/sip/communicator/service/provdisc/AbstractProvisioningDiscoveryService.java
@@ -0,0 +1,92 @@
+/*
+ * 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.provdisc;
+
+import java.util.*;
+
+import net.java.sip.communicator.service.provdisc.event.*;
+
+/**
+ * Abstract base class of ProvisioningDiscoveryService that ease implementation
+ *
+ * @author seb
+ *
+ */
+public abstract class AbstractProvisioningDiscoveryService
+ implements ProvisioningDiscoveryService
+{
+ /**
+ * List of <tt>ProvisioningListener</tt> that will be notified when
+ * a provisioning URL is retrieved.
+ */
+ private List<DiscoveryListener> listeners =
+ new ArrayList<DiscoveryListener>();
+
+ /**
+ * Get the name of the method name used to retrieve provisioning URL.
+ *
+ * @return method name
+ */
+ public abstract String getMethodName();
+
+ /**
+ * Launch a discovery for a provisioning URL.
+ *
+ * This method is asynchronous, the response will be notified to any
+ * <tt>ProvisioningListener</tt> registered.
+ */
+ public abstract void startDiscovery();
+
+ /**
+ * Launch a discovery for a provisioning URL. This method is synchronous and
+ * may block for some time.
+ *
+ * @return provisioning URL
+ */
+ public abstract String discoverURL();
+
+ /**
+ * Add a listener that will be notified when the
+ * <tt>discoverProvisioningURL</tt> has finished.
+ *
+ * @param listener <tt>ProvisioningListener</tt> to add
+ */
+ public void addDiscoveryListener(DiscoveryListener listener)
+ {
+ if(!listeners.contains(listener))
+ {
+ listeners.add(listener);
+ }
+ }
+
+ /**
+ * Add a listener that will be notified when the
+ * <tt>discoverProvisioningURL</tt> has finished.
+ *
+ * @param listener <tt>ProvisioningListener</tt> to add
+ */
+ public void removeDiscoveryListener(DiscoveryListener listener)
+ {
+ if(listeners.contains(listener))
+ {
+ listeners.remove(listener);
+ }
+ }
+
+ /**
+ * Notify all listeners about a <tt>DiscoveryEvent</tt>.
+ *
+ * @param event <tt>DiscoveryEvent</tt> that contains provisioning URL
+ */
+ public void fireDiscoveryEvent(DiscoveryEvent event)
+ {
+ for(DiscoveryListener listener : listeners)
+ {
+ listener.notifyProvisioningURL(event);
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/service/provdisc/ProvisioningDiscoveryService.java b/src/net/java/sip/communicator/service/provdisc/ProvisioningDiscoveryService.java
new file mode 100644
index 0000000..6f35a06
--- /dev/null
+++ b/src/net/java/sip/communicator/service/provdisc/ProvisioningDiscoveryService.java
@@ -0,0 +1,58 @@
+/*
+ * 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.provdisc;
+
+import net.java.sip.communicator.service.provdisc.event.*;
+
+/**
+ * Service that allow to retrieve a provisioning URL to configure
+ * SIP Communicator. Implementations (not exhaustive) could use DHCP,
+ * DNS (A, AAAA, SRV, TXT) or mDNS (Bonjour).
+ *
+ * @author Sebastien Vincent
+ */
+public interface ProvisioningDiscoveryService
+{
+ /**
+ * Get the name of the method name used to retrieve provisioning URL.
+ *
+ * @return method name
+ */
+ public String getMethodName();
+
+ /**
+ * Launch a discovery for a provisioning URL.
+ *
+ * This method is asynchronous, the response will be notified to any
+ * <tt>ProvisioningListener</tt> registered.
+ */
+ public void startDiscovery();
+
+ /**
+ * Launch a discovery for a provisioning URL. This method is synchronous and
+ * may block for some time.
+ *
+ * @return provisioning URL
+ */
+ public String discoverURL();
+
+ /**
+ * Add a listener that will be notified when the
+ * <tt>startDiscovery</tt> has finished.
+ *
+ * @param listener <tt>ProvisioningListener</tt> to add
+ */
+ public void addDiscoveryListener(DiscoveryListener listener);
+
+ /**
+ * Add a listener that will be notified when the
+ * <tt>discoverProvisioningURL</tt> has finished.
+ *
+ * @param listener <tt>ProvisioningListener</tt> to add
+ */
+ public void removeDiscoveryListener(DiscoveryListener listener);
+}
diff --git a/src/net/java/sip/communicator/service/provdisc/event/DiscoveryEvent.java b/src/net/java/sip/communicator/service/provdisc/event/DiscoveryEvent.java
new file mode 100644
index 0000000..0ab9001
--- /dev/null
+++ b/src/net/java/sip/communicator/service/provdisc/event/DiscoveryEvent.java
@@ -0,0 +1,49 @@
+/*
+ * 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.provdisc.event;
+
+import java.util.*;
+
+/**
+ * Event representing that a provisioning URL has been retrieved.
+ *
+ * @author Sebastien Vincent
+ */
+public class DiscoveryEvent extends EventObject
+{
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Provisioning URL.
+ */
+ private String url = null;
+
+ /**
+ * Constructor.
+ *
+ * @param source object that have created this event
+ * @param url provisioning URL
+ */
+ public DiscoveryEvent(Object source, String url)
+ {
+ super(source);
+ this.url = url;
+ }
+
+ /**
+ * Get the provisioning URL.
+ *
+ * @return provisioning URL
+ */
+ public String getProvisioningURL()
+ {
+ return url;
+ }
+}
diff --git a/src/net/java/sip/communicator/service/provdisc/event/DiscoveryListener.java b/src/net/java/sip/communicator/service/provdisc/event/DiscoveryListener.java
new file mode 100644
index 0000000..ef136b9
--- /dev/null
+++ b/src/net/java/sip/communicator/service/provdisc/event/DiscoveryListener.java
@@ -0,0 +1,25 @@
+/*
+ * 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.provdisc.event;
+
+import java.util.*;
+
+/**
+ * Listener that will be notified when a provisioning URL is retrieved by the
+ * <tt>ProvisioningDiscoveryService</tt>.
+ *
+ * @author Sebastien Vincent
+ */
+public interface DiscoveryListener extends EventListener
+{
+ /**
+ * Notify the provisioning URL.
+ *
+ * @param event provisioning event
+ */
+ public void notifyProvisioningURL(DiscoveryEvent event);
+}
diff --git a/src/net/java/sip/communicator/service/provdisc/provdisc.manifest.mf b/src/net/java/sip/communicator/service/provdisc/provdisc.manifest.mf
new file mode 100644
index 0000000..69e9d6c
--- /dev/null
+++ b/src/net/java/sip/communicator/service/provdisc/provdisc.manifest.mf
@@ -0,0 +1,7 @@
+Bundle-Name: Provisioning Discovery Service
+Bundle-Description: Provisioning Discovery Service.
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1
+System-Bundle: yes
+Export-Package: net.java.sip.communicator.service.provdisc,
+ net.java.sip.communicator.service.provdisc.event \ No newline at end of file
diff --git a/src/net/java/sip/communicator/util/swing/AuthenticationWindow.java b/src/net/java/sip/communicator/util/swing/AuthenticationWindow.java
index 46e112e..b6533de 100644
--- a/src/net/java/sip/communicator/util/swing/AuthenticationWindow.java
+++ b/src/net/java/sip/communicator/util/swing/AuthenticationWindow.java
@@ -126,7 +126,12 @@ public class AuthenticationWindow
{
this.server = server;
- Image logoImage = icon.getImage();
+ Image logoImage = null;
+
+ if(icon != null)
+ {
+ logoImage = icon.getImage();
+ }
if(!isUserNameEditable)
this.uinValue = new JLabel();