Files
i2p.i2p/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHelper.java

316 lines
15 KiB
Java
Raw Normal View History

package net.i2p.router.web;
2010-02-08 16:15:23 +00:00
import java.text.SimpleDateFormat;
import java.util.ArrayList;
2010-02-08 16:15:23 +00:00
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
import net.i2p.app.ClientApp;
import net.i2p.app.ClientAppState;
import net.i2p.data.DataHelper;
import net.i2p.router.client.ClientManagerFacadeImpl;
import net.i2p.router.startup.ClientAppConfig;
import net.i2p.router.startup.LoadClientAppsJob;
import net.i2p.util.Addresses;
public class ConfigClientsHelper extends HelperBase {
2010-01-06 21:24:08 +00:00
private String _edit;
/** from ClientListenerRunner */
public static final String BIND_ALL_INTERFACES = "i2cp.tcp.bindAllInterfaces";
/** from ClientManager */
public static final String PROP_DISABLE_EXTERNAL = "i2cp.disableInterface";
public static final String PROP_ENABLE_SSL = "i2cp.SSL";
/** from ClientMessageEventListener */
public static final String PROP_AUTH = "i2cp.auth";
public ConfigClientsHelper() {}
/** @since 0.8.3 */
public String getPort() {
return _context.getProperty(ClientManagerFacadeImpl.PROP_CLIENT_PORT,
Integer.toString(ClientManagerFacadeImpl.DEFAULT_PORT));
}
/** @since 0.8.3 */
public String i2cpModeChecked(int mode) {
boolean disabled = _context.getBooleanProperty(PROP_DISABLE_EXTERNAL);
boolean ssl = _context.getBooleanProperty(PROP_ENABLE_SSL);
if ((mode == 0 && disabled) ||
(mode == 1 && (!disabled) && (!ssl)) ||
(mode == 2 && (!disabled) && ssl))
2012-03-02 22:32:45 +00:00
return "checked=\"checked\"";
return "";
}
/** @since 0.8.3 */
public String getAuth() {
boolean enabled = _context.getBooleanProperty(PROP_AUTH);
if (enabled)
2012-03-02 22:32:45 +00:00
return "checked=\"checked\"";
return "";
}
/** @since 0.8.3 */
public String[] intfcAddresses() {
ArrayList<String> al = new ArrayList<String>(Addresses.getAllAddresses());
2010-12-26 15:07:59 +00:00
return al.toArray(new String[al.size()]);
}
/** @since 0.8.3 */
public boolean isIFSelected(String addr) {
boolean bindAll = _context.getBooleanProperty(BIND_ALL_INTERFACES);
if (bindAll && addr.equals("0.0.0.0") || addr.equals("::"))
return true;
String host = _context.getProperty(ClientManagerFacadeImpl.PROP_CLIENT_HOST,
ClientManagerFacadeImpl.DEFAULT_HOST);
return (host.equals(addr));
}
2010-01-06 21:24:08 +00:00
public void setEdit(String edit) {
if (edit == null)
return;
String xStart = _("Edit");
if (edit.startsWith(xStart + "<span class=hide> ") &&
edit.endsWith("</span>")) {
// IE sucks
_edit = edit.substring(xStart.length() + 18, edit.length() - 7);
} else if (edit.startsWith("Edit ")) {
_edit = edit.substring(5);
} else if (edit.startsWith(xStart + ' ')) {
_edit = edit.substring(xStart.length() + 1);
} else if ((_("Add Client")).equals(edit)) {
_edit = "new";
}
}
2012-12-07 14:21:30 +00:00
/** clients */
public String getForm1() {
StringBuilder buf = new StringBuilder(1024);
buf.append("<table>\n");
2010-02-08 20:57:30 +00:00
buf.append("<tr><th align=\"right\">" + _("Client") + "</th><th>" + _("Run at Startup?") + "</th><th>" + _("Control") + "</th><th align=\"left\">" + _("Class and arguments") + "</th></tr>\n");
2010-01-06 21:24:08 +00:00
List<ClientAppConfig> clients = ClientAppConfig.getClientApps(_context);
for (int cur = 0; cur < clients.size(); cur++) {
2010-01-06 21:24:08 +00:00
ClientAppConfig ca = clients.get(cur);
boolean isConsole = ca.className.equals("net.i2p.router.web.RouterConsoleRunner");
boolean showStart;
boolean showStop;
if (isConsole) {
showStart = false;
showStop = false;
} else {
ClientApp clientApp = _context.clientAppManager().getClientApp(ca.className, LoadClientAppsJob.parseArgs(ca.args));
showStart = clientApp == null;
showStop = clientApp != null && clientApp.getState() == ClientAppState.RUNNING;
}
renderForm(buf, ""+cur, ca.clientName,
// urlify, enabled
false, !ca.disabled,
// read only
2011-01-16 15:30:04 +00:00
// dangerous, but allow editing the console args too
//"webConsole".equals(ca.clientName) || "Web console".equals(ca.clientName),
false,
// description, edit
ca.className + ((ca.args != null) ? " " + ca.args : ""), (""+cur).equals(_edit),
// show edit button, show update button
// Don't allow edit if it's running, or else we would lose the "handle" to the ClientApp to stop it.
!showStop, false,
// show stop button
showStop,
// show delete button, show start button
true, showStart);
}
2010-01-06 21:24:08 +00:00
if ("new".equals(_edit))
renderForm(buf, "" + clients.size(), "", false, false, false, "", true, false, false, false, false, false);
buf.append("</table>\n");
return buf.toString();
}
2012-12-07 14:21:30 +00:00
/** webapps */
public String getForm2() {
StringBuilder buf = new StringBuilder(1024);
buf.append("<table>\n");
2010-02-08 20:57:30 +00:00
buf.append("<tr><th align=\"right\">" + _("WebApp") + "</th><th>" + _("Run at Startup?") + "</th><th>" + _("Control") + "</th><th align=\"left\">" + _("Description") + "</th></tr>\n");
Properties props = RouterConsoleRunner.webAppProperties(_context);
2010-01-06 21:24:08 +00:00
Set<String> keys = new TreeSet(props.keySet());
2013-11-28 11:56:54 +00:00
for (String name : keys) {
if (name.startsWith(RouterConsoleRunner.PREFIX) && name.endsWith(RouterConsoleRunner.ENABLED)) {
String app = name.substring(RouterConsoleRunner.PREFIX.length(), name.lastIndexOf(RouterConsoleRunner.ENABLED));
String val = props.getProperty(name);
boolean isRunning = WebAppStarter.isWebAppRunning(app);
2010-01-06 21:24:08 +00:00
renderForm(buf, app, app, !"addressbook".equals(app),
"true".equals(val), RouterConsoleRunner.ROUTERCONSOLE.equals(app), app + ".war",
false, false, false, isRunning, false, !isRunning);
}
}
buf.append("</table>\n");
return buf.toString();
}
public boolean showPlugins() {
return PluginStarter.pluginsEnabled(_context);
}
2012-12-07 14:21:30 +00:00
/** plugins */
2010-02-07 13:32:49 +00:00
public String getForm3() {
StringBuilder buf = new StringBuilder(1024);
buf.append("<table>\n");
2010-02-08 20:57:30 +00:00
buf.append("<tr><th align=\"right\">" + _("Plugin") + "</th><th>" + _("Run at Startup?") + "</th><th>" + _("Control") + "</th><th align=\"left\">" + _("Description") + "</th></tr>\n");
2010-02-07 13:32:49 +00:00
Properties props = PluginStarter.pluginProperties();
Set<String> keys = new TreeSet(props.keySet());
2013-11-28 11:56:54 +00:00
for (String name : keys) {
2010-02-07 13:32:49 +00:00
if (name.startsWith(PluginStarter.PREFIX) && name.endsWith(PluginStarter.ENABLED)) {
String app = name.substring(PluginStarter.PREFIX.length(), name.lastIndexOf(PluginStarter.ENABLED));
String val = props.getProperty(name);
2010-02-08 16:15:23 +00:00
Properties appProps = PluginStarter.pluginProperties(_context, app);
if (appProps.isEmpty())
continue;
2010-02-08 16:15:23 +00:00
StringBuilder desc = new StringBuilder(256);
desc.append("<table border=\"0\">")
.append("<tr><td><b>").append(_("Version")).append("</b></td><td>").append(stripHTML(appProps, "version"))
2010-02-08 16:15:23 +00:00
.append("<tr><td><b>")
.append(_("Signed by")).append("</b></td><td>");
String s = stripHTML(appProps, "signer");
if (s != null) {
if (s.indexOf("@") > 0)
desc.append("<a href=\"mailto:").append(s).append("\">").append(s).append("</a>");
else
desc.append(s);
}
2010-02-08 23:28:09 +00:00
s = stripHTML(appProps, "date");
2010-02-08 16:15:23 +00:00
if (s != null) {
long ms = 0;
try {
ms = Long.parseLong(s);
} catch (NumberFormatException nfe) {}
if (ms > 0) {
String date = (new SimpleDateFormat("yyyy-MM-dd HH:mm")).format(new Date(ms));
desc.append("<tr><td><b>")
.append(_("Date")).append("</b></td><td>").append(date);
2010-02-08 16:15:23 +00:00
}
}
2010-02-08 23:28:09 +00:00
s = stripHTML(appProps, "author");
2010-02-08 16:15:23 +00:00
if (s != null) {
desc.append("<tr><td><b>")
.append(_("Author")).append("</b></td><td>");
2010-02-08 23:28:09 +00:00
if (s.indexOf("@") > 0)
desc.append("<a href=\"mailto:").append(s).append("\">").append(s).append("</a>");
else
desc.append(s);
2010-02-08 16:15:23 +00:00
}
2010-02-08 23:28:09 +00:00
s = stripHTML(appProps, "description_" + Messages.getLanguage(_context));
2010-02-08 16:15:23 +00:00
if (s == null)
2010-02-08 23:28:09 +00:00
s = stripHTML(appProps, "description");
2010-02-08 16:15:23 +00:00
if (s != null) {
desc.append("<tr><td><b>")
.append(_("Description")).append("</b></td><td>").append(s);
2010-02-08 16:15:23 +00:00
}
2010-02-08 23:28:09 +00:00
s = stripHTML(appProps, "license");
2010-02-08 16:15:23 +00:00
if (s != null) {
desc.append("<tr><td><b>")
.append(_("License")).append("</b></td><td>").append(s);
2010-02-08 16:15:23 +00:00
}
2010-02-08 23:28:09 +00:00
s = stripHTML(appProps, "websiteURL");
2010-02-08 16:15:23 +00:00
if (s != null) {
desc.append("<tr><td>")
.append("<a href=\"").append(s).append("\">").append(_("Website")).append("</a><td>&nbsp;");
}
2010-02-08 23:28:09 +00:00
String updateURL = stripHTML(appProps, "updateURL");
2010-02-08 19:04:46 +00:00
if (updateURL != null) {
2010-02-08 16:15:23 +00:00
desc.append("<tr><td>")
2010-02-08 19:04:46 +00:00
.append("<a href=\"").append(updateURL).append("\">").append(_("Update link")).append("</a><td>&nbsp;");
2010-02-08 16:15:23 +00:00
}
desc.append("</table>");
boolean enableStop = !Boolean.parseBoolean(appProps.getProperty("disableStop"));
enableStop &= PluginStarter.isPluginRunning(app, _context);
boolean enableStart = !PluginStarter.isPluginRunning(app, _context);
2010-02-08 16:15:23 +00:00
renderForm(buf, app, app, false,
2010-02-08 20:57:30 +00:00
"true".equals(val), false, desc.toString(), false, false,
updateURL != null, enableStop, true, enableStart);
2010-02-07 13:32:49 +00:00
}
}
buf.append("</table>\n");
return buf.toString();
}
2012-12-07 14:21:30 +00:00
/**
* Misnamed, renders a single line in a table for a single client/webapp/plugin.
*
* ro trumps edit and showEditButton
*/
2010-01-06 21:24:08 +00:00
private void renderForm(StringBuilder buf, String index, String name, boolean urlify,
2010-02-08 19:04:46 +00:00
boolean enabled, boolean ro, String desc, boolean edit,
boolean showEditButton, boolean showUpdateButton, boolean showStopButton,
boolean showDeleteButton, boolean showStartButton) {
String escapeddesc = DataHelper.escapeHTML(desc);
buf.append("<tr><td class=\"mediumtags\" align=\"right\" width=\"25%\">");
if (urlify && enabled) {
String link = "/";
if (! RouterConsoleRunner.ROUTERCONSOLE.equals(name))
link += name + "/";
buf.append("<a href=\"").append(link).append("\">").append(_(name)).append("</a>");
2010-01-06 21:24:08 +00:00
} else if (edit && !ro) {
buf.append("<input type=\"text\" name=\"name").append(index).append("\" value=\"");
if (name.length() > 0)
buf.append(_(name));
2010-01-06 21:24:08 +00:00
buf.append("\" >");
} else {
if (name.length() > 0)
buf.append(_(name));
}
buf.append("</td><td align=\"center\" width=\"10%\"><input type=\"checkbox\" class=\"optbox\" name=\"").append(index).append(".enabled\" value=\"true\" ");
if (enabled) {
2012-03-02 22:32:45 +00:00
buf.append("checked=\"checked\" ");
if (ro)
2012-03-02 22:32:45 +00:00
buf.append("disabled=\"disabled\" ");
}
buf.append("></td><td align=\"center\" width=\"15%\">");
// The icons were way too much, so there's an X in each button class,
// remove if you wnat to put them back
if (showStartButton && (!ro) && !edit) {
buf.append("<button type=\"submit\" class=\"Xaccept\" name=\"action\" value=\"Start ").append(index).append("\" >" + _("Start") + "<span class=hide> ").append(index).append("</span></button>");
}
2010-02-08 20:57:30 +00:00
if (showStopButton && (!edit))
buf.append("<button type=\"submit\" class=\"Xstop\" name=\"action\" value=\"Stop ").append(index).append("\" >" + _("Stop") + "<span class=hide> ").append(index).append("</span></button>");
if (showEditButton && (!edit) && !ro)
buf.append("<button type=\"submit\" class=\"Xadd\" name=\"edit\" value=\"Edit ").append(index).append("\" >" + _("Edit") + "<span class=hide> ").append(index).append("</span></button>");
2010-02-08 19:04:46 +00:00
if (showUpdateButton && (!edit) && !ro) {
buf.append("<button type=\"submit\" class=\"Xcheck\" name=\"action\" value=\"Check ").append(index).append("\" >" + _("Check for updates") + "<span class=hide> ").append(index).append("</span></button>");
buf.append("<button type=\"submit\" class=\"Xdownload\" name=\"action\" value=\"Update ").append(index).append("\" >" + _("Update") + "<span class=hide> ").append(index).append("</span></button>");
2010-01-06 21:24:08 +00:00
}
if (showDeleteButton && (!edit) && !ro) {
buf.append("<button type=\"submit\" class=\"Xdelete\" name=\"action\" value=\"Delete ").append(index)
.append("\" onclick=\"if (!confirm('")
.append(_("Are you sure you want to delete {0}?", _(name)))
.append("')) { return false; }\">")
.append(_("Delete")).append("<span class=hide> ").append(index).append("</span></button>");
}
2010-01-06 21:24:08 +00:00
buf.append("</td><td align=\"left\" width=\"50%\">");
if (edit && !ro) {
2013-09-20 18:42:51 +00:00
buf.append("<input type=\"text\" size=\"80\" spellcheck=\"false\" name=\"desc").append(index).append("\" value=\"");
buf.append(escapeddesc);
2010-01-06 21:24:08 +00:00
buf.append("\" >");
} else {
buf.append(desc);
2010-01-06 21:24:08 +00:00
}
buf.append("</td></tr>\n");
}
2010-02-08 23:28:09 +00:00
/**
* Like in DataHelper but doesn't convert null to ""
* There's a lot worse things a plugin could do but...
*/
Big refactor of the router console update subsystem, in preparation for implementing out-of-console updaters like i2psnark. - Add new update interfaces in net.i2p.update - All update implementations moved to routerconsole update/ - Implement an UpdateManager that registers with the RouterContext - UpdateManager handles multiple types of things to update (router, plugins, news, ...) and methods of updating (HTTP, ...) - UpdateManager maintains list of installed, downloaded, and available versions of everything - Define Updaters that can check for a new version and/or download an item - Individual Updaters register with the UpdateManager obtained from I2PAppContext, identifying the type of update item and update method they can handle. - Updaters need only core libs, no router.jar or routerconsole access required. - All checks and updates are initiated via the UpdateManager. - All status on checks and updates in-progress or completed are obtained from the UpdateManager. No more use of System properties to broadcast update state. - All update and checker tasks are intantiated on demand and threaded; no more static references left over. - Split out the Runners and Checkers from the Handlers and make the inheritance more sane. - No more permanent NewsFetcher thread; run on the SimpleScheduler queue and thread a checker task only to fetch the news. - No more static NewsFetcher instance in routerconsole. All helper methods that are still required are moved to NewsHelper. The UpdateManager implements the policy for when to check and download. All requests go through the UpdateManager. For each update type, there's several parts: - The xxxUpdateHandler implements the Updater - The xxxUpdateChecker implements the UpdateTask for checking - The xxxUpdateRunner implements the UpdateTask for downloading New and moved classes: web/ update/ ---- ------- new ConsoleUpdateManager.java new PluginUpdateChecker.java from PluginUpdateChecker PluginUpdateChecker -> PluginUpdateHandler.java PluginUpdateHandler.java -> PluginUpdateRunner new UnsignedUpdateHandler.java UnsignedUpdateHandler -> UnsignedUpdateRunner.java new UnsignedUpdateChecker from NewsFetcher UpdateHandler.java remains new UpdateHandler.java new UpdateRunner.java from UpdateHandler move NewsHandler from NewsFetcher new NewsFetcher new NewsTimerTask new DummyHandler Initial checkin. Unfinished, untested, unpolished.
2012-06-18 22:09:45 +00:00
public static String stripHTML(Properties props, String key) {
2010-02-08 23:28:09 +00:00
String orig = props.getProperty(key);
if (orig == null) return null;
String t1 = orig.replace('<', ' ');
String rv = t1.replace('>', ' ');
return rv;
}
}