use of org.klomp.snark.MetaInfo in project i2p.i2p by i2p.
the class I2PSnarkServlet method getListHTML.
/**
* Modded heavily from the Jetty version in Resource.java,
* pass Resource as 1st param
* All the xxxResource constructors are package local so we can't extend them.
*
* <pre>
* // ========================================================================
* // $Id: Resource.java,v 1.32 2009/05/16 01:53:36 gregwilkins Exp $
* // Copyright 1996-2004 Mort Bay Consulting Pty. Ltd.
* // ------------------------------------------------------------------------
* // Licensed under the Apache License, Version 2.0 (the "License");
* // you may not use this file except in compliance with the License.
* // You may obtain a copy of the License at
* // http://www.apache.org/licenses/LICENSE-2.0
* // Unless required by applicable law or agreed to in writing, software
* // distributed under the License is distributed on an "AS IS" BASIS,
* // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* // See the License for the specific language governing permissions and
* // limitations under the License.
* // ========================================================================
* </pre>
*
* Get the resource list as a HTML directory listing.
* @param xxxr The Resource unused
* @param base The encoded base URL
* @param parent True if the parent directory should be included
* @param postParams map of POST parameters or null if not a POST
* @param sortParam may be null
* @return String of HTML or null if postParams != null
* @since 0.7.14
*/
private String getListHTML(File xxxr, String base, boolean parent, Map<String, String[]> postParams, String sortParam) throws IOException {
String decodedBase = decodePath(base);
String title = decodedBase;
String cpath = _contextPath + '/';
if (title.startsWith(cpath))
title = title.substring(cpath.length());
// Get the snark associated with this directory
String torrentName;
String pathInTorrent;
int slash = title.indexOf('/');
if (slash > 0) {
torrentName = title.substring(0, slash);
pathInTorrent = title.substring(slash);
} else {
torrentName = title;
pathInTorrent = "/";
}
Snark snark = _manager.getTorrentByBaseName(torrentName);
if (snark != null && postParams != null) {
// caller must P-R-G
String[] val = postParams.get("nonce");
if (val != null) {
String nonce = val[0];
if (String.valueOf(_nonce).equals(nonce)) {
if (postParams.get("savepri") != null) {
savePriorities(snark, postParams);
} else if (postParams.get("addComment") != null) {
saveComments(snark, postParams);
} else if (postParams.get("deleteComments") != null) {
deleteComments(snark, postParams);
} else if (postParams.get("setCommentsEnabled") != null) {
saveCommentsSetting(snark, postParams);
} else if (postParams.get("stop") != null) {
_manager.stopTorrent(snark, false);
} else if (postParams.get("start") != null) {
_manager.startTorrent(snark);
} else if (postParams.get("recheck") != null) {
_manager.recheckTorrent(snark);
} else {
_manager.addMessage("Unknown command");
}
} else {
_manager.addMessage("Please retry form submission (bad nonce)");
}
}
return null;
}
File r;
if (snark != null) {
Storage storage = snark.getStorage();
if (storage != null) {
File sbase = storage.getBase();
if (pathInTorrent.equals("/"))
r = sbase;
else
r = new File(sbase, pathInTorrent);
} else {
// magnet, dummy
r = new File("");
}
} else {
// dummy
r = new File("");
}
boolean showStopStart = snark != null;
boolean showPriority = snark != null && snark.getStorage() != null && !snark.getStorage().complete() && r.isDirectory();
StringBuilder buf = new StringBuilder(4096);
buf.append(DOCTYPE).append("<html><head><title>");
if (title.endsWith("/"))
title = title.substring(0, title.length() - 1);
final String directory = title;
final int dirSlash = directory.indexOf('/');
final boolean isTopLevel = dirSlash <= 0;
title = _t("Torrent") + ": " + DataHelper.escapeHTML(title);
buf.append(title);
buf.append("</title>\n").append(HEADER_A).append(_themePath).append(HEADER_B).append("<noscript><style type=\"text/css\">.script {display: none;}</style></noscript>").append("<link rel=\"shortcut icon\" href=\"" + _themePath + "favicon.ico\">\n");
if (showPriority)
buf.append("<script src=\"").append(_contextPath).append(WARBASE + "js/folder.js\" type=\"text/javascript\"></script>\n");
buf.append("</head><body");
if (showPriority)
buf.append(" onload=\"setupbuttons()\"");
buf.append(">\n<center><div class=\"snarknavbar\"><a href=\"").append(_contextPath).append("/\" title=\"Torrents\"");
buf.append(" class=\"snarkNav nav_main\">");
if (_contextName.equals(DEFAULT_NAME))
buf.append(_t("I2PSnark"));
else
buf.append(_contextName);
buf.append("</a></div>\n");
if (// always true
parent)
buf.append("<div class=\"page\">\n<div class=\"mainsection\">");
// for stop/start/check
final boolean er = isTopLevel && snark != null && _manager.util().ratingsEnabled();
// global setting
final boolean ec = isTopLevel && snark != null && _manager.util().commentsEnabled();
// per-torrent setting
final boolean esc = ec && _manager.getSavedCommentsEnabled(snark);
final boolean includeForm = showStopStart || showPriority || er || ec;
if (includeForm) {
buf.append("<form action=\"").append(base).append("\" method=\"POST\">\n");
buf.append("<input type=\"hidden\" name=\"nonce\" value=\"").append(_nonce).append("\" >\n");
if (sortParam != null) {
buf.append("<input type=\"hidden\" name=\"sort\" value=\"").append(DataHelper.stripHTML(sortParam)).append("\" >\n");
}
}
if (snark != null) {
// first table - torrent info
buf.append("<table class=\"snarkTorrentInfo\">\n");
buf.append("<tr><th></th><th><b>").append(_t("Torrent")).append(":</b> ").append(DataHelper.escapeHTML(snark.getBaseName())).append("</th></tr>\n");
String fullPath = snark.getName();
String baseName = encodePath((new File(fullPath)).getName());
buf.append("<tr><td>");
toThemeImg(buf, "file");
buf.append("</td><td><b>").append(_t("Torrent file")).append(":</b> <a href=\"").append(_contextPath).append('/').append(baseName).append("\">").append(DataHelper.escapeHTML(fullPath)).append("</a></td></tr>\n");
if (snark.getStorage() != null) {
buf.append("<tr><td>");
toThemeImg(buf, "file");
buf.append("</td><td><b>").append(_t("Data location")).append(":</b> ").append(DataHelper.escapeHTML(snark.getStorage().getBase().getPath())).append("</td></tr>\n");
}
String hex = I2PSnarkUtil.toHex(snark.getInfoHash());
buf.append("<tr><td>");
toThemeImg(buf, "details");
buf.append("</td><td><b>").append(_t("Info hash")).append(":</b> <span id=\"infohash\">").append(hex.toUpperCase(Locale.US)).append("</span></td></tr>\n");
String announce = null;
MetaInfo meta = snark.getMetaInfo();
if (meta != null) {
announce = meta.getAnnounce();
if (announce == null)
announce = snark.getTrackerURL();
if (announce != null) {
announce = DataHelper.stripHTML(announce);
buf.append("<tr><td>");
toThemeImg(buf, "details");
buf.append("</td><td><b>").append(_t("Primary Tracker")).append(":</b> <span class=\"info_tracker\">");
buf.append(getShortTrackerLink(announce, snark.getInfoHash()));
buf.append("</span></td></tr>");
}
List<List<String>> alist = meta.getAnnounceList();
if (alist != null && !alist.isEmpty()) {
buf.append("<tr><td>");
toThemeImg(buf, "details");
buf.append("</td><td><b>").append(_t("Tracker List")).append(":</b> ");
for (List<String> alist2 : alist) {
buf.append("<span class=\"info_tracker\">");
boolean more = false;
for (String s : alist2) {
if (more)
buf.append(' ');
else
more = true;
buf.append(getShortTrackerLink(DataHelper.stripHTML(s), snark.getInfoHash()));
}
buf.append("</span> ");
}
buf.append("</td></tr>\n");
}
}
if (meta != null) {
String com = meta.getComment();
if (com != null && com.length() > 0) {
if (com.length() > 1024)
com = com.substring(0, 1024);
buf.append("<tr><td>");
toThemeImg(buf, "details");
buf.append("</td><td><b>").append(_t("Comment")).append(":</b> ").append(DataHelper.stripHTML(com)).append("</td></tr>\n");
}
long dat = meta.getCreationDate();
// needs locale configured for automatic translation
SimpleDateFormat fmt = new SimpleDateFormat("HH:mm, EEEE dd MMMM yyyy");
fmt.setTimeZone(SystemVersion.getSystemTimeZone(_context));
if (dat > 0) {
String date = fmt.format(new Date(dat));
buf.append("<tr><td>");
toThemeImg(buf, "details");
buf.append("</td><td><b>").append(_t("Created")).append(":</b> ").append(date).append("</td></tr>\n");
}
String cby = meta.getCreatedBy();
if (cby != null && cby.length() > 0) {
if (cby.length() > 128)
cby = com.substring(0, 128);
buf.append("<tr><td>");
toThemeImg(buf, "details");
buf.append("</td><td><b>").append(_t("Created By")).append(":</b> ").append(DataHelper.stripHTML(cby)).append("</td></tr>\n");
}
long[] dates = _manager.getSavedAddedAndCompleted(snark);
if (dates[0] > 0) {
String date = fmt.format(new Date(dates[0]));
buf.append("<tr><td>");
toThemeImg(buf, "details");
buf.append("</td><td><b>").append(_t("Added")).append(":</b> ").append(date).append("</td></tr>\n");
}
if (dates[1] > 0) {
String date = fmt.format(new Date(dates[1]));
buf.append("<tr><td>");
toThemeImg(buf, "details");
buf.append("</td><td><b>").append(_t("Completed")).append(":</b> ").append(date).append("</td></tr>\n");
}
}
if (meta == null || !meta.isPrivate()) {
buf.append("<tr><td><a href=\"").append(MagnetURI.MAGNET_FULL).append(hex);
if (announce != null)
buf.append("&tr=").append(announce);
buf.append("\">").append(toImg("magnet", _t("Magnet link"))).append("</a></td><td><b>Magnet:</b> <a href=\"").append(MagnetURI.MAGNET_FULL).append(hex);
if (announce != null)
buf.append("&tr=").append(announce);
buf.append("\">").append(MagnetURI.MAGNET_FULL).append(hex);
if (announce != null)
buf.append("&tr=").append(announce);
buf.append("</a>").append("</td></tr>\n");
} else {
buf.append("<tr><td>");
toThemeImg(buf, "details");
buf.append("</td><td><b>").append(_t("Private torrent")).append("</td></tr>\n");
}
// We don't have the hash of the torrent file
// buf.append("<tr><td>").append(_t("Maggot link")).append(": <a href=\"").append(MAGGOT).append(hex).append(':').append(hex).append("\">")
// .append(MAGGOT).append(hex).append(':').append(hex).append("</a></td></tr>");
buf.append("<tr id=\"torrentInfoStats\"><td colspan=\"2\"><span>");
toThemeImg(buf, "size");
buf.append("<b>").append(_t("Size")).append(":</b> ").append(formatSize(snark.getTotalLength()));
int pieces = snark.getPieces();
double completion = (pieces - snark.getNeeded()) / (double) pieces;
buf.append("</span> <span>");
toThemeImg(buf, "head_rx");
buf.append("<b>");
if (completion < 1.0)
buf.append(_t("Completion")).append(":</b> ").append((new DecimalFormat("0.00%")).format(completion));
else
buf.append(_t("Complete")).append("</b>");
// up ratio
buf.append("</span> <span>");
toThemeImg(buf, "head_tx");
buf.append("<b>").append(_t("Upload ratio")).append(":</b> ");
long uploaded = snark.getUploaded();
if (uploaded > 0) {
double ratio = uploaded / ((double) snark.getTotalLength());
buf.append((new DecimalFormat("0.000")).format(ratio));
buf.append(" x");
} else {
buf.append('0');
}
// not including skipped files, but -1 when not running
long needed = snark.getNeededLength();
if (needed < 0) {
// including skipped files, valid when not running
needed = snark.getRemainingLength();
}
if (needed > 0) {
buf.append("</span> <span>");
toThemeImg(buf, "head_rx");
buf.append("<b>").append(_t("Remaining")).append(":</b> ").append(formatSize(needed));
}
long skipped = snark.getSkippedLength();
if (skipped > 0) {
buf.append("</span> <span>");
toThemeImg(buf, "head_rx");
buf.append("<b>").append(_t("Skipped")).append(":</b> ").append(formatSize(skipped));
}
if (meta != null) {
List<List<String>> files = meta.getFiles();
int fileCount = files != null ? files.size() : 1;
buf.append("</span> <span>");
toThemeImg(buf, "file");
buf.append("<b>").append(_t("Files")).append(":</b> ").append(fileCount);
}
buf.append("</span> <span>");
toThemeImg(buf, "file");
buf.append("<b>").append(_t("Pieces")).append(":</b> ").append(pieces);
buf.append("</span> <span>");
toThemeImg(buf, "file");
buf.append("<b>").append(_t("Piece size")).append(":</b> ").append(formatSize(snark.getPieceLength(0))).append("</span></td></tr>\n");
// buttons
if (showStopStart) {
buf.append("<tr id=\"torrentInfoControl\"><td colspan=\"2\">");
if (snark.isChecking()) {
buf.append("<span id=\"fileCheck\"><b>").append(_t("Checking")).append("… ").append((new DecimalFormat("0.00%")).format(snark.getCheckingProgress())).append(" <a href=\"").append(base).append("\">").append(_t("Refresh page for results")).append("</a></span>");
} else if (snark.isStarting()) {
buf.append("<b>").append(_t("Starting")).append("…</b>");
} else if (snark.isAllocating()) {
buf.append("<b>").append(_t("Allocating")).append("…</b>");
} else {
boolean isRunning = !snark.isStopped();
buf.append("<input type=\"submit\" value=\"");
if (isRunning)
buf.append(_t("Stop")).append("\" name=\"stop\" class=\"stoptorrent\">\n");
else
buf.append(_t("Start")).append("\" name=\"start\" class=\"starttorrent\">\n");
buf.append("<input type=\"submit\" name=\"recheck\" value=\"").append(_t("Force Recheck"));
if (isRunning)
buf.append("\" class=\"disabled\" disabled=\"disabled\" title=\"").append(_t("Stop the torrent in order to check file integrity")).append("\">\n");
else
buf.append("\" class=\"reload\" title=\"").append(_t("Check integrity of the downloaded file(s)")).append("\">\n");
}
buf.append("</td></tr>\n");
}
} else {
// snark == null
// shouldn't happen
buf.append("<table class=\"resourceError\" id=\"NotFound\"><tr><th colspan=\"2\">").append(_t("Resource Not found")).append("</th></tr><tr><td><b>").append(_t("Resource")).append(":</b></td><td>").append(r.toString()).append("</td></tr><tr><td><b>").append(_t("Base")).append(":</b></td><td>").append(base).append("</td></tr><tr><td><b>").append(_t("Torrent")).append(":</b></td><td>").append(DataHelper.escapeHTML(torrentName)).append("</td></tr>\n");
}
buf.append("</table>\n");
if (snark != null && !r.exists()) {
// fixup TODO
buf.append("<table class=\"resourceError\" id=\"DoesNotExist\"><tr><th colspan=\"2\">").append(_t("Resource Does Not Exist")).append("</th></tr><tr><td><b>").append(_t("Resource")).append(":</b></td><td>").append(r.toString()).append("</td></tr><tr><td><b>").append(_t("Base")).append(":</b></td><td>").append(base).append("</td></tr><tr><td><b>").append(_t("Torrent")).append(":</b></td><td>").append(DataHelper.escapeHTML(torrentName)).append("</td></tr></table></div></div></center>\n</body>\n</html>");
return buf.toString();
}
File[] ls = null;
if (r.isDirectory()) {
ls = r.listFiles();
}
if (ls == null) {
// We are only showing the torrent info section
if (er || ec)
displayComments(snark, er, ec, esc, buf);
if (includeForm)
buf.append("</form>");
buf.append("</div></div>\n</body>\n</html>");
return buf.toString();
}
Storage storage = snark != null ? snark.getStorage() : null;
List<Sorters.FileAndIndex> fileList = new ArrayList<Sorters.FileAndIndex>(ls.length);
// precompute remaining for all files for efficiency
long[] remainingArray = (storage != null) ? storage.remaining() : null;
for (int i = 0; i < ls.length; i++) {
fileList.add(new Sorters.FileAndIndex(ls[i], storage, remainingArray));
}
boolean showSort = fileList.size() > 1;
if (showSort) {
int sort = 0;
if (sortParam != null) {
try {
sort = Integer.parseInt(sortParam);
} catch (NumberFormatException nfe) {
}
}
Collections.sort(fileList, Sorters.getFileComparator(sort, this));
}
// second table - dir info
buf.append("<table class=\"snarkDirInfo\"><thead>\n");
buf.append("<tr>\n").append("<th colspan=2>");
String tx = _t("Directory");
// cycle through sort by name or type
String sort;
boolean isTypeSort = false;
if (showSort) {
if (sortParam == null || "0".equals(sortParam) || "1".equals(sortParam)) {
sort = "-1";
} else if ("-1".equals(sortParam)) {
sort = "12";
isTypeSort = true;
} else if ("12".equals(sortParam)) {
sort = "-12";
isTypeSort = true;
} else {
sort = "";
}
buf.append("<a href=\"").append(base).append(getQueryString(sort)).append("\">");
}
toThemeImg(buf, "file", tx, showSort ? _t("Sort by {0}", (isTypeSort ? _t("File type") : _t("Name"))) : tx + ": " + directory);
if (showSort)
buf.append("</a>");
if (!isTopLevel) {
buf.append(" ");
buf.append(DataHelper.escapeHTML(directory.substring(dirSlash + 1)));
}
buf.append("</th>\n<th align=\"right\">");
if (showSort) {
sort = ("5".equals(sortParam)) ? "-5" : "5";
buf.append("<a href=\"").append(base).append(getQueryString(sort)).append("\">");
}
tx = _t("Size");
toThemeImg(buf, "size", tx, showSort ? _t("Sort by {0}", tx) : tx);
if (showSort)
buf.append("</a>");
buf.append("</th>\n<th class=\"headerstatus\">");
boolean showRemainingSort = showSort && showPriority;
if (showRemainingSort) {
sort = ("10".equals(sortParam)) ? "-10" : "10";
buf.append("<a href=\"").append(base).append(getQueryString(sort)).append("\">");
}
tx = _t("Download Status");
toThemeImg(buf, "status", tx, showRemainingSort ? _t("Sort by {0}", _t("Remaining")) : tx);
if (showRemainingSort)
buf.append("</a>");
if (showPriority) {
buf.append("</th>\n<th class=\"headerpriority\">");
if (showSort) {
sort = ("13".equals(sortParam)) ? "-13" : "13";
buf.append("<a href=\"").append(base).append(getQueryString(sort)).append("\">");
}
tx = _t("Download Priority");
toThemeImg(buf, "priority", tx, showSort ? _t("Sort by {0}", tx) : tx);
if (showSort)
buf.append("</a>");
}
buf.append("</th>\n</tr>\n</thead>\n");
buf.append("<tr><td colspan=\"" + (showPriority ? '5' : '4') + "\" class=\"ParentDir\"><A HREF=\"");
URIUtil.encodePath(buf, addPaths(decodedBase, "../"));
buf.append("\">");
toThemeImg(buf, "up");
buf.append(' ').append(_t("Up to higher level directory")).append("</A></td></tr>\n");
// DateFormat dfmt=DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
// DateFormat.MEDIUM);
boolean showSaveButton = false;
boolean rowEven = true;
for (Sorters.FileAndIndex fai : fileList) {
// String encoded = encodePath(ls[i].getName());
// bugfix for I2P - Backport from Jetty 6 (zero file lengths and last-modified times)
// http://jira.codehaus.org/browse/JETTY-361?page=com.atlassian.jira.plugin.system.issuetabpanels%3Achangehistory-tabpanel#issue-tabs
// See resource.diff attachment
// Resource item = addPath(encoded);
File item = fai.file;
String rowClass = (rowEven ? "snarkTorrentEven" : "snarkTorrentOdd");
rowEven = !rowEven;
buf.append("<tr class=\"").append(rowClass).append("\">");
// Get completeness and status string
boolean complete = false;
String status = "";
long length = item.length();
int fileIndex = fai.index;
int priority = 0;
if (fai.isDirectory) {
complete = true;
// status = toImg("tick") + ' ' + _t("Directory");
} else {
if (snark == null || snark.getStorage() == null) {
// Assume complete, perhaps he removed a completed torrent but kept a bookmark
complete = true;
status = toImg("cancel") + ' ' + _t("Torrent not found?");
} else {
long remaining = fai.remaining;
if (remaining < 0) {
complete = true;
status = toImg("cancel") + ' ' + _t("File not found in torrent?");
} else if (remaining == 0 || length <= 0) {
complete = true;
status = "<div class=\"priorityIndicator\">" + toImg("tick") + "</div>" + _t("Complete");
} else {
priority = fai.priority;
if (priority < 0)
status = "<div class=\"priorityIndicator\">" + toImg("cancel") + "</div>";
else if (priority == 0)
status = "<div class=\"priorityIndicator\">" + toImg("clock") + "</div>";
else
status = "<div class=\"priorityIndicator\">" + toImg("clock_red") + "</div>";
long percent = 100 * (length - remaining) / length;
status += " <div class=\"percentBarOuter\">" + "<div class=\"percentBarInner\" style=\"width: " + percent + "%;\"><div class=\"percentBarText\" tabindex=\"0\" title=\"" + formatSize(remaining) + ' ' + _t("remaining") + "\">" + percent + "%</div></div></div>";
}
}
}
String path = addPaths(decodedBase, item.getName());
if (item.isDirectory() && !path.endsWith("/"))
path = addPaths(path, "/");
path = encodePath(path);
String icon = toIcon(item);
String mime = getMimeType(path);
if (mime == null)
mime = "";
buf.append("<td class=\"snarkFileIcon\">");
if (complete) {
buf.append("<a href=\"").append(path).append("\">");
// thumbnail ?
String plc = item.toString().toLowerCase(Locale.US);
if (mime.startsWith("image/")) {
buf.append("<img alt=\"\" border=\"0\" class=\"thumb\" src=\"").append(path).append("\"></a>");
} else {
buf.append(toImg(icon, _t("Open"))).append("</a>");
}
} else {
buf.append(toImg(icon));
}
buf.append("</td><td class=\"snarkFileName\">");
if (complete) {
buf.append("<a href=\"").append(path);
// send browser-viewable files to new tab to avoid potential display in iframe
if (mime.startsWith("text/") || mime.startsWith("image/") || mime.startsWith("audio/") || mime.startsWith("video/") || mime.equals("application/ogg"))
buf.append("\" target=\"_blank");
buf.append("\">");
}
buf.append(DataHelper.escapeHTML(item.getName()));
if (complete)
buf.append("</a>");
buf.append("</td><td align=right class=\"snarkFileSize\">");
if (!item.isDirectory())
buf.append(formatSize(length));
buf.append("</td><td class=\"snarkFileStatus\">");
// buf.append(dfmt.format(new Date(item.lastModified())));
buf.append(status);
buf.append("</td>");
if (showPriority) {
buf.append("<td class=\"priority\">");
if ((!complete) && (!item.isDirectory())) {
buf.append("<label class=\"priorityHigh\" title=\"").append(_t("Download file at high priority")).append("\">").append("\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"prihigh\" value=\"5\" name=\"pri.").append(fileIndex).append("\" ");
if (priority > 0)
buf.append("checked=\"checked\"");
buf.append('>').append(_t("High")).append("</label>");
buf.append("<label class=\"priorityNormal\" title=\"").append(_t("Download file at normal priority")).append("\">").append("\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"prinorm\" value=\"0\" name=\"pri.").append(fileIndex).append("\" ");
if (priority == 0)
buf.append("checked=\"checked\"");
buf.append('>').append(_t("Normal")).append("</label>");
buf.append("<label class=\"prioritySkip\" title=\"").append(_t("Do not download this file")).append("\">").append("\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"priskip\" value=\"-9\" name=\"pri.").append(fileIndex).append("\" ");
if (priority < 0)
buf.append("checked=\"checked\"");
buf.append('>').append(_t("Skip")).append("</label>");
showSaveButton = true;
}
buf.append("</td>");
}
buf.append("</tr>\n");
}
if (showSaveButton) {
buf.append("<thead><tr id=\"setPriority\"><th class=\"headerpriority\" colspan=\"5\">" + "<span class=\"script\"><a class=\"control\" id=\"setallhigh\" href=\"javascript:void(null);\" onclick=\"setallhigh();\">").append(toImg("clock_red")).append(_t("Set all high")).append("</a>\n" + "<a class=\"control\" id=\"setallnorm\" href=\"javascript:void(null);\" onclick=\"setallnorm();\">").append(toImg("clock")).append(_t("Set all normal")).append("</a>\n" + "<a class=\"control\" id=\"setallskip\" href=\"javascript:void(null);\" onclick=\"setallskip();\">").append(toImg("cancel")).append(_t("Skip all")).append("</a></span>\n" + "<input type=\"submit\" class=\"accept\" value=\"").append(_t("Save priorities")).append("\" name=\"savepri\" >\n" + "</th></tr></thead>\n");
}
buf.append("</table>\n");
if (er || ec)
displayComments(snark, er, ec, esc, buf);
// for stop/start/check
if (includeForm)
buf.append("</form>");
buf.append("</div></div>\n</body>\n</html>\n");
return buf.toString();
}
use of org.klomp.snark.MetaInfo in project i2p.i2p by i2p.
the class I2PSnarkServlet method displaySnark.
/**
* Display one snark (one line in table, unless showPeers is true)
*
* @param stats in/out param (totals)
* @param statsOnly if true, output nothing, update stats only
* @param canWrite is the i2psnark data directory writable?
*/
private void displaySnark(PrintWriter out, HttpServletRequest req, Snark snark, String uri, int row, long[] stats, boolean showPeers, boolean isDegraded, boolean noThinsp, boolean showDebug, boolean statsOnly, boolean showRatios, boolean canWrite) throws IOException {
// stats
long uploaded = snark.getUploaded();
stats[0] += snark.getDownloaded();
stats[1] += uploaded;
long downBps = snark.getDownloadRate();
long upBps = snark.getUploadRate();
boolean isRunning = !snark.isStopped();
if (isRunning) {
stats[2] += downBps;
stats[3] += upBps;
}
int curPeers = snark.getPeerCount();
stats[4] += curPeers;
long total = snark.getTotalLength();
if (total > 0)
stats[5] += total;
if (statsOnly)
return;
String basename = snark.getBaseName();
String fullBasename = basename;
if (basename.length() > MAX_DISPLAYED_FILENAME_LENGTH) {
String start = ServletUtil.truncate(basename, MAX_DISPLAYED_FILENAME_LENGTH);
if (start.indexOf(' ') < 0 && start.indexOf('-') < 0) {
// browser has nowhere to break it
basename = start + HELLIP;
}
}
// includes skipped files, -1 for magnet mode
long remaining = snark.getRemainingLength();
if (remaining > total)
remaining = total;
// does not include skipped files, -1 for magnet mode or when not running.
long needed = snark.getNeededLength();
if (needed > total)
needed = total;
long remainingSeconds;
if (downBps > 0 && needed > 0)
remainingSeconds = needed / downBps;
else
remainingSeconds = -1;
MetaInfo meta = snark.getMetaInfo();
String b64 = Base64.encode(snark.getInfoHash());
String b64Short = b64.substring(0, 6);
// isValid means isNotMagnet
boolean isValid = meta != null;
boolean isMultiFile = isValid && meta.getFiles() != null;
String err = snark.getTrackerProblems();
int knownPeers = Math.max(curPeers, snark.getTrackerSeenPeers());
String rowClass = (row % 2 == 0 ? "snarkTorrentEven" : "snarkTorrentOdd");
String statusString;
if (snark.isChecking()) {
statusString = toThemeImg("stalled", "", _t("Checking")) + "</td>" + "<td class=\"snarkTorrentStatus\"><b>" + _t("Checking") + "</b>" + ' ' + (new DecimalFormat("0.00%")).format(snark.getCheckingProgress());
} else if (snark.isAllocating()) {
statusString = toThemeImg("stalled", "", _t("Allocating")) + "</td>" + "<td class=\"snarkTorrentStatus\"><b>" + _t("Allocating") + "</b>";
} else if (err != null && isRunning && curPeers == 0) {
// } else if (err != null && curPeers == 0) {
// Also don't show if seeding... but then we won't see the not-registered error
// && remaining != 0 && needed != 0) {
// let's only show this if we have no peers, otherwise PEX and DHT should bail us out, user doesn't care
// if (isRunning && curPeers > 0 && !showPeers)
// statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td>" +
// "<td class=\"snarkTorrentStatus " + rowClass + "\">" + _t("Tracker Error") +
// ": <a href=\"" + uri + "?p=" + Base64.encode(snark.getInfoHash()) + "\">" +
// curPeers + thinsp(noThinsp) +
// ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
// else if (isRunning)
// if (isRunning) {
statusString = toThemeImg("trackererror", "", err) + "</td>" + "<td class=\"snarkTorrentStatus\"><b>" + _t("Tracker Error") + ":</b> " + curPeers + thinsp(noThinsp) + ngettext("1 peer", "{0} peers", knownPeers);
// } else {
// if (err.length() > MAX_DISPLAYED_ERROR_LENGTH)
// err = DataHelper.escapeHTML(err.substring(0, MAX_DISPLAYED_ERROR_LENGTH)) + "…";
// else
// err = DataHelper.escapeHTML(err);
// statusString = toThemeImg("trackererror", "", err) + "</td>" +
// "<td class=\"snarkTorrentStatus\">" + _t("Tracker Error");
// }
} else if (snark.isStarting()) {
statusString = toThemeImg("stalled", "", _t("Starting")) + "</td>" + "<td class=\"snarkTorrentStatus\"><b class=\"alwaysShow\">" + _t("Starting") + "</b>";
} else if (remaining == 0 || needed == 0) {
// partial complete or seeding
if (isRunning) {
String img;
String txt;
String tooltip;
if (remaining == 0) {
img = "seeding";
txt = _t("Seeding");
tooltip = _t("Seeding to {0} of {1} peers in swarm", curPeers, knownPeers);
} else {
// partial
img = "complete";
txt = _t("Complete");
tooltip = txt;
if (curPeers > 0) {
tooltip = txt + " (" + _t("Seeding to {0} of {1} peers in swarm", curPeers, knownPeers) + ")";
}
}
if (curPeers > 0 && !showPeers) {
statusString = toThemeImg(img, "", tooltip) + "</td>" + "<td class=\"snarkTorrentStatus\"><b>" + txt + ":</b> <a href=\"" + uri + getQueryString(req, b64, null, null) + '#' + b64Short + "\">" + curPeers + thinsp(noThinsp) + ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
} else {
statusString = toThemeImg(img, "", tooltip) + "</td>" + "<td class=\"snarkTorrentStatus\"><b>" + txt + ":</b> " + curPeers + thinsp(noThinsp) + ngettext("1 peer", "{0} peers", knownPeers);
}
} else {
statusString = toThemeImg("complete", "", _t("Complete")) + "</td>" + "<td class=\"snarkTorrentStatus\"><b class=\"alwaysShow\">" + _t("Complete") + "</b>";
}
} else {
if (isRunning && curPeers > 0 && downBps > 0 && !showPeers) {
statusString = toThemeImg("downloading", "", _t("OK") + " (" + _t("Downloading from {0} of {1} peers in swarm", curPeers, knownPeers) + ")") + "</td>" + "<td class=\"snarkTorrentStatus\"><b>" + _t("OK") + ":</b> <a href=\"" + uri + getQueryString(req, b64, null, null) + '#' + b64Short + "\">" + curPeers + thinsp(noThinsp) + ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
} else if (isRunning && curPeers > 0 && downBps > 0) {
statusString = toThemeImg("downloading", "", _t("OK") + " (" + _t("Downloading from {0} of {1} peers in swarm", curPeers, knownPeers) + ")") + "</td>" + "<td class=\"snarkTorrentStatus\"><b>" + _t("OK") + ":</b> " + curPeers + thinsp(noThinsp) + ngettext("1 peer", "{0} peers", knownPeers);
} else if (isRunning && curPeers > 0 && !showPeers) {
statusString = toThemeImg("stalled", "", _t("Stalled") + " (" + _t("Connected to {0} of {1} peers in swarm", curPeers, knownPeers) + ")") + "</td>" + "<td class=\"snarkTorrentStatus\"><b>" + _t("Stalled") + ":</b> <a href=\"" + uri + getQueryString(req, b64, null, null) + '#' + b64Short + "\">" + curPeers + thinsp(noThinsp) + ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
} else if (isRunning && curPeers > 0) {
statusString = toThemeImg("stalled", "", _t("Stalled") + " (" + _t("Connected to {0} of {1} peers in swarm", curPeers, knownPeers) + ")") + "</td>" + "<td class=\"snarkTorrentStatus\"><b>" + _t("Stalled") + ":</b> " + curPeers + thinsp(noThinsp) + ngettext("1 peer", "{0} peers", knownPeers);
} else if (isRunning && knownPeers > 0) {
statusString = toThemeImg("nopeers", "", _t("No Peers") + " (" + _t("Connected to {0} of {1} peers in swarm", curPeers, knownPeers) + ")") + "</td>" + "<td class=\"snarkTorrentStatus\"><b>" + _t("No Peers") + ":</b> 0" + thinsp(noThinsp) + knownPeers;
} else if (isRunning) {
statusString = toThemeImg("nopeers", "", _t("No Peers")) + "</td>" + "<td class=\"snarkTorrentStatus\"><b class=\"alwaysShow\">" + _t("No Peers") + "</b>";
} else {
statusString = toThemeImg("stopped", "", _t("Stopped")) + "</td>" + "<td class=\"snarkTorrentStatus\"><b class=\"alwaysShow\">" + _t("Stopped") + "</b>";
}
}
out.write("<tr class=\"" + rowClass + "\" id=\"" + b64Short + "\">");
out.write("<td class=\"snarkGraphicStatus\" align=\"center\">");
out.write(statusString + "</td>\n\t");
// (i) icon column
out.write("<td class=\"snarkTrackerDetails\">");
if (isValid) {
String announce = meta.getAnnounce();
if (announce == null)
announce = snark.getTrackerURL();
if (announce != null) {
// Link to tracker details page
String trackerLink = getTrackerLink(announce, snark.getInfoHash());
if (trackerLink != null)
out.write(trackerLink);
}
}
String encodedBaseName = encodePath(fullBasename);
// File type icon column
out.write("</td>\n<td class=\"snarkTorrentDetails\">");
if (isValid) {
// Link to local details page - note that trailing slash on a single-file torrent
// gets us to the details page instead of the file.
StringBuilder buf = new StringBuilder(128);
buf.append("<a href=\"").append(encodedBaseName).append("/\" title=\"").append(_t("Torrent details")).append("\">");
out.write(buf.toString());
}
String icon;
if (isMultiFile)
icon = "folder";
else if (isValid)
icon = toIcon(meta.getName());
else if (snark instanceof FetchAndAdd)
icon = "basket_put";
else
icon = "magnet";
if (isValid) {
out.write(toImg(icon));
out.write("</a>");
} else {
out.write(toImg(icon));
}
// Torrent name column
out.write("</td><td class=\"snarkTorrentName\">");
// }
if (remaining == 0 || isMultiFile) {
StringBuilder buf = new StringBuilder(128);
buf.append("<a href=\"").append(encodedBaseName);
if (isMultiFile)
buf.append('/');
buf.append("\" title=\"");
if (isMultiFile)
buf.append(_t("View files"));
else
buf.append(_t("Open file"));
buf.append("\">");
out.write(buf.toString());
}
out.write(DataHelper.escapeHTML(basename));
if (remaining == 0 || isMultiFile)
out.write("</a>");
out.write("<td align=\"right\" class=\"snarkTorrentETA\">");
if (isRunning && remainingSeconds > 0 && !snark.isChecking())
// (eta 6h)
out.write(DataHelper.formatDuration2(Math.max(remainingSeconds, 10) * 1000));
out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentDownloaded\">");
if (remaining > 0) {
long percent = 100 * (total - remaining) / total;
out.write("<div class=\"percentBarOuter\">");
out.write("<div class=\"percentBarInner\" style=\"width: " + percent + "%;\">");
out.write("<div class=\"percentBarText\" tabindex=\"0\" title=\"");
out.write(percent + "% " + _t("complete") + "; " + formatSize(remaining) + ' ' + _t("remaining"));
out.write("\">");
out.write(formatSize(total - remaining) + thinsp(noThinsp) + formatSize(total));
out.write("</div></div></div>");
} else if (remaining == 0) {
// needs locale configured for automatic translation
SimpleDateFormat fmt = new SimpleDateFormat("HH:mm, EEE dd MMM yyyy");
fmt.setTimeZone(SystemVersion.getSystemTimeZone(_context));
long[] dates = _manager.getSavedAddedAndCompleted(snark);
String date = fmt.format(new Date(dates[1]));
out.write("<div class=\"percentBarComplete\" title=\"");
out.write(_t("Completed") + ": " + date + "\">");
// 3GB
out.write(formatSize(total));
out.write("</div>");
}
// else
// out.write("??"); // no meta size yet
out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentUploaded\">");
if (isValid) {
if (showRatios) {
if (total > 0) {
double ratio = uploaded / ((double) total);
out.write((new DecimalFormat("0.000")).format(ratio));
out.write(" x");
}
} else if (uploaded > 0) {
out.write(formatSize(uploaded));
}
}
out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentRateDown\">");
if (isRunning && needed > 0)
out.write(formatSizeDec(downBps) + "ps");
out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentRateUp\">");
if (isRunning && isValid)
out.write(formatSizeDec(upBps) + "ps");
out.write("</td>\n\t");
out.write("<td align=\"center\" class=\"snarkTorrentAction\">");
if (snark.isChecking()) {
// show no buttons
} else if (isRunning) {
// Stop Button
if (isDegraded)
out.write("<a href=\"" + _contextPath + "/?action=Stop_" + b64 + "&nonce=" + _nonce + getQueryString(req, "", null, null).replace("?", "&") + "\"><img title=\"");
else
out.write("<input type=\"image\" name=\"action_Stop_" + b64 + "\" value=\"foo\" title=\"");
out.write(_t("Stop the torrent"));
out.write("\" src=\"" + _imgPath + "stop.png\" alt=\"");
out.write(_t("Stop"));
out.write("\">");
if (isDegraded)
out.write("</a>");
} else if (!snark.isStarting()) {
if (!_manager.isStopping()) {
// This works in Opera but it's displayed a little differently, so use noThinsp here too so all 3 icons are consistent
if (noThinsp)
out.write("<a href=\"" + _contextPath + "/?action=Start_" + b64 + "&nonce=" + _nonce + getQueryString(req, "", null, null).replace("?", "&") + "\"><img title=\"");
else
out.write("<input type=\"image\" name=\"action_Start_" + b64 + "\" value=\"foo\" title=\"");
out.write(_t("Start the torrent"));
out.write("\" src=\"" + _imgPath + "start.png\" alt=\"");
out.write(_t("Start"));
out.write("\">");
if (isDegraded)
out.write("</a>");
}
if (isValid && canWrite) {
// Doesnt work with Opera so use noThinsp instead of isDegraded
if (noThinsp)
out.write("<a href=\"" + _contextPath + "/?action=Remove_" + b64 + "&nonce=" + _nonce + getQueryString(req, "", null, null).replace("?", "&") + "\"><img title=\"");
else
out.write("<input type=\"image\" name=\"action_Remove_" + b64 + "\" value=\"foo\" title=\"");
out.write(_t("Remove the torrent from the active list, deleting the .torrent file"));
out.write("\" onclick=\"if (!confirm('");
// Can't figure out how to escape double quotes inside the onclick string.
// Single quotes in translate strings with parameters must be doubled.
// Then the remaining single quote must be escaped
out.write(_t("Are you sure you want to delete the file \\''{0}\\'' (downloaded data will not be deleted) ?", escapeJSString(snark.getName())));
out.write("')) { return false; }\"");
out.write(" src=\"" + _imgPath + "remove.png\" alt=\"");
out.write(_t("Remove"));
out.write("\">");
if (isDegraded)
out.write("</a>");
}
// We can delete magnets without write privs
if (!isValid || canWrite) {
// Doesnt work with Opera so use noThinsp instead of isDegraded
if (noThinsp)
out.write("<a href=\"" + _contextPath + "/?action=Delete_" + b64 + "&nonce=" + _nonce + getQueryString(req, "", null, null).replace("?", "&") + "\"><img title=\"");
else
out.write("<input type=\"image\" name=\"action_Delete_" + b64 + "\" value=\"foo\" title=\"");
out.write(_t("Delete the .torrent file and the associated data file(s)"));
out.write("\" onclick=\"if (!confirm('");
// Can't figure out how to escape double quotes inside the onclick string.
// Single quotes in translate strings with parameters must be doubled.
// Then the remaining single quote must be escaped
out.write(_t("Are you sure you want to delete the torrent \\''{0}\\'' and all downloaded data?", escapeJSString(fullBasename)));
out.write("')) { return false; }\"");
out.write(" src=\"" + _imgPath + "delete.png\" alt=\"");
out.write(_t("Delete"));
out.write("\">");
if (isDegraded)
out.write("</a>");
}
}
out.write("</td>\n</tr>\n");
if (showPeers && isRunning && curPeers > 0) {
List<Peer> peers = snark.getPeerList();
if (!showDebug)
Collections.sort(peers, new PeerComparator());
for (Peer peer : peers) {
if (!peer.isConnected())
continue;
out.write("<tr class=\"peerinfo " + rowClass + "\"><td class=\"snarkGraphicStatus\" title=\"");
out.write(_t("Peer attached to swarm"));
out.write("\"></td><td colspan=\"4\">");
PeerID pid = peer.getPeerID();
String ch = pid != null ? pid.toString().substring(0, 4) : "????";
String client;
if ("AwMD".equals(ch))
client = _t("I2PSnark");
else if ("LUFa".equals(ch))
client = "Vuze" + getAzVersion(pid.getID());
else if ("LUJJ".equals(ch))
client = "BiglyBT" + getAzVersion(pid.getID());
else if ("LVhE".equals(ch))
client = "XD" + getAzVersion(pid.getID());
else if ("ZV".equals(ch.substring(2, 4)) || "VUZP".equals(ch))
client = "Robert" + getRobtVersion(pid.getID());
else if (// LVCS 1.0.2?; LVRS 1.0.4
ch.startsWith("LV"))
client = "Transmission" + getAzVersion(pid.getID());
else if ("LUtU".equals(ch))
client = "KTorrent" + getAzVersion(pid.getID());
else if ("CwsL".equals(ch))
client = "I2PSnarkXL";
else if ("BFJT".equals(ch))
client = "I2PRufus";
else if ("TTMt".equals(ch))
client = "I2P-BT";
else
client = _t("Unknown") + " (" + ch + ')';
out.write(client + " <tt title=\"");
out.write(_t("Destination (identity) of peer"));
out.write("\">" + peer.toString().substring(5, 9) + "</tt>");
if (showDebug)
out.write(" inactive " + (peer.getInactiveTime() / 1000) + "s");
out.write("</td>\n\t");
out.write("<td class=\"snarkTorrentETA\">");
out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentDownloaded\">");
float pct;
if (isValid) {
pct = (float) (100.0 * peer.completed() / meta.getPieces());
if (pct >= 100.0)
out.write(_t("Seed"));
else {
String ps = String.valueOf(pct);
if (ps.length() > 5)
ps = ps.substring(0, 5);
out.write("<div class=\"percentBarOuter\">");
out.write("<div class=\"percentBarInner\" style=\"width:" + ps + "%;\">");
out.write("<div class=\"percentBarText\" tabindex=\"0\">" + ps + "%</div>");
out.write("</div></div>");
}
} else {
pct = (float) 101.0;
// until we get the metainfo we don't know how many pieces there are
// out.write("??");
}
out.write("</td>\n\t");
out.write("<td class=\"snarkTorrentUploaded\">");
out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentRateDown\">");
if (needed > 0) {
if (peer.isInteresting() && !peer.isChoked()) {
out.write("<span class=\"unchoked\">");
out.write(formatSizeDec(peer.getDownloadRate()) + "ps</span>");
} else {
out.write("<span class=\"choked\" title=\"");
if (!peer.isInteresting())
out.write(_t("Uninteresting (The peer has no pieces we need)"));
else
out.write(_t("Choked (The peer is not allowing us to request pieces)"));
out.write("\">");
out.write(formatSizeDec(peer.getDownloadRate()) + "ps</span>");
}
} else if (!isValid) {
// if (peer supports metadata extension) {
out.write("<span class=\"unchoked\">");
out.write(formatSizeDec(peer.getDownloadRate()) + "ps</span>");
// } else {
// }
}
out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentRateUp\">");
if (isValid && pct < 100.0) {
if (peer.isInterested() && !peer.isChoking()) {
out.write("<span class=\"unchoked\">");
out.write(formatSizeDec(peer.getUploadRate()) + "ps</span>");
} else {
out.write("<span class=\"choked\" title=\"");
if (!peer.isInterested())
out.write(_t("Uninterested (We have no pieces the peer needs)"));
else
out.write(_t("Choking (We are not allowing the peer to request pieces)"));
out.write("\">");
out.write(formatSizeDec(peer.getUploadRate()) + "ps</span>");
}
}
out.write("</td>\n\t");
out.write("<td class=\"snarkTorrentAction\">");
out.write("</td></tr>\n\t");
if (showDebug)
out.write("<tr class=\"debuginfo " + rowClass + "\"><td class=\"snarkGraphicStatus\"></td><td colspan=\"10\">" + peer.getSocket() + "</td></tr>");
}
}
}
use of org.klomp.snark.MetaInfo in project i2p.i2p by i2p.
the class I2PSnarkServlet method processRequest.
/**
* Do what they ask, adding messages to _manager.addMessage as necessary
*/
private void processRequest(HttpServletRequest req) {
String action = req.getParameter("action");
if (action == null) {
// http://www.onenaught.com/posts/382/firefox-4-change-input-type-image-only-submits-x-and-y-not-name
// TODO-Java6: Remove cast, return type is correct
@SuppressWarnings("unchecked") Map<String, String[]> params = req.getParameterMap();
for (Object o : params.keySet()) {
String key = (String) o;
if (key.startsWith("action_") && key.endsWith(".x")) {
action = key.substring(0, key.length() - 2).substring(7);
break;
}
}
if (action == null) {
_manager.addMessage("No action specified");
return;
}
}
// }
if ("Add".equals(action)) {
String newURL = req.getParameter("nofilter_newURL");
/**
****
* // NOTE - newFile currently disabled in HTML form - see below
* File f = null;
* if ( (newFile != null) && (newFile.trim().length() > 0) )
* f = new File(newFile.trim());
* if ( (f != null) && (!f.exists()) ) {
* _manager.addMessage(_t("Torrent file {0} does not exist", newFile));
* }
* if ( (f != null) && (f.exists()) ) {
* // NOTE - All this is disabled - load from local file disabled
* File local = new File(_manager.getDataDir(), f.getName());
* String canonical = null;
* try {
* canonical = local.getCanonicalPath();
*
* if (local.exists()) {
* if (_manager.getTorrent(canonical) != null)
* _manager.addMessage(_t("Torrent already running: {0}", newFile));
* else
* _manager.addMessage(_t("Torrent already in the queue: {0}", newFile));
* } else {
* boolean ok = FileUtil.copy(f.getAbsolutePath(), local.getAbsolutePath(), true);
* if (ok) {
* _manager.addMessage(_t("Copying torrent to {0}", local.getAbsolutePath()));
* _manager.addTorrent(canonical);
* } else {
* _manager.addMessage(_t("Unable to copy the torrent to {0}", local.getAbsolutePath()) + ' ' + _t("from {0}", f.getAbsolutePath()));
* }
* }
* } catch (IOException ioe) {
* _log.warn("hrm: " + local, ioe);
* }
* } else
****
*/
if (newURL != null) {
newURL = newURL.trim();
String newDir = req.getParameter("nofilter_newDir");
File dir = null;
if (newDir != null) {
newDir = newDir.trim();
if (newDir.length() > 0) {
dir = new SecureFile(newDir);
if (!dir.isAbsolute()) {
_manager.addMessage(_t("Data directory must be an absolute path") + ": " + dir);
return;
}
if (!dir.isDirectory() && !dir.mkdirs()) {
_manager.addMessage(_t("Data directory cannot be created") + ": " + dir);
return;
}
Collection<Snark> snarks = _manager.getTorrents();
for (Snark s : snarks) {
Storage storage = s.getStorage();
if (storage == null)
continue;
File sbase = storage.getBase();
if (isParentOf(sbase, dir)) {
_manager.addMessage(_t("Cannot add torrent {0} inside another torrent: {1}", dir.getAbsolutePath(), sbase));
return;
}
}
}
}
File dd = _manager.getDataDir();
if (!dd.canWrite()) {
_manager.addMessage(_t("No write permissions for data directory") + ": " + dd);
return;
}
if (newURL.startsWith("http://")) {
FetchAndAdd fetch = new FetchAndAdd(_context, _manager, newURL, dir);
_manager.addDownloader(fetch);
} else if (newURL.startsWith(MagnetURI.MAGNET) || newURL.startsWith(MagnetURI.MAGGOT)) {
addMagnet(newURL, dir);
} else if (newURL.length() == 40 && newURL.replaceAll("[a-fA-F0-9]", "").length() == 0) {
// hex
newURL = newURL.toUpperCase(Locale.US);
addMagnet(MagnetURI.MAGNET_FULL + newURL, dir);
} else if (newURL.length() == 32 && newURL.replaceAll("[a-zA-Z2-7]", "").length() == 0) {
// b32
newURL = newURL.toUpperCase(Locale.US);
addMagnet(MagnetURI.MAGNET_FULL + newURL, dir);
} else {
_manager.addMessage(_t("Invalid URL: Must start with \"http://\", \"{0}\", or \"{1}\"", MagnetURI.MAGNET, MagnetURI.MAGGOT));
}
} else {
// no file or URL specified
}
} else if (action.startsWith("Stop_")) {
String torrent = action.substring(5);
if (torrent != null) {
byte[] infoHash = Base64.decode(torrent);
if ((infoHash != null) && (infoHash.length == 20)) {
// valid sha1
for (String name : _manager.listTorrentFiles()) {
Snark snark = _manager.getTorrent(name);
if ((snark != null) && (DataHelper.eq(infoHash, snark.getInfoHash()))) {
_manager.stopTorrent(snark, false);
break;
}
}
}
}
} else if (action.startsWith("Start_")) {
String torrent = action.substring(6);
if (torrent != null) {
byte[] infoHash = Base64.decode(torrent);
if ((infoHash != null) && (infoHash.length == 20)) {
// valid sha1
_manager.startTorrent(infoHash);
}
}
} else if (action.startsWith("Remove_")) {
String torrent = action.substring(7);
if (torrent != null) {
byte[] infoHash = Base64.decode(torrent);
if ((infoHash != null) && (infoHash.length == 20)) {
// valid sha1
for (String name : _manager.listTorrentFiles()) {
Snark snark = _manager.getTorrent(name);
if ((snark != null) && (DataHelper.eq(infoHash, snark.getInfoHash()))) {
MetaInfo meta = snark.getMetaInfo();
if (meta == null) {
// magnet - remove and delete are the same thing
// Remove not shown on UI so we shouldn't get here
_manager.deleteMagnet(snark);
_manager.addMessage(_t("Magnet deleted: {0}", name));
return;
}
File f = new File(name);
File dd = _manager.getDataDir();
boolean canDelete = dd.canWrite() || !f.exists();
_manager.stopTorrent(snark, canDelete);
// TODO race here with the DirMonitor, could get re-added
if (f.delete()) {
_manager.addMessage(_t("Torrent file deleted: {0}", f.getAbsolutePath()));
} else if (f.exists()) {
if (!canDelete)
_manager.addMessage(_t("No write permissions for data directory") + ": " + dd);
_manager.addMessage(_t("Torrent file could not be deleted: {0}", f.getAbsolutePath()));
}
break;
}
}
}
}
} else if (action.startsWith("Delete_")) {
String torrent = action.substring(7);
if (torrent != null) {
byte[] infoHash = Base64.decode(torrent);
if ((infoHash != null) && (infoHash.length == 20)) {
// valid sha1
for (String name : _manager.listTorrentFiles()) {
Snark snark = _manager.getTorrent(name);
if ((snark != null) && (DataHelper.eq(infoHash, snark.getInfoHash()))) {
MetaInfo meta = snark.getMetaInfo();
if (meta == null) {
// magnet - remove and delete are the same thing
_manager.deleteMagnet(snark);
if (snark instanceof FetchAndAdd)
_manager.addMessage(_t("Download deleted: {0}", name));
else
_manager.addMessage(_t("Magnet deleted: {0}", name));
return;
}
File f = new File(name);
File dd = _manager.getDataDir();
boolean canDelete = dd.canWrite() || !f.exists();
_manager.stopTorrent(snark, canDelete);
// TODO race here with the DirMonitor, could get re-added
if (f.delete()) {
_manager.addMessage(_t("Torrent file deleted: {0}", f.getAbsolutePath()));
} else if (f.exists()) {
if (!canDelete)
_manager.addMessage(_t("No write permissions for data directory") + ": " + dd);
_manager.addMessage(_t("Torrent file could not be deleted: {0}", f.getAbsolutePath()));
return;
}
Storage storage = snark.getStorage();
if (storage == null)
break;
List<List<String>> files = meta.getFiles();
if (files == null) {
// single file torrent
for (File df : storage.getFiles()) {
// should be only one
if (df.delete())
_manager.addMessage(_t("Data file deleted: {0}", df.getAbsolutePath()));
else if (df.exists())
_manager.addMessage(_t("Data file could not be deleted: {0}", df.getAbsolutePath()));
// else already gone
}
break;
}
// step 1 delete files
for (File df : storage.getFiles()) {
if (df.delete()) {
// _manager.addMessage(_t("Data file deleted: {0}", df.getAbsolutePath()));
} else if (df.exists()) {
_manager.addMessage(_t("Data file could not be deleted: {0}", df.getAbsolutePath()));
// else already gone
}
}
// step 2 delete dirs bottom-up
Set<File> dirs = storage.getDirectories();
if (dirs == null)
// directory deleted out from under us
break;
if (_log.shouldLog(Log.INFO))
_log.info("Dirs to delete: " + DataHelper.toString(dirs));
boolean ok = false;
for (File df : dirs) {
if (df.delete()) {
ok = true;
// _manager.addMessage(_t("Data dir deleted: {0}", df.getAbsolutePath()));
} else if (df.exists()) {
ok = false;
_manager.addMessage(_t("Directory could not be deleted: {0}", df.getAbsolutePath()));
if (_log.shouldLog(Log.WARN))
_log.warn("Could not delete dir " + df);
// else already gone
}
}
// step 3 message for base (last one)
if (ok)
_manager.addMessage(_t("Directory deleted: {0}", storage.getBase()));
break;
}
}
}
}
} else if ("Save".equals(action)) {
String dataDir = req.getParameter("nofilter_dataDir");
boolean filesPublic = req.getParameter("filesPublic") != null;
boolean autoStart = req.getParameter("autoStart") != null;
boolean smartSort = req.getParameter("smartSort") != null;
String seedPct = req.getParameter("seedPct");
String eepHost = req.getParameter("eepHost");
String eepPort = req.getParameter("eepPort");
String i2cpHost = req.getParameter("i2cpHost");
String i2cpPort = req.getParameter("i2cpPort");
String i2cpOpts = buildI2CPOpts(req);
String upLimit = req.getParameter("upLimit");
String upBW = req.getParameter("upBW");
String refreshDel = req.getParameter("refreshDelay");
String startupDel = req.getParameter("startupDelay");
String pageSize = req.getParameter("pageSize");
boolean useOpenTrackers = req.getParameter("useOpenTrackers") != null;
boolean useDHT = req.getParameter("useDHT") != null;
// String openTrackers = req.getParameter("openTrackers");
String theme = req.getParameter("theme");
String lang = req.getParameter("lang");
boolean ratings = req.getParameter("ratings") != null;
boolean comments = req.getParameter("comments") != null;
// commentsName is filtered in SnarkManager.updateConfig()
String commentsName = req.getParameter("nofilter_commentsName");
boolean collapsePanels = req.getParameter("collapsePanels") != null;
_manager.updateConfig(dataDir, filesPublic, autoStart, smartSort, refreshDel, startupDel, pageSize, seedPct, eepHost, eepPort, i2cpHost, i2cpPort, i2cpOpts, upLimit, upBW, useOpenTrackers, useDHT, theme, lang, ratings, comments, commentsName, collapsePanels);
// update servlet
try {
setResourceBase(_manager.getDataDir());
} catch (ServletException se) {
}
} else if ("Save2".equals(action)) {
String taction = req.getParameter("taction");
if (taction != null)
processTrackerForm(taction, req);
} else if ("Create".equals(action)) {
String baseData = req.getParameter("nofilter_baseFile");
if (baseData != null && baseData.trim().length() > 0) {
File baseFile = new File(baseData.trim());
if (!baseFile.isAbsolute())
baseFile = new File(_manager.getDataDir(), baseData);
String announceURL = req.getParameter("announceURL");
if (baseFile.exists()) {
File dd = _manager.getDataDir();
if (!dd.canWrite()) {
_manager.addMessage(_t("No write permissions for data directory") + ": " + dd);
return;
}
String torrentName = baseFile.getName();
if (torrentName.toLowerCase(Locale.US).endsWith(".torrent")) {
_manager.addMessage(_t("Cannot add a torrent ending in \".torrent\": {0}", baseFile.getAbsolutePath()));
return;
}
Snark snark = _manager.getTorrentByBaseName(torrentName);
if (snark != null) {
_manager.addMessage(_t("Torrent with this name is already running: {0}", torrentName));
return;
}
if (isParentOf(baseFile, _manager.getDataDir()) || isParentOf(baseFile, _manager.util().getContext().getBaseDir()) || isParentOf(baseFile, _manager.util().getContext().getConfigDir())) {
_manager.addMessage(_t("Cannot add a torrent including an I2P directory: {0}", baseFile.getAbsolutePath()));
return;
}
Collection<Snark> snarks = _manager.getTorrents();
for (Snark s : snarks) {
Storage storage = s.getStorage();
if (storage == null)
continue;
File sbase = storage.getBase();
if (isParentOf(sbase, baseFile)) {
_manager.addMessage(_t("Cannot add torrent {0} inside another torrent: {1}", baseFile.getAbsolutePath(), sbase));
return;
}
if (isParentOf(baseFile, sbase)) {
_manager.addMessage(_t("Cannot add torrent {0} including another torrent: {1}", baseFile.getAbsolutePath(), sbase));
return;
}
}
if (announceURL.equals("none"))
announceURL = null;
_lastAnnounceURL = announceURL;
List<String> backupURLs = new ArrayList<String>();
Enumeration<?> e = req.getParameterNames();
while (e.hasMoreElements()) {
Object o = e.nextElement();
if (!(o instanceof String))
continue;
String k = (String) o;
if (k.startsWith("backup_")) {
String url = k.substring(7);
if (!url.equals(announceURL))
backupURLs.add(DataHelper.stripHTML(url));
}
}
List<List<String>> announceList = null;
if (!backupURLs.isEmpty()) {
// BEP 12 - Put primary first, then the others, each as the sole entry in their own list
if (announceURL == null) {
_manager.addMessage(_t("Error - Cannot include alternate trackers without a primary tracker"));
return;
}
backupURLs.add(0, announceURL);
boolean hasPrivate = false;
boolean hasPublic = false;
for (String url : backupURLs) {
if (_manager.getPrivateTrackers().contains(url))
hasPrivate = true;
else
hasPublic = true;
}
if (hasPrivate && hasPublic) {
_manager.addMessage(_t("Error - Cannot mix private and public trackers in a torrent"));
return;
}
announceList = new ArrayList<List<String>>(backupURLs.size());
for (String url : backupURLs) {
announceList.add(Collections.singletonList(url));
}
}
try {
// This may take a long time to check the storage, but since it already exists,
// it shouldn't be THAT bad, so keep it in this thread.
// TODO thread it for big torrents, perhaps a la FetchAndAdd
boolean isPrivate = _manager.getPrivateTrackers().contains(announceURL);
Storage s = new Storage(_manager.util(), baseFile, announceURL, announceList, null, isPrivate, null);
// close the files... maybe need a way to pass this Storage to addTorrent rather than starting over
s.close();
MetaInfo info = s.getMetaInfo();
File torrentFile = new File(_manager.getDataDir(), s.getBaseName() + ".torrent");
// FIXME is the storage going to stay around thanks to the info reference?
// now add it, but don't automatically start it
boolean ok = _manager.addTorrent(info, s.getBitField(), torrentFile.getAbsolutePath(), baseFile, true);
if (!ok)
return;
_manager.addMessage(_t("Torrent created for \"{0}\"", baseFile.getName()) + ": " + torrentFile.getAbsolutePath());
if (announceURL != null && !_manager.util().getOpenTrackers().contains(announceURL))
_manager.addMessage(_t("Many I2P trackers require you to register new torrents before seeding - please do so before starting \"{0}\"", baseFile.getName()));
} catch (IOException ioe) {
_manager.addMessage(_t("Error creating a torrent for \"{0}\"", baseFile.getAbsolutePath()) + ": " + ioe);
_log.error("Error creating a torrent", ioe);
}
} else {
_manager.addMessage(_t("Cannot create a torrent for the nonexistent data: {0}", baseFile.getAbsolutePath()));
}
} else {
_manager.addMessage(_t("Error creating torrent - you must enter a file or directory"));
}
} else if ("StopAll".equals(action)) {
_manager.stopAllTorrents(false);
} else if ("StartAll".equals(action)) {
_manager.startAllTorrents();
} else if ("Clear".equals(action)) {
String sid = req.getParameter("id");
if (sid != null) {
try {
int id = Integer.parseInt(sid);
_manager.clearMessages(id);
} catch (NumberFormatException nfe) {
}
}
} else {
_manager.addMessage("Unknown POST action: \"" + action + '\"');
}
}
Aggregations