diff --git a/.gitignore b/.gitignore
index e1a535379..35c645123 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,4 @@ sip-communicator.utest.bin
release
lib/accounts.properties
.DS_Store
+web-start/WebStartBuild.properties
diff --git a/build.xml b/build.xml
index a8d0fb6db..85b9ee74f 100644
--- a/build.xml
+++ b/build.xml
@@ -1463,7 +1463,7 @@ javax.swing.event, javax.swing.border"/>
-
diff --git a/src/net/java/sip/communicator/launcher/SIPCommunicatorJWS.java b/src/net/java/sip/communicator/launcher/SIPCommunicatorJWS.java
new file mode 100644
index 000000000..51c02c43d
--- /dev/null
+++ b/src/net/java/sip/communicator/launcher/SIPCommunicatorJWS.java
@@ -0,0 +1,140 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.launcher;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.net.*;
+import java.util.*;
+import java.util.jar.*;
+import java.util.logging.*;
+
+import net.java.sip.communicator.util.FileHandler;
+import net.java.sip.communicator.util.*;
+
+public class SIPCommunicatorJWS
+{
+ public static void main(String[] args) throws Exception
+ {
+ // allow access to everything
+ System.setSecurityManager(null);
+
+ // prepare the logger
+ // needed by the FileHandler-Logger
+ SIPCommunicator.setScHomeDir(System.getProperty("os.name"));
+ LogManager.getLogManager()
+ .readConfiguration(
+ SIPCommunicatorJWS.class
+ .getResourceAsStream("/logging.properties"));
+
+ for (Handler h : LogManager.getLogManager().getLogger("").getHandlers())
+ LogManager.getLogManager().getLogger("").removeHandler(h);
+ LogManager.getLogManager().getLogger("").addHandler(new FileHandler());
+ LogManager.getLogManager().getLogger("")
+ .addHandler(new ConsoleHandler());
+ for (Handler h : LogManager.getLogManager().getLogger("").getHandlers())
+ h.setFormatter(new ScLogFormatter());
+
+ // be evil :-)
+ // find the path of the nativelibs under webstart (findLibrary is
+ // protected and therefore at least documented api)
+ Method findLibrary =
+ SIPCommunicatorJWS.class.getClassLoader().getClass()
+ .getDeclaredMethod("findLibrary", String.class);
+ findLibrary.setAccessible(true);
+ File path =
+ new File((String) findLibrary.invoke(
+ SIPCommunicatorJWS.class.getClassLoader(), "hid"))
+ .getParentFile();
+ System.setProperty(
+ "java.library.path",
+ System.getProperty("java.library.path") + File.pathSeparator
+ + path.getAbsolutePath());
+
+ // reset sys_paths to re-read usr_paths (runtime-dependent and therefore
+ // very very ugly :()
+ Field sys_paths = ClassLoader.class.getDeclaredField("sys_paths");
+ sys_paths.setAccessible(true);
+ sys_paths.set(null, null);
+
+ // prepare the felix-config with the absolute paths
+ Properties pIn = new Properties();
+ Properties pOut = new Properties();
+ pIn.load(SIPCommunicatorJWS.class.getResourceAsStream(System
+ .getProperty("felix.config.properties")));
+
+ String baseServerUrl =
+ System.getProperty("net.java.sip.communicator.SC_JWS_BASEDIR");
+ ClassLoader cl = SIPCommunicatorJWS.class.getClassLoader();
+ Method getJarFile =
+ cl.getClass().getDeclaredMethod("getJarFile", URL.class);
+ getJarFile.setAccessible(true);
+ for (Map.Entry e : pIn.entrySet())
+ {
+ if (((String) e.getKey()).startsWith("felix.auto.start."))
+ {
+ String[] refs = ((String) e.getValue()).split("\\s");
+ StringBuilder sb = new StringBuilder();
+ for (String ref : refs)
+ {
+ JarFile localFile =
+ (JarFile) getJarFile.invoke(cl, new URL(baseServerUrl
+ + ref.replace("@URL@", "")));
+ if (localFile != null)
+ {
+ String localFileName =
+ new File(localFile.getName()).toURI().toString();
+ sb.append("reference:");
+ sb.append(localFileName);
+ sb.append(" ");
+ }
+ else
+ {
+ throw new Exception("ref <" + ref
+ + "> not found in cache");
+ }
+ }
+ pOut.put(e.getKey(), sb.toString());
+ }
+ else
+ {
+ pOut.put(e.getKey(), e.getValue());
+ }
+ }
+ File jwsFelixConfig = File.createTempFile("jws", ".properties");
+ jwsFelixConfig.deleteOnExit();
+ pOut.store(new FileOutputStream(jwsFelixConfig),
+ "--- autogenerated, do not edit! ---");
+ System.setProperty("felix.config.properties", jwsFelixConfig.toURI()
+ .toString());
+
+ // Workaround broken desktop shortcut in ubuntu linux:
+ // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6957030
+ try
+ {
+ if (System.getProperty("os.name").equals("Linux"))
+ {
+ File desktop =
+ new File(System.getProperty("user.home") + "/Desktop");
+ File[] files = desktop.listFiles();
+ for (File file : files)
+ {
+ if (file.getName().contains("jws_app_shortcut_"))
+ {
+ file.setExecutable(true, false);
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ }
+
+ // launch the original app
+ SIPCommunicator.main(args);
+ }
+}
diff --git a/web-start/WebStartBuild.properties.sample b/web-start/WebStartBuild.properties.sample
new file mode 100644
index 000000000..f2591cc5e
--- /dev/null
+++ b/web-start/WebStartBuild.properties.sample
@@ -0,0 +1,9 @@
+# value without trailing '/' (slash)
+java.jdk.dir = c:\\java\\jdk6
+
+keystore.alias =
+keystore.file =
+keystore.password =
+
+# value without trailing '/' (slash)
+webstart.codebase.url = http://localhost/client
diff --git a/web-start/WebStartBuild.xml b/web-start/WebStartBuild.xml
new file mode 100644
index 000000000..5af278925
--- /dev/null
+++ b/web-start/WebStartBuild.xml
@@ -0,0 +1,292 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/web-start/ant-ext/FelixConfigSelector.java b/web-start/ant-ext/FelixConfigSelector.java
new file mode 100644
index 000000000..e1ceae847
--- /dev/null
+++ b/web-start/ant-ext/FelixConfigSelector.java
@@ -0,0 +1,92 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
+ */
+import java.io.*;
+import java.util.*;
+
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.types.selectors.*;
+
+/**
+ * Selector which lets those files through that are referenced in the felix
+ * configuration file.
+ */
+public class FelixConfigSelector
+ implements FileSelector
+{
+ private Set referencedBundleCache;
+
+ private File felixConfig;
+
+ public void setFelixConfig(File felixConifg)
+ {
+ if (!felixConifg.isFile())
+ throw new BuildException("No felix configuration file provided.");
+
+ this.felixConfig = felixConifg;
+ }
+
+ @Override
+ public boolean isSelected(File basedir, String filename, File file)
+ {
+ cacheConfigEntries(basedir);
+ return referencedBundleCache.contains(file);
+ }
+
+ private void cacheConfigEntries(File basedir)
+ {
+ if (referencedBundleCache != null)
+ return;
+
+ // cache files referenced in felix config
+ referencedBundleCache = new HashSet();
+
+ // load felix config
+ Properties pIn = new Properties();
+ try
+ {
+ pIn.load(new FileInputStream(felixConfig));
+ }
+ catch (FileNotFoundException e)
+ {
+ throw new BuildException(e);
+ }
+ catch (IOException e)
+ {
+ throw new BuildException(e);
+ }
+
+ for (Map.Entry e : pIn.entrySet())
+ {
+ if (((String) e.getKey()).startsWith("felix.auto.start."))
+ {
+ String[] refs = ((String) e.getValue()).split("\\s");
+ for (String jar : refs)
+ {
+ if (jar.startsWith("reference:file:"))
+ {
+ String relPath =
+ jar.substring("reference:file:".length());
+ String absPath =
+ basedir.getPath() + File.separator + relPath;
+ File f = new File(absPath);
+ if (f.isFile())
+ {
+ referencedBundleCache.add(f);
+ }
+ else
+ {
+ System.out.println(
+ "WARNING: Referenced file does not exist: "
+ + f.getPath());
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/web-start/ant-ext/GenerateFelixConfigs.java b/web-start/ant-ext/GenerateFelixConfigs.java
new file mode 100644
index 000000000..2a1db05c5
--- /dev/null
+++ b/web-start/ant-ext/GenerateFelixConfigs.java
@@ -0,0 +1,161 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
+ */
+import org.apache.tools.ant.*;
+
+import java.io.*;
+import java.util.*;
+
+public class GenerateFelixConfigs
+ extends Task
+{
+ private File baseConfig;
+
+ private String os;
+
+ private File libdir;
+
+ private File bundledir;
+
+ private File output;
+
+ public void setFile(File f)
+ {
+ baseConfig = f;
+ }
+
+ public void setOs(String os)
+ {
+ this.os = os;
+ }
+
+ public void setBundledir(File bundledir)
+ {
+ this.bundledir = bundledir;
+ }
+
+ public void setLibdir(File libdir)
+ {
+ this.libdir = libdir;
+ }
+
+ public void setOutput(File output)
+ {
+ this.output = output;
+ }
+
+ public void execute() throws BuildException
+ {
+ try
+ {
+ execute0();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ throw new BuildException(e);
+ }
+ }
+
+ public void execute0() throws BuildException
+ {
+ Properties pIn = new Properties();
+ Properties pOut = new Properties();
+ try
+ {
+ pIn.load(new FileInputStream(baseConfig));
+ }
+ catch (FileNotFoundException e)
+ {
+ throw new BuildException(e);
+ }
+ catch (IOException e)
+ {
+ throw new BuildException(e);
+ }
+
+ for (Map.Entry e : pIn.entrySet())
+ {
+ if (((String) e.getKey()).startsWith("felix.auto.start."))
+ {
+ String[] refs = ((String) e.getValue()).split("\\s");
+ StringBuilder value = new StringBuilder();
+ for (String jar : refs)
+ {
+ if (jar.startsWith("reference:file:sc-bundles/"))
+ {
+ String name =
+ jar.substring("reference:file:sc-bundles/".length());
+ if (contains(
+ new File(bundledir, "os-specific/" + os).list(),
+ name))
+ {
+ value.append("@URL@/sc-bundles/");
+ value.append("os-specific/");
+ value.append(os);
+ value.append("/");
+ value.append(name);
+ }
+ else if (contains(bundledir.list(), name))
+ {
+ value.append("@URL@/sc-bundles/");
+ value.append(name);
+ }
+ else
+ {
+ log("Bundle <" + name + "> not found in <"
+ + bundledir.getName()
+ + ">. Seems like this bundle was ignored.");
+ }
+ }
+ else if (jar.startsWith("reference:file:lib/bundle/"))
+ {
+ String name =
+ jar.substring("reference:file:lib/bundle/".length());
+ if (contains(libdir.list(), name))
+ {
+ value.append("@URL@/lib/bundle/");
+ value.append(name);
+ }
+ else
+ {
+ log("Lib <" + name + "> not found in <" + libdir
+ + ">. Seems like this lib was ignored.");
+ }
+ }
+ else
+ {
+ throw new BuildException(
+ "unsupported reference prefix: " + jar);
+ }
+ value.append(" ");
+ }
+ pOut.put(e.getKey(), value.toString());
+ }
+ else
+ {
+ pOut.put(e.getKey(), e.getValue());
+ }
+ }
+ try
+ {
+ pOut.store(new FileOutputStream(output),
+ "--- autogenerated by GenerateFelixConfigs, do not edit! ---");
+ }
+ catch (FileNotFoundException e)
+ {
+ throw new BuildException(e);
+ }
+ catch (IOException e)
+ {
+ throw new BuildException(e);
+ }
+ }
+
+ private boolean contains(String[] files, String file)
+ {
+ return Arrays.asList(files).contains(file);
+ }
+}
diff --git a/web-start/ant-ext/PutJarsToJnlp.java b/web-start/ant-ext/PutJarsToJnlp.java
new file mode 100644
index 000000000..de597608a
--- /dev/null
+++ b/web-start/ant-ext/PutJarsToJnlp.java
@@ -0,0 +1,76 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license. See terms of license at gnu.org.
+ */
+import org.apache.tools.ant.*;
+
+import java.io.*;
+import java.util.*;
+
+public class PutJarsToJnlp
+ extends Task
+{
+ private File bundledir;
+
+ private File osbundles;
+
+ public void setBundledir(File b)
+ {
+ bundledir = b;
+ }
+
+ public void setOsbundles(File f)
+ {
+ osbundles = f;
+ }
+
+ public void execute() throws BuildException
+ {
+ try
+ {
+ execute0();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ throw new BuildException(e);
+ }
+ }
+
+ public void execute0() throws BuildException
+ {
+ StringBuilder common = new StringBuilder();
+ for (File jar : bundledir.listFiles())
+ {
+ if (jar.isFile())
+ {
+ common.append(" \n");
+ }
+ }
+ getProject().setProperty("jnlp.jars.common", common.toString());
+
+ for (File dir : osbundles.listFiles())
+ {
+ if (dir.isDirectory())
+ {
+ StringBuilder os = new StringBuilder();
+ for (File jar : dir.listFiles())
+ {
+ if (jar.isFile())
+ {
+ os.append(" \n");
+ }
+ }
+ getProject().setProperty("jnlp.jars." + dir.getName(),
+ os.toString());
+ }
+ }
+ }
+}
diff --git a/web-start/client.jnlp_template b/web-start/client.jnlp_template
new file mode 100644
index 000000000..58079dd5f
--- /dev/null
+++ b/web-start/client.jnlp_template
@@ -0,0 +1,102 @@
+
+
+
+
+ Jitsi
+ jitsi.org
+ Jitsi - Open Source Video Calls and Chat
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @WINDOWS@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @LINUX@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @MACOSX@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @COMMON@
+
+
+
+
+
diff --git a/web-start/index.html b/web-start/index.html
new file mode 100644
index 000000000..cdeadcd1a
--- /dev/null
+++ b/web-start/index.html
@@ -0,0 +1,21 @@
+
+
+Launch Jitsi
+
+
+Tested Operating Systems:
+
+ Windows Vista, 7, 8 (32 & 64 bit)
+ Windows XP 32 bit
+ Mac OS X
+ Ubuntu Linux 32 & 64 bit
+
+Only Sun's/Oracle's JVM is supported and tested. Your Java Web Start cache must be enabled.
+
+
+In case Jitsi starts with errors please delete the 'jitsi-jws'
+folder in your home directory and try again. If this does not solve the problem contact us.
+
+
+
+