Compare commits

...

16 Commits

Author SHA1 Message Date
idk
57833edc36 always check out branch when building launcher, not just the first time 2023-03-20 17:27:16 +00:00
idk
a19fcd9ea5 remember to update I2PFIREFOX_VERSION to 1.0.9 2023-03-20 17:11:01 +00:00
idk
bfddc378cd update I2P version 2023-03-19 16:26:53 +00:00
idk
fd712293b4 update I2P version 2023-03-19 16:26:26 +00:00
idk
068fbee70e move extra docs to docs directory 2023-02-22 22:05:50 +00:00
idk
377c836887 fix other static reference conflicts 2023-02-12 19:27:24 +00:00
idk
99a4959c12 fix other static reference conflicts 2023-02-12 19:18:25 +00:00
idk
922ec66f95 only use instance reference to logger in static context 2023-02-12 19:05:56 +00:00
idk
298c87f457 update javadoc at top of winlauncher, lots more javadoc to do. 2023-02-12 16:52:40 +00:00
idk
fcacf59a48 main functions should still be static 2023-02-12 16:50:59 +00:00
idk
8d06c9079b main functions should still be static 2023-02-12 16:48:49 +00:00
idk
c0fb7dcf67 remove redundant admin check in nsis 2023-02-09 19:02:59 +00:00
idk
019581479b Tag nightlies with a date, remove jpackaged file from nsis installer 2023-02-09 02:48:49 +00:00
idk
65fb9e1847 Remove admin update subsystem along with admin installs. There is no more need to change the update URL on the first run now that it uses it's own directory. Tweak WindowsUpdatePostProcessor to use a zip update only as a backup. 2023-02-08 21:47:54 +00:00
idk
402cede106 mark Elevator and Shell32X for removal 2023-02-06 17:46:14 +00:00
idk
673d6b469f change appname 2023-01-31 20:10:19 +00:00
16 changed files with 180 additions and 418 deletions

View File

@ -1,29 +0,0 @@
Setting up an Update Server for an I2P Bundle
=============================================
It is important to set up a signed update server so that people are able to
safely and anonymously update your I2P bundle.
The quick way:
--------------
This process depends on my ability to push releases to github. If you are
forking, setting up a dev server, or taking over because I got hit by a bus,
you'll need to do it the complete way.
For as long as I am building updates, you will be able to mirror the jpackaged
Windows bundle by cloning the repository `https://github.com/eyedeekay/i2p` and
running the `make docker run` target in that repository. You can retrieve the
base32 address of your update server by viewing the log with
`docker logs eephttpd-jpackage | grep b32.i2p | tee eephttpd-address.md`. To
update the site, run `./update.site.sh` in that repository.
Once you have cloned the repository and started the container with
`make docker run`, you can simply add `path/to/repo/update-site.sh` to your
`crontab` and it will update at an interval of your choosing.
The complete way:
-----------------
TODO: describe how to do it with less of the awesome fancy stuff I put together
to make it easier on myself to keep an update server going.

View File

@ -30,10 +30,10 @@ if [ "$JAVA" -lt "17" ]; then
fi fi
if [ -z "${JAVA_HOME}" ]; then if [ -z "${JAVA_HOME}" ]; then
export JAVA_HOME=`type -p java|xargs readlink -f|xargs dirname|xargs dirname` export JAVA_HOME=$(type -p java|xargs readlink -f|xargs dirname|xargs dirname)
fi fi
if [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then if [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then
export JAVA_HOME=`type -p java|xargs readlink -f|xargs dirname|xargs dirname` export JAVA_HOME=$(type -p java|xargs readlink -f|xargs dirname|xargs dirname)
fi fi
echo "Building with: $JAVA, $JAVA_HOME" echo "Building with: $JAVA, $JAVA_HOME"
sleep 5s sleep 5s
@ -56,10 +56,16 @@ if [ -z "$EXTRA" ]; then
export EXTRACODE="win" export EXTRACODE="win"
export EXTRA=" public final static String EXTRA = \"-$EXTRACODE\";" export EXTRA=" public final static String EXTRA = \"-$EXTRACODE\";"
fi fi
if [ "$VERSION" = master ]; then
VERSIONDATE="$(date +%m%d)"
fi
find . -name RouterVersion.java -exec sed -i "s|$OLDEXTRA|$EXTRA|g" {} \; find . -name RouterVersion.java -exec sed -i "s|$OLDEXTRA|$EXTRA|g" {} \;
git checkout -b "i2p-$VERSION-$EXTRACODE" && git commit -am "i2p-$VERSION-$EXTRACODE" git switch - || :
git pull --tags git pull --tags
git archive --format=tar.gz --output="$SCRIPT_DIR/../i2p.firefox/i2p.i2p.jpackage-build.tar.gz" "i2p-$VERSION-$EXTRACODE" git checkout -b "i2p-$VERSION$VERSIONDATE-$EXTRACODE" || :
git commit -am "i2p-$VERSION$VERSIONDATE-$EXTRACODE" || :
git archive --format=tar.gz --output="$SCRIPT_DIR/../i2p.firefox/i2p.i2p.jpackage-build.tar.gz" "i2p-$VERSION$VERSIONDATE-$EXTRACODE"
git checkout "i2p-$VERSION$VERSIONDATE-$EXTRACODE" || :
for i in $COUNT; do for i in $COUNT; do
echo -n "$i...."; sleep 1s echo -n "$i...."; sleep 1s
@ -105,15 +111,12 @@ for dll in "$I2P_JBIGI/"*windows*.dll; do
done done
cd "$SCRIPT_DIR"/java cd "$SCRIPT_DIR"/java
"$JAVA_HOME"/bin/javac -d ../build -classpath "$SCRIPT_DIR/build/i2pfirefox.jar:$SCRIPT_DIR/build/jna.jar":"$SCRIPT_DIR/build/jna-platform.jar":"$SCRIPT_DIR/build/i2p.jar":"$SCRIPT_DIR/build/router.jar":"$SCRIPT_DIR/build/routerconsole.jar":"$SCRIPT_DIR/build/jbigi.jar" \ "$JAVA_HOME"/bin/javac -Xlint:deprecation -d ../build -classpath "$SCRIPT_DIR/build/i2pfirefox.jar:$SCRIPT_DIR/build/jna.jar":"$SCRIPT_DIR/build/jna-platform.jar":"$SCRIPT_DIR/build/i2p.jar":"$SCRIPT_DIR/build/router.jar":"$SCRIPT_DIR/build/routerconsole.jar":"$SCRIPT_DIR/build/jbigi.jar" \
net/i2p/router/CopyConfigDir.java \ net/i2p/router/CopyConfigDir.java \
net/i2p/router/Elevator.java \
net/i2p/router/Shell32X.java \
net/i2p/router/WindowsServiceUtil.java \ net/i2p/router/WindowsServiceUtil.java \
net/i2p/router/WinLauncher.java \
net/i2p/router/WindowsUpdatePostProcessor.java \ net/i2p/router/WindowsUpdatePostProcessor.java \
net/i2p/router/WinLauncher.java \
net/i2p/router/WinUpdateProcess.java \ net/i2p/router/WinUpdateProcess.java \
net/i2p/router/WindowsServiceUtil.java \
net/i2p/router/ZipUpdateProcess.java net/i2p/router/ZipUpdateProcess.java
cd .. cd ..

25
docs/UPDATES.md Normal file
View File

@ -0,0 +1,25 @@
Setting up an Update Server for an I2P Bundle
=============================================
It is important to set up a signed update server so that people are able to
safely and anonymously update your I2P bundle. There are two sort of "Levels"
to what you might do to provide updates to your users. Each of them requires the
generation of a [signed newsfeed](https://eyedeekay.github.io/Hopefully-Holistic-Guide-to-I2P-Dev-Build-Update-Hosting/),
which also serves as a way to provide information to your users about updates,
features, and security events.
This project, `i2p.firefox` a.k.a. the "I2P Easy Install Bundle" uses the "Executable"
update subtype, meaning that it capable of installing itself by executing code as the
user who runs the update, which is usually the main user of a Windows 10 or 11 PC.
This update subtype is highly flexible, but requires the creation of a "Scripted" using
something like `NSIS`, `wixl`, or custom code. Other update types include ZIP (used by
the core I2P product) and DMG(used by Mac OSX).
Static HTTP Update URL over I2P
===============================
Bittorrent Update URL over I2P
==============================
[If you choose to do this, consider using zzzot to host your open tracker instead of a normal site](https://github.com/i2p/i2p.plugins.zzzot),
which you can obtain from [this I2P link](http://stats.i2p/i2p/plugins/zzzot.su3).

View File

@ -2,14 +2,14 @@
JNA_VERSION=5.12.1 JNA_VERSION=5.12.1
export JNA_VERSION=5.12.1 export JNA_VERSION=5.12.1
I2PFIREFOX_VERSION=1.0.7 I2PFIREFOX_VERSION=1.0.9
export I2PFIREFOX_VERSION=1.0.7 export I2PFIREFOX_VERSION=1.0.9
# Comment this out to build from an alternate branch or # Comment this out to build from an alternate branch or
# the tip of the master branch. # the tip of the master branch.
VERSIONMAJOR=2 VERSIONMAJOR=2
VERSIONMINOR=1 VERSIONMINOR=2
VERSIONBUILD=0 VERSIONBUILD=0
I2P_VERSION="$VERSIONMAJOR.$VERSIONMINOR.$VERSIONBUILD" I2P_VERSION="$VERSIONMAJOR.$VERSIONMINOR.$VERSIONBUILD"
export I2P_VERSION="$VERSIONMAJOR.$VERSIONMINOR.$VERSIONBUILD" export I2P_VERSION="$VERSIONMAJOR.$VERSIONMINOR.$VERSIONBUILD"
VERSION=i2p-2.1.0 VERSION=i2p-2.2.0
export VERSION=i2p-2.1.0 export VERSION=i2p-2.2.0

View File

@ -13,9 +13,9 @@ import java.util.logging.Logger;
import java.util.logging.SimpleFormatter; import java.util.logging.SimpleFormatter;
public class CopyConfigDir extends WindowsServiceUtil { public class CopyConfigDir extends WindowsServiceUtil {
static final Logger logger = Logger.getLogger("configlog"); final Logger logger = Logger.getLogger("configlog");
public static void initLogger() { public void initLogger() {
try { try {
// This block configure the logger with handler and formatter // This block configure the logger with handler and formatter
FileHandler fh = new FileHandler(logFile().toString()); FileHandler fh = new FileHandler(logFile().toString());
@ -31,13 +31,13 @@ public class CopyConfigDir extends WindowsServiceUtil {
} }
} }
public static boolean copyDirectory(String baseDir, String workDir) { public boolean copyDirectory(String baseDir, String workDir) {
File baseFile = new File(baseDir); File baseFile = new File(baseDir);
File workFile = new File(workDir); File workFile = new File(workDir);
return copyDirectory(baseFile, workFile); return copyDirectory(baseFile, workFile);
} }
public static boolean copyDirectory(File baseDir, File workDir) { public boolean copyDirectory(File baseDir, File workDir) {
for (File file : baseDir.listFiles()) { for (File file : baseDir.listFiles()) {
String fPath = file.getAbsolutePath().replace( String fPath = file.getAbsolutePath().replace(
file.getParentFile().getAbsolutePath(), ""); file.getParentFile().getAbsolutePath(), "");
@ -52,7 +52,7 @@ public class CopyConfigDir extends WindowsServiceUtil {
return true; return true;
} }
public static boolean copyConfigDirectory(File baseDir, File workDir) { public boolean copyConfigDirectory(File baseDir, File workDir) {
for (File file : baseDir.listFiles()) { for (File file : baseDir.listFiles()) {
// System.out.println(file.getAbsolutePath()); // System.out.println(file.getAbsolutePath());
String fPath = file.getAbsolutePath().replace( String fPath = file.getAbsolutePath().replace(
@ -87,17 +87,17 @@ public class CopyConfigDir extends WindowsServiceUtil {
return true; return true;
} }
public static int copyFileNeverOverwrite(String basePath, String workPath) { public int copyFileNeverOverwrite(String basePath, String workPath) {
File baseFile = new File(basePath); File baseFile = new File(basePath);
File workFile = new File(workPath); File workFile = new File(workPath);
return copyFileNeverOverwrite(baseFile, workFile); return copyFileNeverOverwrite(baseFile, workFile);
} }
public static int copyFileNeverOverwrite(File basePath, File workPath) { public int copyFileNeverOverwrite(File basePath, File workPath) {
return copyFile(basePath, workPath, false); return copyFile(basePath, workPath, false);
} }
public static int copyFile(File basePath, File workPath, boolean overWrite) { public int copyFile(File basePath, File workPath, boolean overWrite) {
if (!basePath.exists()) { if (!basePath.exists()) {
logger.info(basePath.getAbsolutePath() + " doesn't exist, not copying"); logger.info(basePath.getAbsolutePath() + " doesn't exist, not copying");
return 0; return 0;
@ -135,7 +135,7 @@ public class CopyConfigDir extends WindowsServiceUtil {
} }
} }
protected static File selectHome() { // throws Exception { protected File selectHome() { // throws Exception {
String path_override = System.getenv("I2P_CONFIG"); String path_override = System.getenv("I2P_CONFIG");
if (path_override != null) { if (path_override != null) {
File path = new File(path_override); File path = new File(path_override);
@ -151,7 +151,7 @@ public class CopyConfigDir extends WindowsServiceUtil {
return i2p; return i2p;
} }
protected static File selectProgramFile() { protected File selectProgramFile() {
String path_override = System.getenv("I2P"); String path_override = System.getenv("I2P");
if (path_override != null) { if (path_override != null) {
File path = new File(path_override); File path = new File(path_override);
@ -182,7 +182,7 @@ public class CopyConfigDir extends WindowsServiceUtil {
* *
* @return * @return
*/ */
protected static File javaHome() { protected File javaHome() {
File jrehome = new File(System.getProperty("java.home")); File jrehome = new File(System.getProperty("java.home"));
if (jrehome != null) { if (jrehome != null) {
if (jrehome.exists()) { if (jrehome.exists()) {
@ -199,7 +199,7 @@ public class CopyConfigDir extends WindowsServiceUtil {
* *
* @return the app-image root * @return the app-image root
*/ */
protected static File appImageHome() { protected File appImageHome() {
File jreHome = javaHome(); File jreHome = javaHome();
if (jreHome != null) { if (jreHome != null) {
switch (osName()) { switch (osName()) {
@ -221,7 +221,7 @@ public class CopyConfigDir extends WindowsServiceUtil {
* *
* @return the app-image root * @return the app-image root
*/ */
protected static String appImageExe() { protected String appImageExe() {
File aih = appImageHome(); File aih = appImageHome();
if (aih != null) { if (aih != null) {
switch (osName()) { switch (osName()) {
@ -243,7 +243,7 @@ public class CopyConfigDir extends WindowsServiceUtil {
* *
* @return the app-image root * @return the app-image root
*/ */
protected static File appImageConfig() { protected File appImageConfig() {
File aih = appImageHome(); File aih = appImageHome();
if (aih == null) { if (aih == null) {
return null; return null;
@ -269,13 +269,13 @@ public class CopyConfigDir extends WindowsServiceUtil {
return null; return null;
} }
protected static boolean copyConfigDir() { protected boolean copyConfigDir() {
File appImageConfigDir = appImageConfig(); File appImageConfigDir = appImageConfig();
File appImageHomeDir = selectHome(); File appImageHomeDir = selectHome();
return copyConfigDirectory(appImageConfigDir, appImageHomeDir); return copyConfigDirectory(appImageConfigDir, appImageHomeDir);
} }
protected static String routerConfig() { protected String routerConfig() {
File appImageHomeDir = selectHome(); File appImageHomeDir = selectHome();
File routerConf = new File(appImageHomeDir, "router.config"); File routerConf = new File(appImageHomeDir, "router.config");
if (routerConf != null) { if (routerConf != null) {
@ -291,14 +291,14 @@ public class CopyConfigDir extends WindowsServiceUtil {
* *
* @return * @return
*/ */
protected static File logFile() { return logFile("launcher.log"); } protected File logFile() { return logFile("launcher.log"); }
/** /**
* set up the path to the log file * set up the path to the log file
* *
* @return * @return
*/ */
protected static File logFile(String p) { protected File logFile(String p) {
File log = new File(selectProgramFile(), "logs"); File log = new File(selectProgramFile(), "logs");
if (!log.exists()) if (!log.exists())
log.mkdirs(); log.mkdirs();

View File

@ -1,35 +0,0 @@
package net.i2p.router;
import com.sun.jna.WString;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.Kernel32Util;
public class Elevator {
public static void main(String... args) {
executeAsAdministrator("c:\\windows\\system32\\notepad.exe", "");
}
public static void executeAsAdministrator(String command, String args) {
if (command == "" || command == null) {
System.out.println("No command specified");
return;
}
Shell32X.SHELLEXECUTEINFO execInfo = new Shell32X.SHELLEXECUTEINFO();
execInfo.lpFile = new WString(command);
if (args != null)
execInfo.lpParameters = new WString(args);
execInfo.nShow = Shell32X.SW_SHOWDEFAULT;
execInfo.fMask = Shell32X.SEE_MASK_NOCLOSEPROCESS;
execInfo.lpVerb = new WString("runas");
boolean result = Shell32X.INSTANCE.ShellExecuteEx(execInfo);
if (!result) {
int lastError = Kernel32.INSTANCE.GetLastError();
String errorMessage =
Kernel32Util.formatMessageFromLastErrorCode(lastError);
throw new RuntimeException("Error performing elevation: " + lastError +
": " + errorMessage +
" (apperror=" + execInfo.hInstApp + ")");
}
}
}

View File

@ -1,123 +0,0 @@
package net.i2p.router;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.WString;
import com.sun.jna.platform.win32.Shell32;
import com.sun.jna.platform.win32.WinDef.HINSTANCE;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.platform.win32.WinReg.HKEY;
import com.sun.jna.win32.W32APIOptions;
import java.util.*;
public interface Shell32X extends Shell32 {
Shell32X INSTANCE = (Shell32X)Native.loadLibrary(
"shell32", Shell32X.class, W32APIOptions.UNICODE_OPTIONS);
int SW_HIDE = 0;
int SW_MAXIMIZE = 3;
int SW_MINIMIZE = 6;
int SW_RESTORE = 9;
int SW_SHOW = 5;
int SW_SHOWDEFAULT = 10;
int SW_SHOWMAXIMIZED = 3;
int SW_SHOWMINIMIZED = 2;
int SW_SHOWMINNOACTIVE = 7;
int SW_SHOWNA = 8;
int SW_SHOWNOACTIVATE = 4;
int SW_SHOWNORMAL = 1;
/** File not found. */
int SE_ERR_FNF = 2;
/** Path not found. */
int SE_ERR_PNF = 3;
/** Access denied. */
int SE_ERR_ACCESSDENIED = 5;
/** Out of memory. */
int SE_ERR_OOM = 8;
/** DLL not found. */
int SE_ERR_DLLNOTFOUND = 32;
/** Cannot share an open file. */
int SE_ERR_SHARE = 26;
int SEE_MASK_NOCLOSEPROCESS = 0x00000040;
int ShellExecute(int i, String lpVerb, String lpFile, String lpParameters,
String lpDirectory, int nShow);
boolean ShellExecuteEx(SHELLEXECUTEINFO lpExecInfo);
public static class SHELLEXECUTEINFO extends Structure {
/*
* DWORD cbSize;
* ULONG fMask;
* HWND hwnd;
* LPCTSTR lpVerb;
* LPCTSTR lpFile;
* LPCTSTR lpParameters;
* LPCTSTR lpDirectory;
* int nShow;
* HINSTANCE hInstApp;
* LPVOID lpIDList;
* LPCTSTR lpClass;
* HKEY hkeyClass;
* DWORD dwHotKey;
* union {
* HANDLE hIcon;
* HANDLE hMonitor;
* } DUMMYUNIONNAME;
* HANDLE hProcess;
*/
public int cbSize = size();
public int fMask;
public HWND hwnd;
public WString lpVerb;
public WString lpFile;
public WString lpParameters;
public WString lpDirectory;
public int nShow;
public HINSTANCE hInstApp;
public Pointer lpIDList;
public WString lpClass;
public HKEY hKeyClass;
public int dwHotKey;
/*
* Actually:
* union {
* HANDLE hIcon;
* HANDLE hMonitor;
* } DUMMYUNIONNAME;
*/
public HANDLE hMonitor;
public HANDLE hProcess;
protected List getFieldOrder() {
return Arrays.asList(new String[] {
"cbSize",
"fMask",
"hwnd",
"lpVerb",
"lpFile",
"lpParameters",
"lpDirectory",
"nShow",
"hInstApp",
"lpIDList",
"lpClass",
"hKeyClass",
"dwHotKey",
"hMonitor",
"hProcess",
});
}
}
}

View File

@ -1,7 +1,5 @@
package net.i2p.router; package net.i2p.router;
import static net.i2p.update.UpdateType.*;
import java.io.*; import java.io.*;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
@ -18,10 +16,11 @@ import net.i2p.router.RouterLaunch;
import net.i2p.update.*; import net.i2p.update.*;
import net.i2p.update.UpdateManager; import net.i2p.update.UpdateManager;
import net.i2p.update.UpdatePostProcessor; import net.i2p.update.UpdatePostProcessor;
import net.i2p.update.UpdateType.*;
/** /**
* Launches a router from %PROGRAMFILES%/I2P using configuration data in * Launches a router from %WORKINGDIR%/I2P using configuration data in
* %LOCALAPPDATA%/I2P.. Uses Java 9 APIs. * %WORKINGDIR%/I2P.. Uses Java 9 APIs.
* *
* Sets the following properties: * Sets the following properties:
* i2p.dir.base - this points to the (read-only) resources inside the bundle * i2p.dir.base - this points to the (read-only) resources inside the bundle
@ -30,12 +29,13 @@ import net.i2p.update.UpdatePostProcessor;
* router.pid - the pid of the java process. * router.pid - the pid of the java process.
*/ */
public class WinLauncher extends CopyConfigDir { public class WinLauncher extends CopyConfigDir {
static WindowsUpdatePostProcessor wupp = null; WindowsUpdatePostProcessor wupp = null;
private static Router i2pRouter; private Router i2pRouter;
public static void main(String[] args) { public static void main(String[] args) {
setupLauncher(); var launcher = new WinLauncher();
initLogger(); launcher.setupLauncher();
launcher.initLogger();
int privateBrowsing = 0; int privateBrowsing = 0;
boolean usabilityMode = false; boolean usabilityMode = false;
boolean chromiumFirst = false; boolean chromiumFirst = false;
@ -47,18 +47,18 @@ public class WinLauncher extends CopyConfigDir {
for (String arg : args) { for (String arg : args) {
if (arg.equals("-private")) { if (arg.equals("-private")) {
privateBrowsing = 1; privateBrowsing = 1;
logger.info( launcher.logger.info(
"Private browsing is true, profile will be discarded at end of session."); "Private browsing is true, profile will be discarded at end of session.");
} else if (arg.equals("-chromium")) { } else if (arg.equals("-chromium")) {
chromiumFirst = true; chromiumFirst = true;
logger.info("Chromium will be selected before Firefox."); launcher.logger.info("Chromium will be selected before Firefox.");
} else if (arg.equals("-usability")) { } else if (arg.equals("-usability")) {
usabilityMode = true; usabilityMode = true;
logger.info( launcher.logger.info(
"Usability mode is true, using alternate extensions loadout."); "Usability mode is true, using alternate extensions loadout.");
} else if (arg.equals("-noproxycheck")) { } else if (arg.equals("-noproxycheck")) {
proxyTimeoutTime = 0; proxyTimeoutTime = 0;
logger.info("Proxy timeout time set to zero"); launcher.logger.info("Proxy timeout time set to zero");
} else { } else {
// make an effort to not let people launch into sites if the proxy // make an effort to not let people launch into sites if the proxy
// isn't quite ready yet, but also disable the proxy timeout if // isn't quite ready yet, but also disable the proxy timeout if
@ -77,7 +77,7 @@ public class WinLauncher extends CopyConfigDir {
proxyTimeoutTime = 0; proxyTimeoutTime = 0;
} else if (proxyTimeoutTime > 0) { } else if (proxyTimeoutTime > 0) {
newArgsList.add(arg); newArgsList.add(arg);
} else if (!isAvailable(4444)) { } else if (!launcher.isAvailable(4444)) {
newArgsList.add(arg); newArgsList.add(arg);
} }
} }
@ -85,8 +85,8 @@ public class WinLauncher extends CopyConfigDir {
} }
} }
File programs = programFile(); File programs = launcher.programFile();
File home = homeDir(); File home = launcher.homeDir();
System.setProperty( System.setProperty(
"i2p.dir.base", "i2p.dir.base",
@ -101,126 +101,66 @@ public class WinLauncher extends CopyConfigDir {
* to find the JVM and Runtime bundle. This broke Windows 11 installs. * to find the JVM and Runtime bundle. This broke Windows 11 installs.
*/ */
System.setProperty("user.dir", programs.getAbsolutePath()); System.setProperty("user.dir", programs.getAbsolutePath());
logger.info("\t" + System.getProperty("user.dir")); launcher.logger.info("\t" + System.getProperty("user.dir"));
logger.info("\t" + System.getProperty("i2p.dir.base")); launcher.logger.info("\t" + System.getProperty("i2p.dir.base"));
logger.info("\t" + System.getProperty("i2p.dir.config")); launcher.logger.info("\t" + System.getProperty("i2p.dir.config"));
logger.info("\t" + System.getProperty("router.pid")); launcher.logger.info("\t" + System.getProperty("router.pid"));
boolean continuerunning = promptServiceStartIfAvailable("i2p"); boolean continuerunning = launcher.promptServiceStartIfAvailable("i2p");
if (!continuerunning) { if (!continuerunning) {
logger.severe( launcher.logger.severe(
"Service startup failure, please start I2P service with services.msc"); "Service startup failure, please start I2P service with services.msc");
System.exit(2); System.exit(2);
} else {
fixServiceConfig();
} }
continuerunning = promptUserInstallStartIfAvailable(); continuerunning = launcher.promptUserInstallStartIfAvailable();
if (!continuerunning) { if (!continuerunning) {
logger.severe("User-install startup required."); launcher.logger.severe("User-install startup required.");
System.exit(2); System.exit(2);
} else {
fixServiceConfig();
} }
// This actually does most of what we use NSIS for if NSIS hasn't // This actually does most of what we use NSIS for if NSIS hasn't
// already done it, which essentially makes this whole thing portable. // already done it, which essentially makes this whole thing portable.
if (!copyConfigDir()) { if (!launcher.copyConfigDir()) {
logger.severe("Cannot copy the configuration directory"); launcher.logger.severe("Cannot copy the configuration directory");
System.exit(1); System.exit(1);
} }
if (launchBrowser(privateBrowsing, usabilityMode, chromiumFirst, if (launcher.launchBrowser(privateBrowsing, usabilityMode, chromiumFirst,
proxyTimeoutTime, newArgsList)) { proxyTimeoutTime, newArgsList)) {
System.exit(0); System.exit(0);
} }
i2pRouter = new Router(routerConfig(), System.getProperties()); launcher.i2pRouter =
if (!isInstalled("i2p")) { new Router(launcher.routerConfig(), System.getProperties());
if (i2pRouter.saveConfig("routerconsole.browser", null)) { if (!launcher.isInstalled("i2p")) {
logger.info("removed routerconsole.browser config"); if (launcher.i2pRouter.saveConfig("routerconsole.browser", null)) {
launcher.logger.info("removed routerconsole.browser config");
} }
if (i2pRouter.saveConfig("routerconsole.browser", if (launcher.i2pRouter.saveConfig("routerconsole.browser",
appImageExe() + " -noproxycheck")) { launcher.appImageExe() +
logger.info("updated routerconsole.browser config " + appImageExe()); " -noproxycheck")) {
launcher.logger.info("updated routerconsole.browser config " +
launcher.appImageExe());
} }
} }
logger.info("Router is configured"); launcher.logger.info("Router is configured");
Thread registrationThread = new Thread(REGISTER_UPP); Thread registrationThread = new Thread(launcher.REGISTER_UPP);
registrationThread.setName("UPP Registration"); registrationThread.setName("UPP Registration");
registrationThread.setDaemon(true); registrationThread.setDaemon(true);
registrationThread.start(); registrationThread.start();
setNotStarting(); launcher.setNotStarting();
i2pRouter.runRouter(); launcher.i2pRouter.runRouter();
} }
private static void fixServiceConfig() { private void setupLauncher() {
if (osName() != "windows")
return;
// If the user installed the Easy bundle before installing the
// IzPack installer, then they have a config file which contains the
// wrong update URL. Check for it, and change it back if necessary.
// closes #23
String routerconf = routerConfig();
if (routerconf != null) {
File routerconffile = new File(routerconf);
if (!routerconffile.exists()) {
return;
}
} else {
return;
}
if (isInstalled("i2p") || checkProgramFilesInstall()) {
i2pRouter = new Router(routerconf, System.getProperties());
String newsURL = i2pRouter.getConfigSetting("router.newsURL");
if (newsURL != null) {
if (newsURL.contains(
"http://dn3tvalnjz432qkqsvpfdqrwpqkw3ye4n4i2uyfr4jexvo3sp5ka.b32.i2p/news/win/beta/news.su3")) {
logger.info(
"checked router.newsURL config, containes win/beta in a service install, invalid update type");
if (i2pRouter.saveConfig("router.newsURL", ServiceUpdaterString())) {
logger.info("updated routerconsole.browser config " +
appImageExe());
}
}
}
String backupNewsURL = i2pRouter.getConfigSetting("router.backupNewsURL");
if (backupNewsURL != null) {
if (backupNewsURL.contains(
"http://tc73n4kivdroccekirco7rhgxdg5f3cjvbaapabupeyzrqwv5guq.b32.i2p/win/beta/news.su3")) {
logger.info(
"checked router.backupNewsURL config, containes win/beta in a service install, invalid update type");
if (i2pRouter.saveConfig("router.backupNewsURL",
ServiceBackupUpdaterString())) {
logger.info("updated routerconsole.browser config " +
appImageExe());
}
}
}
String updateURL = i2pRouter.getConfigSetting("router.updateURL");
if (updateURL != null) {
if (updateURL.contains(
"http://ekm3fu6fr5pxudhwjmdiea5dovc3jdi66hjgop4c7z7dfaw7spca.b32.i2p/i2pwinupdate.su3")) {
logger.info(
"checked router.updateURL config, containes easy-intall update in a service install, invalid update type");
if (i2pRouter.saveConfig("router.updateURL",
ServiceStaticUpdaterString())) {
logger.info("updated routerconsole.browser config " +
appImageExe());
}
}
}
}
}
private static void setupLauncher() {
File jrehome = javaHome(); File jrehome = javaHome();
logger.info("jre home is: " + jrehome.getAbsolutePath()); logger.info("jre home is: " + jrehome.getAbsolutePath());
File appimagehome = appImageHome(); File appimagehome = appImageHome();
logger.info("appimage home is: " + appimagehome.getAbsolutePath()); logger.info("appimage home is: " + appimagehome.getAbsolutePath());
} }
private static File programFile() { private File programFile() {
File programs = selectProgramFile(); File programs = selectProgramFile();
if (!programs.exists()) if (!programs.exists())
programs.mkdirs(); programs.mkdirs();
@ -233,7 +173,7 @@ public class WinLauncher extends CopyConfigDir {
return programs; return programs;
} }
private static File homeDir() { private File homeDir() {
File home = selectHome(); File home = selectHome();
if (!home.exists()) if (!home.exists())
home.mkdirs(); home.mkdirs();
@ -246,11 +186,9 @@ public class WinLauncher extends CopyConfigDir {
return home; return home;
} }
private static boolean launchBrowser(int privateBrowsing, private boolean launchBrowser(int privateBrowsing, boolean usabilityMode,
boolean usabilityMode, boolean chromiumFirst, int proxyTimeoutTime,
boolean chromiumFirst, ArrayList<String> newArgsList) {
int proxyTimeoutTime,
ArrayList<String> newArgsList) {
if (i2pIsRunning()) { if (i2pIsRunning()) {
logger.info("I2P is already running, launching an I2P browser"); logger.info("I2P is already running, launching an I2P browser");
I2PBrowser i2pBrowser = new I2PBrowser(); I2PBrowser i2pBrowser = new I2PBrowser();
@ -273,7 +211,7 @@ public class WinLauncher extends CopyConfigDir {
// see // see
// https://stackoverflow.com/questions/434718/sockets-discover-port-availability-using-java // https://stackoverflow.com/questions/434718/sockets-discover-port-availability-using-java
private static boolean isAvailable(int portNr) { private boolean isAvailable(int portNr) {
boolean portFree; boolean portFree;
try (var ignored = new ServerSocket(portNr)) { try (var ignored = new ServerSocket(portNr)) {
portFree = true; portFree = true;
@ -283,7 +221,7 @@ public class WinLauncher extends CopyConfigDir {
return portFree; return portFree;
} }
private static boolean i2pIsRunningCheck() { private boolean i2pIsRunningCheck() {
// check if there's something listening on port 7657(Router Console) // check if there's something listening on port 7657(Router Console)
if (!isAvailable(7657)) if (!isAvailable(7657))
return true; return true;
@ -295,7 +233,7 @@ public class WinLauncher extends CopyConfigDir {
return false; return false;
} }
private static void setNotStarting() { private void setNotStarting() {
logger.info("removing startup file, the application has started"); logger.info("removing startup file, the application has started");
File home = selectHome(); File home = selectHome();
File starting = new File(home, "starting"); File starting = new File(home, "starting");
@ -304,7 +242,7 @@ public class WinLauncher extends CopyConfigDir {
} }
} }
private static void setStarting() { private void setStarting() {
logger.info("creating startup file, router is starting up"); logger.info("creating startup file, router is starting up");
File home = selectHome(); File home = selectHome();
File starting = new File(home, "starting"); File starting = new File(home, "starting");
@ -323,7 +261,7 @@ public class WinLauncher extends CopyConfigDir {
}); });
} }
private static boolean checkStarting() { private boolean checkStarting() {
logger.info("checking startup file"); logger.info("checking startup file");
File home = selectHome(); File home = selectHome();
File starting = new File(home, "starting"); File starting = new File(home, "starting");
@ -338,7 +276,7 @@ public class WinLauncher extends CopyConfigDir {
// check for the existence of router.ping file, if it's less then 2 // check for the existence of router.ping file, if it's less then 2
// minutes old, exit // minutes old, exit
private static boolean checkPing() { private boolean checkPing() {
File home = selectHome(); File home = selectHome();
File ping = new File(home, "router.ping"); File ping = new File(home, "router.ping");
if (ping.exists()) { if (ping.exists()) {
@ -355,7 +293,7 @@ public class WinLauncher extends CopyConfigDir {
return false; return false;
} }
private static boolean i2pIsRunning() { private boolean i2pIsRunning() {
if (checkStarting()) if (checkStarting())
return true; return true;
if (checkPing()) if (checkPing())
@ -370,7 +308,7 @@ public class WinLauncher extends CopyConfigDir {
return false; return false;
} }
private static final Runnable REGISTER_UPP = () -> { private final Runnable REGISTER_UPP = () -> {
RouterContext ctx; RouterContext ctx;
while ((ctx = i2pRouter.getContext()) == null) { while ((ctx = i2pRouter.getContext()) == null) {
sleep(1000); sleep(1000);
@ -395,7 +333,7 @@ public class WinLauncher extends CopyConfigDir {
* *
* @param millis * @param millis
*/ */
private static void sleep(int millis) { private void sleep(int millis) {
try { try {
Thread.sleep(millis); Thread.sleep(millis);
} catch (InterruptedException bad) { } catch (InterruptedException bad) {

View File

@ -47,43 +47,34 @@ class WinUpdateProcess implements Runnable {
File workingDir = workDir(); File workingDir = workDir();
File logFile = new File(workingDir, "log-" + version + ".txt"); File logFile = new File(workingDir, "log-" + version + ".txt");
if (logFile.canWrite()) { // check if we can write to the log file. If we can, use the
// check if we can write to the log file. If we can, use the // ProcessBuilder to run the installer.
// ProcessBuilder to run the installer. ProcessBuilder pb = new ProcessBuilder(
ProcessBuilder pb = new ProcessBuilder( file.getAbsolutePath(), "/S", "/D=" + workingDir.getAbsolutePath());
file.getAbsolutePath(), "/S", "/D=" + workingDir.getAbsolutePath()); Map<String, String> env = pb.environment();
Map<String, String> env = pb.environment(); env.put("OLD_I2P_VERSION", version);
env.put("OLD_I2P_VERSION", version); env.remove("RESTART_I2P");
env.remove("RESTART_I2P");
int exitCode = ctx.router().scheduledGracefulExitCode(); int exitCode = ctx.router().scheduledGracefulExitCode();
if (exitCode == Router.EXIT_HARD_RESTART || if (exitCode == Router.EXIT_HARD_RESTART ||
exitCode == Router.EXIT_GRACEFUL_RESTART) exitCode == Router.EXIT_GRACEFUL_RESTART)
env.put("RESTART_I2P", "true"); env.put("RESTART_I2P", "true");
try { try {
Process p = pb.directory(workingDir) Process p = pb.directory(workingDir)
.redirectErrorStream(true) .redirectErrorStream(true)
.redirectOutput(logFile) .redirectOutput(logFile)
.start(); .start();
exitCode = p.waitFor(); exitCode = p.waitFor();
if (exitCode != 0) if (exitCode != 0)
_log.error("Update failed with exit code " + exitCode + " see " + _log.error("Update failed with exit code " + exitCode + " see " +
logFile.getAbsolutePath() + " for more details"); logFile.getAbsolutePath() + " for more details");
} catch (IOException ex) { } catch (IOException ex) {
_log.error( _log.error(
"Unable to run update program in background. Update will fail.", "Unable to run update program in background. Update will fail.", ex);
ex); } catch (InterruptedException ex) {
} catch (InterruptedException ex) { _log.error(
_log.error( "Unable to run update program in background. Update will fail.", ex);
"Unable to run update program in background. Update will fail.",
ex);
}
} else {
// If we cant write to the log file and we're on Windows, use the elevator
// to execute the installer instead of the ProcessBuilder.
Elevator.executeAsAdministrator(file.getAbsolutePath(),
" /S /D=" + workingDir.getAbsolutePath());
} }
} }

View File

@ -31,7 +31,7 @@ import javax.swing.JOptionPane;
public class WindowsServiceUtil { public class WindowsServiceUtil {
public WindowsServiceUtil() {} public WindowsServiceUtil() {}
public static String queryService(String serviceName) { public String queryService(String serviceName) {
String result = ""; String result = "";
String line; String line;
ProcessBuilder pb = new ProcessBuilder("sc", "query", serviceName); ProcessBuilder pb = new ProcessBuilder("sc", "query", serviceName);
@ -54,7 +54,7 @@ public class WindowsServiceUtil {
} }
return result; return result;
} }
public static String getStatePrefix(String qResult) { public String getStatePrefix(String qResult) {
String statePrefix = "STATE : "; String statePrefix = "STATE : ";
// get the first occurrence of "STATE", then find the // get the first occurrence of "STATE", then find the
// next occurrence of of ":" after that. Count the // next occurrence of of ":" after that. Count the
@ -70,7 +70,7 @@ public class WindowsServiceUtil {
} }
return statePrefix; return statePrefix;
} }
public static int getServiceStateInt(String serviceName) { public int getServiceStateInt(String serviceName) {
// String statePrefix = "STATE : "; // String statePrefix = "STATE : ";
String qResult = queryService(serviceName); String qResult = queryService(serviceName);
String statePrefix = getStatePrefix(qResult); String statePrefix = getStatePrefix(qResult);
@ -86,14 +86,14 @@ public class WindowsServiceUtil {
return -2; return -2;
} }
public static boolean isInstalled(String serviceName) { public boolean isInstalled(String serviceName) {
if (getServiceState(serviceName).equals("uninstalled")) { if (getServiceState(serviceName).equals("uninstalled")) {
return false; return false;
} }
return true; return true;
} }
public static boolean isStart(String serviceName) { public boolean isStart(String serviceName) {
if (getServiceState(serviceName).equals("started")) { if (getServiceState(serviceName).equals("started")) {
return true; return true;
} }
@ -106,7 +106,7 @@ public class WindowsServiceUtil {
return false; return false;
} }
public static boolean promptServiceStartIfAvailable(String serviceName) { public boolean promptServiceStartIfAvailable(String serviceName) {
if (osName() != "windows") { if (osName() != "windows") {
return true; return true;
} }
@ -152,17 +152,17 @@ public class WindowsServiceUtil {
return true; return true;
} }
public static String ServiceUpdaterString() { public String ServiceUpdaterString() {
return "http://tc73n4kivdroccekirco7rhgxdg5f3cjvbaapabupeyzrqwv5guq.b32.i2p/news.su3"; return "http://tc73n4kivdroccekirco7rhgxdg5f3cjvbaapabupeyzrqwv5guq.b32.i2p/news.su3";
} }
public static String ServiceBackupUpdaterString() { public String ServiceBackupUpdaterString() {
return "http://dn3tvalnjz432qkqsvpfdqrwpqkw3ye4n4i2uyfr4jexvo3sp5ka.b32.i2p/news.su3"; return "http://dn3tvalnjz432qkqsvpfdqrwpqkw3ye4n4i2uyfr4jexvo3sp5ka.b32.i2p/news.su3";
} }
public static String ServiceStaticUpdaterString() { public String ServiceStaticUpdaterString() {
return "http://echelon.i2p/i2p/i2pupdate.sud,http://stats.i2p/i2p/i2pupdate.sud"; return "http://echelon.i2p/i2p/i2pupdate.sud,http://stats.i2p/i2p/i2pupdate.sud";
} }
public static String getProgramFilesInstall() { public String getProgramFilesInstall() {
String programFiles = System.getenv("PROGRAMFILES"); String programFiles = System.getenv("PROGRAMFILES");
if (programFiles != null) { if (programFiles != null) {
File programFilesI2P = new File(programFiles, "i2p/i2p.exe"); File programFilesI2P = new File(programFiles, "i2p/i2p.exe");
@ -178,7 +178,7 @@ public class WindowsServiceUtil {
return null; return null;
} }
public static boolean checkProgramFilesInstall() { public boolean checkProgramFilesInstall() {
String programFiles = System.getenv("PROGRAMFILES"); String programFiles = System.getenv("PROGRAMFILES");
if (programFiles != null) { if (programFiles != null) {
File programFilesI2P = new File(programFiles, "i2p/i2p.exe"); File programFilesI2P = new File(programFiles, "i2p/i2p.exe");
@ -194,7 +194,7 @@ public class WindowsServiceUtil {
return false; return false;
} }
public static boolean promptUserInstallStartIfAvailable() { public boolean promptUserInstallStartIfAvailable() {
if (osName() != "windows") { if (osName() != "windows") {
return true; return true;
} }
@ -205,7 +205,7 @@ public class WindowsServiceUtil {
message += message +=
"However, it is not running yet. Please start it using the shortcut on the desktop.\n"; "However, it is not running yet. Please start it using the shortcut on the desktop.\n";
message += message +=
"If you click \"No\", the jpackage router will be launched instead.\n"; "If you click \"No\", the Easy-Install router will be launched instead.\n";
a = JOptionPane.showConfirmDialog(null, message, a = JOptionPane.showConfirmDialog(null, message,
"I2P Service detected not running", "I2P Service detected not running",
JOptionPane.YES_NO_OPTION); JOptionPane.YES_NO_OPTION);
@ -216,7 +216,7 @@ public class WindowsServiceUtil {
try { try {
String pfi = getProgramFilesInstall(); String pfi = getProgramFilesInstall();
if (pfi != null) if (pfi != null)
Runtime.getRuntime().exec(pfi); Runtime.getRuntime().exec(new String[] {pfi});
} catch (IOException e) { } catch (IOException e) {
return false; return false;
} }
@ -226,7 +226,7 @@ public class WindowsServiceUtil {
return true; return true;
} }
public static String getServiceState(String serviceName) { public String getServiceState(String serviceName) {
String stateString = "uninstalled"; String stateString = "uninstalled";
int state = getServiceStateInt(serviceName); int state = getServiceStateInt(serviceName);
switch (state) { switch (state) {
@ -269,11 +269,12 @@ public class WindowsServiceUtil {
return "linux"; return "linux";
} }
public static void main(String args[]) { public static void main(String args[]) {
WindowsServiceUtil wsu = new WindowsServiceUtil();
// when querying the I2P router service installed by the IzPack installer // when querying the I2P router service installed by the IzPack installer
// this is the correct call. // this is the correct call.
String state = getServiceState("i2p"); String state = wsu.getServiceState("i2p");
int stateInt = getServiceStateInt("i2p"); int stateInt = wsu.getServiceStateInt("i2p");
System.out.println("i2p state: " + state + " code: " + stateInt); System.out.println("i2p state: " + state + " code: " + stateInt);
promptServiceStartIfAvailable("i2p"); wsu.promptServiceStartIfAvailable("i2p");
} }
} }

View File

@ -44,20 +44,6 @@ public class WindowsUpdatePostProcessor implements UpdatePostProcessor {
_log.warn("Unsupported update type " + type); _log.warn("Unsupported update type " + type);
return; return;
} }
if (fileType != SU3File.TYPE_ZIP) {
this.positionedFile = moveUpdateInstaller(file);
this.version = version;
if (!hook.compareAndSet(false, true)) {
_log.info("shutdown hook was already set");
return;
}
_log.info("adding shutdown hook");
ctx.addFinalShutdownTask(
new ZipUpdateProcess(ctx, this::getVersion, this::getFile));
}
if (SystemVersion.isWindows()) { if (SystemVersion.isWindows()) {
if (fileType != SU3File.TYPE_EXE) { if (fileType != SU3File.TYPE_EXE) {
@ -77,6 +63,21 @@ public class WindowsUpdatePostProcessor implements UpdatePostProcessor {
ctx.addFinalShutdownTask( ctx.addFinalShutdownTask(
new WinUpdateProcess(ctx, this::getVersion, this::getFile)); new WinUpdateProcess(ctx, this::getVersion, this::getFile));
} else {
if (fileType == SU3File.TYPE_ZIP) {
this.positionedFile = moveUpdateInstaller(file);
this.version = version;
if (!hook.compareAndSet(false, true)) {
_log.info("shutdown hook was already set");
return;
}
_log.info("adding shutdown hook");
ctx.addFinalShutdownTask(
new ZipUpdateProcess(ctx, this::getVersion, this::getFile));
}
} }
} }

View File

@ -1,7 +1,7 @@
# This now requires v3 # This now requires v3
UniCode true UniCode true
!define APPNAME "I2PBrowser-Launcher" !define APPNAME "i2peasy"
!define COMPANYNAME "I2P" !define COMPANYNAME "I2P"
!define DESCRIPTION "This is a tool which contains an I2P router, a bundled JVM, and a tool for automatically configuring a browser to use with I2P." !define DESCRIPTION "This is a tool which contains an I2P router, a bundled JVM, and a tool for automatically configuring a browser to use with I2P."
!define I2P_MESSAGE "Please choose a directory." !define I2P_MESSAGE "Please choose a directory."
@ -18,11 +18,11 @@ UniCode true
SetOverwrite on SetOverwrite on
!define INSTDIR !define INSTDIR
!define I2PINSTEXE_USERMODE "$LOCALAPPDATA\i2peasy" !define I2PINSTEXE_USERMODE "$LOCALAPPDATA\${APPNAME}"
!define RAM_NEEDED_FOR_64BIT 0x80000000 !define RAM_NEEDED_FOR_64BIT 0x80000000
InstallDir "$PROGRAMFILES64\${COMPANYNAME}\${APPNAME}" InstallDir $LOCALAPPDATA\${APPNAME}
# rtf or txt file - remember if it is txt, it must be in the DOS text format (\r\n) # rtf or txt file - remember if it is txt, it must be in the DOS text format (\r\n)
LicenseData "licenses\LICENSE.txt" LicenseData "licenses\LICENSE.txt"
@ -132,11 +132,6 @@ Function .onInit
# Admin installs have been migrated to user-mode installs. # Admin installs have been migrated to user-mode installs.
# But I'm leaving it because I might need it again if I support service installs. # But I'm leaving it because I might need it again if I support service installs.
StrCpy $INSTDIR "${I2PINSTEXE_USERMODE}" StrCpy $INSTDIR "${I2PINSTEXE_USERMODE}"
UserInfo::GetAccountType
pop $0
${If} $0 != "admin"
StrCpy $INSTDIR "${I2PINSTEXE_USERMODE}"
${EndIf}
!insertmacro MUI_LANGDLL_DISPLAY !insertmacro MUI_LANGDLL_DISPLAY
#Call ShouldInstall64Bit #Call ShouldInstall64Bit
# look for user installs # look for user installs
@ -168,11 +163,6 @@ Function installerFunction
Sleep 500 Sleep 500
${LoopWhile} $0 <> 0 ${LoopWhile} $0 <> 0
${EndIf} ${EndIf}
# delete the jpackaged file for safety. Remove this IMMEDIATELY after the next release.
# early-adopters and daily-build users may have to manually delete config files if they
# uninstall.
# RELATED: line 246
Delete "$INSTDIR\jpackaged"
# set the installation directory as the destination for the following actions # set the installation directory as the destination for the following actions
createDirectory $INSTDIR createDirectory $INSTDIR

View File

@ -1,3 +1,3 @@
!define VERSIONMAJOR 2 !define VERSIONMAJOR 2
!define VERSIONMINOR 1 !define VERSIONMINOR 2
!define VERSIONBUILD 0 !define VERSIONBUILD 0