* Updater:

- Add new unsigned update option, triggered by
        last-modified date, using the new EepHead.
        Buttons still are not hidden after download complete.
      - Make the .sud updater use the temp dir when proxied
      - Several cleanups
This commit is contained in:
zzz
2009-08-09 14:28:20 +00:00
parent 3dd3bf829d
commit 3febcf6043
8 changed files with 320 additions and 41 deletions

View File

@ -16,6 +16,8 @@ public class ConfigUpdateHandler extends FormHandler {
private String _proxyPort;
private boolean _updateThroughProxy;
private String _trustedKeys;
private boolean _updateUnsigned;
private String _zipURL;
public static final String PROP_NEWS_URL = "router.newsURL";
// public static final String DEFAULT_NEWS_URL = "http://dev.i2p.net/cgi-bin/cvsweb.cgi/i2p/news.xml?rev=HEAD";
@ -30,7 +32,12 @@ public class ConfigUpdateHandler extends FormHandler {
public static final String PROP_PROXY_HOST = "router.updateProxyHost";
public static final String DEFAULT_PROXY_HOST = "127.0.0.1";
public static final String PROP_PROXY_PORT = "router.updateProxyPort";
public static final String DEFAULT_PROXY_PORT = "4444";
public static final int DEFAULT_PROXY_PORT_INT = 4444;
public static final String DEFAULT_PROXY_PORT = "" + DEFAULT_PROXY_PORT_INT;
/** default false */
public static final String PROP_UPDATE_UNSIGNED = "router.updateUnsigned";
/** no default */
public static final String PROP_ZIP_URL = "router.updateUnsignedURL";
public static final String PROP_UPDATE_URL = "router.updateURL";
public static final String DEFAULT_UPDATE_URL =
@ -46,7 +53,9 @@ public class ConfigUpdateHandler extends FormHandler {
if ("Check for update now".equals(_action)) {
NewsFetcher fetcher = NewsFetcher.getInstance(I2PAppContext.getGlobalContext());
fetcher.fetchNews();
if (fetcher.updateAvailable()) {
if (fetcher.shouldFetchUnsigned())
fetcher.fetchUnsigned();
if (fetcher.updateAvailable() || fetcher.unsignedUpdateAvailable()) {
if ( (_updatePolicy == null) || (!_updatePolicy.equals("notify")) )
addFormNotice("Update available, attempting to download now");
else
@ -79,11 +88,8 @@ public class ConfigUpdateHandler extends FormHandler {
}
}
if (_updateThroughProxy) {
_context.router().setConfigSetting(PROP_SHOULD_PROXY, Boolean.TRUE.toString());
} else {
_context.router().setConfigSetting(PROP_SHOULD_PROXY, Boolean.FALSE.toString());
}
_context.router().setConfigSetting(PROP_SHOULD_PROXY, "" + _updateThroughProxy);
_context.router().setConfigSetting(PROP_UPDATE_UNSIGNED, "" + _updateUnsigned);
String oldFreqStr = _context.router().getConfigSetting(PROP_REFRESH_FREQUENCY);
long oldFreq = -1;
@ -119,6 +125,14 @@ public class ConfigUpdateHandler extends FormHandler {
}
}
if ( (_zipURL != null) && (_zipURL.length() > 0) ) {
String oldURL = _context.router().getConfigSetting(PROP_ZIP_URL);
if ( (oldURL == null) || (!_zipURL.equals(oldURL)) ) {
_context.router().setConfigSetting(PROP_ZIP_URL, _zipURL);
addFormNotice("Updating unsigned update URL to " + _zipURL);
}
}
_context.router().saveConfig();
}
@ -132,4 +146,6 @@ public class ConfigUpdateHandler extends FormHandler {
public void setUpdateThroughProxy(String foo) { _updateThroughProxy = true; }
public void setProxyHost(String host) { _proxyHost = host; }
public void setProxyPort(String port) { _proxyPort = port; }
public void setUpdateUnsigned(String foo) { _updateUnsigned = true; }
public void setZipURL(String url) { _zipURL = url; }
}

View File

@ -44,10 +44,17 @@ public class ConfigUpdateHelper extends HelperBase {
if (Boolean.valueOf(proxy).booleanValue())
return "<input type=\"checkbox\" class=\"optbox\" value=\"true\" name=\"updateThroughProxy\" checked=\"true\" >";
else
return "<input type=\"checkbox\" class=\"optbox\" value=\"true\" name=\"updateThroughProxy\" >";
}
public String getUpdateUnsigned() {
String foo = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_UNSIGNED);
if (Boolean.valueOf(foo).booleanValue())
return "<input type=\"checkbox\" class=\"optbox\" value=\"true\" name=\"updateUnsigned\" checked=\"true\" >";
else
return "<input type=\"checkbox\" class=\"optbox\" value=\"true\" name=\"updateUnsigned\" >";
}
private static final long PERIODS[] = new long[] { 12*60*60*1000l, 24*60*60*1000l, 48*60*60*1000l, -1l };
public String getRefreshFrequencySelectBox() {
@ -105,11 +112,11 @@ public class ConfigUpdateHelper extends HelperBase {
return new TrustedUpdate(_context).getTrustedKeysString();
}
public String getZipURL() {
return _context.getProperty(ConfigUpdateHandler.PROP_ZIP_URL, "");
}
public String getNewsStatus() {
return NewsFetcher.getInstance(_context).status();
}
public String getUpdateVersion() {
return NewsFetcher.getInstance(_context).updateVersion();
}
}

View File

@ -3,7 +3,11 @@ package net.i2p.router.web;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import net.i2p.I2PAppContext;
import net.i2p.crypto.TrustedUpdate;
@ -12,6 +16,7 @@ import net.i2p.router.Router;
import net.i2p.router.RouterContext;
import net.i2p.router.RouterVersion;
import net.i2p.util.EepGet;
import net.i2p.util.EepHead;
import net.i2p.util.FileUtil;
import net.i2p.util.Log;
@ -23,9 +28,11 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener {
private I2PAppContext _context;
private Log _log;
private boolean _updateAvailable;
private boolean _unsignedUpdateAvailable;
private long _lastFetch;
private long _lastUpdated;
private String _updateVersion;
private String _unsignedUpdateVersion;
private String _lastModified;
private File _newsFile;
private File _tempFile;
@ -63,6 +70,8 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener {
public boolean updateAvailable() { return _updateAvailable; }
public String updateVersion() { return _updateVersion; }
public boolean unsignedUpdateAvailable() { return _unsignedUpdateAvailable; }
public String unsignedUpdateVersion() { return _unsignedUpdateVersion; }
public String status() {
long now = _context.clock().now();
@ -75,8 +84,11 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener {
try { Thread.sleep(_context.random().nextLong(5*60*1000)); } catch (InterruptedException ie) {}
while (true) {
if (!_updateAvailable) checkForUpdates();
if (shouldFetchNews())
if (shouldFetchNews()) {
fetchNews();
if (shouldFetchUnsigned())
fetchUnsignedHead();
}
try { Thread.sleep(10*60*1000); } catch (InterruptedException ie) {}
}
}
@ -91,9 +103,8 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener {
private boolean shouldFetchNews() {
updateLastFetched();
String freq = _context.getProperty(ConfigUpdateHandler.PROP_REFRESH_FREQUENCY);
if (freq == null)
freq = ConfigUpdateHandler.DEFAULT_REFRESH_FREQUENCY;
String freq = _context.getProperty(ConfigUpdateHandler.PROP_REFRESH_FREQUENCY,
ConfigUpdateHandler.DEFAULT_REFRESH_FREQUENCY);
try {
long ms = Long.parseLong(freq);
if (ms <= 0)
@ -116,13 +127,11 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener {
String newsURL = ConfigUpdateHelper.getNewsURL(_context);
boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue();
String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST);
String port = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT, ConfigUpdateHandler.DEFAULT_PROXY_PORT);
int proxyPort = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT, ConfigUpdateHandler.DEFAULT_PROXY_PORT_INT);
if (_tempFile.exists())
_tempFile.delete();
int proxyPort = -1;
try {
proxyPort = Integer.parseInt(port);
EepGet get = null;
if (shouldProxy)
get = new EepGet(_context, true, proxyHost, proxyPort, 2, _tempFile.getAbsolutePath(), newsURL, true, null, _lastModified);
@ -136,6 +145,103 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener {
}
}
public boolean shouldFetchUnsigned() {
String url = _context.getProperty(ConfigUpdateHandler.PROP_ZIP_URL);
return url != null && url.length() > 0 &&
Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_UPDATE_UNSIGNED)).booleanValue();
}
/**
* HEAD the update url, and if the last-mod time is newer than the last update we
* downloaded, as stored in the properties, then we download it using eepget.
*/
public void fetchUnsignedHead() {
String url = _context.getProperty(ConfigUpdateHandler.PROP_ZIP_URL);
if (url == null || url.length() <= 0)
return;
// assume always proxied for now
//boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue();
String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST);
int proxyPort = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT, ConfigUpdateHandler.DEFAULT_PROXY_PORT_INT);
try {
EepHead get = new EepHead(_context, proxyHost, proxyPort, 0, url);
if (get.fetch()) {
String lastmod = get.getLastModified();
if (lastmod != null) {
if (!(_context instanceof RouterContext)) return;
long modtime = parse822Date(lastmod);
if (modtime <= 0) return;
String lastUpdate = _context.getProperty(UpdateHandler.PROP_LAST_UPDATE_TIME);
if (lastUpdate == null) {
// we don't know what version you have, so stamp it with the current time,
// and we'll look for something newer next time around.
((RouterContext)_context).router().setConfigSetting(UpdateHandler.PROP_LAST_UPDATE_TIME,
"" + _context.clock().now());
((RouterContext)_context).router().saveConfig();
return;
}
long ms = 0;
try {
ms = Long.parseLong(lastUpdate);
} catch (NumberFormatException nfe) {}
if (ms <= 0) return;
if (modtime > ms) {
_unsignedUpdateAvailable = true;
// '07-Jul 21:09' with month name in the system locale
_unsignedUpdateVersion = (new SimpleDateFormat("dd-MMM HH:mm")).format(new Date(modtime));
if (shouldInstall())
fetchUnsigned();
}
}
}
} catch (Throwable t) {
_log.error("Error fetching the unsigned update", t);
}
}
public void fetchUnsigned() {
String url = _context.getProperty(ConfigUpdateHandler.PROP_ZIP_URL);
if (url == null || url.length() <= 0)
return;
UpdateHandler handler = new UnsignedUpdateHandler((RouterContext)_context, url,
_unsignedUpdateVersion);
handler.update();
}
/**
* http://jimyjoshi.com/blog/2007/08/rfc822dateparsinginjava.html
* Apparently public domain
* Probably don't need all of these...
*/
private static final SimpleDateFormat rfc822DateFormats[] = new SimpleDateFormat[] {
new SimpleDateFormat("EEE, d MMM yy HH:mm:ss z", Locale.US),
new SimpleDateFormat("EEE, d MMM yy HH:mm z", Locale.US),
new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z", Locale.US),
new SimpleDateFormat("EEE, d MMM yyyy HH:mm z", Locale.US),
new SimpleDateFormat("d MMM yy HH:mm z", Locale.US),
new SimpleDateFormat("d MMM yy HH:mm:ss z", Locale.US),
new SimpleDateFormat("d MMM yyyy HH:mm z", Locale.US),
new SimpleDateFormat("d MMM yyyy HH:mm:ss z", Locale.US)
};
/**
* new Date(String foo) is deprecated, so let's do this the hard way
*
* @param s non-null
* @return -1 on failure
*/
public static long parse822Date(String s) {
for (int i = 0; i < rfc822DateFormats.length; i++) {
try {
Date date = rfc822DateFormats[i].parse(s);
if (date != null)
return date.getTime();
} catch (ParseException pe) {}
}
return -1;
}
private static final String VERSION_STRING = "version=\"" + RouterVersion.VERSION + "\"";
private static final String VERSION_PREFIX = "version=\"";
private void checkForUpdates() {

View File

@ -525,4 +525,15 @@ public class SummaryHelper extends HelperBase {
return NewsFetcher.getInstance(_context).updateAvailable();
}
public boolean unsignedUpdateAvailable() {
return NewsFetcher.getInstance(_context).unsignedUpdateAvailable();
}
public String getUpdateVersion() {
return NewsFetcher.getInstance(_context).updateVersion();
}
public String getUnsignedUpdateVersion() {
return NewsFetcher.getInstance(_context).unsignedUpdateVersion();
}
}

View File

@ -0,0 +1,119 @@
package net.i2p.router.web;
import java.io.File;
import net.i2p.I2PAppContext;
import net.i2p.router.Router;
import net.i2p.router.RouterContext;
import net.i2p.util.EepGet;
import net.i2p.util.FileUtil;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
/**
* <p>Handles the request to update the router by firing off an
* {@link net.i2p.util.EepGet} call to download the latest unsigned zip file
* and displaying the status to anyone who asks.
* </p>
* <p>After the download completes the signed update file is copied to the
* router directory, and if configured the router is restarted to complete
* the update process.
* </p>
*/
public class UnsignedUpdateHandler extends UpdateHandler {
private String _zipURL;
private String _zipVersion;
public UnsignedUpdateHandler(RouterContext ctx, String zipURL, String version) {
super(ctx);
_zipURL = zipURL;
_zipVersion = version;
_updateFile = (new File(ctx.getTempDir(), "tmp" + ctx.random().nextInt() + Router.UPDATE_FILE)).getAbsolutePath();
}
@Override
public void update() {
// don't block waiting for the other one to finish
if ("true".equals(System.getProperty(PROP_UPDATE_IN_PROGRESS, "false"))) {
_log.error("Update already running");
return;
}
synchronized (UpdateHandler.class) {
if (_updateRunner == null) {
_updateRunner = new UnsignedUpdateRunner();
}
if (_updateRunner.isRunning()) {
return;
} else {
System.setProperty(PROP_UPDATE_IN_PROGRESS, "true");
I2PAppThread update = new I2PAppThread(_updateRunner, "Update");
update.start();
}
}
}
/**
* Eepget the .zip file to the temp dir, then copy it over
*/
public class UnsignedUpdateRunner extends UpdateRunner implements Runnable, EepGet.StatusListener {
public UnsignedUpdateRunner() {
super();
}
/** Get the file */
@Override
protected void update() {
_status = "<b>Updating</b>";
// always proxy for now
//boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue();
String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST);
int proxyPort = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT, ConfigUpdateHandler.DEFAULT_PROXY_PORT_INT);
try {
// 40 retries!!
_get = new EepGet(_context, proxyHost, proxyPort, 40, _updateFile, _zipURL, false);
_get.addStatusListener(UnsignedUpdateRunner.this);
_get.fetch();
} catch (Throwable t) {
_context.logManager().getLog(UpdateHandler.class).error("Error updating", t);
}
}
/** eepget listener callback Overrides */
@Override
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {
_status = "<b>Update downloaded</b>";
// we should really verify zipfile integrity here but there's no easy way to do it
String to = (new File(_context.getBaseDir(), Router.UPDATE_FILE)).getAbsolutePath();
boolean copied = FileUtil.copy(_updateFile, to, true);
if (copied) {
(new File(_updateFile)).delete();
String policy = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_POLICY);
this.done = true;
String lastmod = _get.getLastModified();
long modtime = 0;
if (lastmod != null)
modtime = NewsFetcher.parse822Date(lastmod);
if (modtime <= 0)
modtime = _context.clock().now();
_context.router().setConfigSetting(PROP_LAST_UPDATE_TIME, "" + modtime);
_context.router().saveConfig();
if ("install".equals(policy)) {
_log.log(Log.CRIT, "Update was downloaded, restarting to install it");
_status = "<b>Update downloaded</b><br />Restarting";
restart();
} else {
_log.log(Log.CRIT, "Update was downloaded, will be installed at next restart");
_status = "<b>Update downloaded</b><br />";
if (System.getProperty("wrapper.version") != null)
_status += "Click Restart to install";
else
_status += "Click Shutdown and restart to install";
_status += " Version " + _zipVersion;
}
} else {
_log.log(Log.CRIT, "Failed copy to " + to);
_status = "<b>Failed copy to " + to + "</b>";
}
}
}
}

View File

@ -30,11 +30,12 @@ public class UpdateHandler {
protected static UpdateRunner _updateRunner;
protected RouterContext _context;
protected Log _log;
protected DecimalFormat _pct = new DecimalFormat("00.0%");
protected String _updateFile;
private String _action;
protected static final String SIGNED_UPDATE_FILE = "i2pupdate.sud";
protected static final String PROP_UPDATE_IN_PROGRESS = "net.i2p.router.web.UpdateHandler.updateInProgress";
protected static final String PROP_LAST_UPDATE_TIME = "router.updateLastDownloaded";
public UpdateHandler() {
this(ContextHelper.getContext(null));
@ -48,7 +49,7 @@ public class UpdateHandler {
/**
* Configure this bean to query a particular router context
*
* @param contextId begging few characters of the routerHash, or null to pick
* @param contextId beginning few characters of the routerHash, or null to pick
* the first one we come across.
*/
public void setContextId(String contextId) {
@ -60,18 +61,25 @@ public class UpdateHandler {
}
}
public void setUpdateAction(String val) { _action = val; }
public void setUpdateNonce(String nonce) {
if (nonce == null) return;
if (nonce.equals(System.getProperty("net.i2p.router.web.UpdateHandler.nonce")) ||
nonce.equals(System.getProperty("net.i2p.router.web.UpdateHandler.noncePrev"))) {
update();
if (_action != null && _action.contains("Unsigned")) {
// Not us, have NewsFetcher instantiate the correct class.
NewsFetcher fetcher = NewsFetcher.getInstance(_context);
fetcher.fetchUnsigned();
} else {
update();
}
}
}
public void update() {
// don't block waiting for the other one to finish
if ("true".equals(System.getProperty(PROP_UPDATE_IN_PROGRESS, "false"))) {
if ("true".equals(System.getProperty(PROP_UPDATE_IN_PROGRESS))) {
_log.error("Update already running");
return;
}
@ -106,6 +114,9 @@ public class UpdateHandler {
protected boolean _isRunning;
protected boolean done;
protected String _status;
protected EepGet _get;
private final DecimalFormat _pct = new DecimalFormat("0.0%");
public UpdateRunner() {
_isRunning = false;
this.done = false;
@ -129,22 +140,15 @@ public class UpdateHandler {
_log.debug("Selected update URL: " + updateURL);
boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue();
String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST);
String port = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT, ConfigUpdateHandler.DEFAULT_PROXY_PORT);
int proxyPort = -1;
int proxyPort = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT, ConfigUpdateHandler.DEFAULT_PROXY_PORT_INT);
try {
proxyPort = Integer.parseInt(port);
} catch (NumberFormatException nfe) {
return;
}
try {
EepGet get = null;
if (shouldProxy)
// 40 retries!!
get = new EepGet(_context, proxyHost, proxyPort, 40, SIGNED_UPDATE_FILE, updateURL, false);
_get = new EepGet(_context, proxyHost, proxyPort, 40, _updateFile, updateURL, false);
else
get = new EepGet(_context, 1, _updateFile, updateURL, false);
get.addStatusListener(UpdateRunner.this);
get.fetch();
_get = new EepGet(_context, 1, _updateFile, updateURL, false);
_get.addStatusListener(UpdateRunner.this);
_get.fetch();
} catch (Throwable t) {
_context.logManager().getLog(UpdateHandler.class).error("Error updating", t);
}
@ -177,6 +181,15 @@ public class UpdateHandler {
if (err == null) {
String policy = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_POLICY);
this.done = true;
// So unsigned update handler doesn't overwrite unless newer.
String lastmod = _get.getLastModified();
long modtime = 0;
if (lastmod != null)
modtime = NewsFetcher.parse822Date(lastmod);
if (modtime <= 0)
modtime = _context.clock().now();
_context.router().setConfigSetting(PROP_LAST_UPDATE_TIME, "" + modtime);
_context.router().saveConfig();
if ("install".equals(policy)) {
_log.log(Log.CRIT, "Update was VERIFIED, restarting to install it");
_status = "<b>Update verified</b><br />Restarting";
@ -208,7 +221,7 @@ public class UpdateHandler {
public void attempting(String url) {}
}
private void restart() {
protected void restart() {
_context.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
_context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
}

View File

@ -63,6 +63,12 @@
<tr>
<td class= "mediumtags" align="right"><b>Trusted keys:</b>
<td><textarea name="trustedKeys" wrap="off"><jsp:getProperty name="updatehelper" property="trustedKeys" /></textarea>
<tr>
<td class= "mediumtags" align="right"><b>Update with unsigned development builds?</b>
<td><jsp:getProperty name="updatehelper" property="updateUnsigned" />
<tr>
<td class= "mediumtags" align="right"><b>Unsigned Build URL:</b></td>
<td><input type="text" size="60" name="zipURL" value="<jsp:getProperty name="updatehelper" property="zipURL" />"></td>
<tr>
<td>
<td><div class="formaction">

View File

@ -12,9 +12,6 @@
<jsp:useBean class="net.i2p.router.web.UpdateHandler" id="update" scope="request" />
<jsp:setProperty name="update" property="*" />
<jsp:setProperty name="update" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
<jsp:useBean class="net.i2p.router.web.ConfigUpdateHelper" id="uhelper" scope="request" />
<jsp:setProperty name="uhelper" property="*" />
<jsp:setProperty name="uhelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
<center><a href="index.jsp" target="_top"><img src="/themes/console/images/i2plogo.png" alt="I2P Router Console" title="I2P Router Console"/></a></center><hr />
<center>
<% java.io.File lpath = new java.io.File(net.i2p.I2PAppContext.getGlobalContext().getBaseDir(), "docs/toolbar.html");
@ -50,7 +47,7 @@
<b>Uptime:</b> <jsp:getProperty name="helper" property="uptime" /><br />
<b>Reachability:</b> <a href="config.jsp#help" target="_top"><jsp:getProperty name="helper" property="reachability" /></a>
<%
if (helper.updateAvailable()) {
if (helper.updateAvailable() || helper.unsignedUpdateAvailable()) {
// display all the time so we display the final failure message
out.print("<br />" + update.getStatus());
if ("true".equals(System.getProperty("net.i2p.router.web.UpdateHandler.updateInProgress"))) {
@ -65,7 +62,11 @@
String uri = request.getRequestURI();
out.print("<p><center><form action=\"" + uri + "\" method=\"GET\">\n");
out.print("<input type=\"hidden\" name=\"updateNonce\" value=\"" + nonce + "\" />\n");
out.print("<input type=\"submit\" value=\"Download " + uhelper.getUpdateVersion() + " Update\" /></form></center></p>\n");
if (helper.updateAvailable())
out.print("<button type=\"submit\" name=\"updateAction\" value=\"signed\" >Download " + helper.getUpdateVersion() + " Update</button>\n");
if (helper.unsignedUpdateAvailable())
out.print("<button type=\"submit\" name=\"updateAction\" value=\"Unsigned\" >Download Unsigned<br />" + helper.getUnsignedUpdateVersion() + " Update</button>\n");
out.print("</form></center></p>\n");
}
}
%>