use of org.klomp.snark.Storage 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.Storage in project i2p.i2p by i2p.
the class I2PSnarkServlet method savePriorities.
/**
* @since 0.8.1
*/
private void savePriorities(Snark snark, Map<String, String[]> postParams) {
Storage storage = snark.getStorage();
if (storage == null)
return;
for (Map.Entry<String, String[]> entry : postParams.entrySet()) {
String key = entry.getKey();
if (key.startsWith("pri.")) {
try {
int fileIndex = Integer.parseInt(key.substring(4));
// jetty arrays
String val = entry.getValue()[0];
int pri = Integer.parseInt(val);
storage.setPriority(fileIndex, pri);
// System.err.println("Priority now " + pri + " for " + file);
} catch (Throwable t) {
t.printStackTrace();
}
}
}
snark.updatePiecePriorities();
_manager.saveTorrentStatus(snark);
}
use of org.klomp.snark.Storage 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 + '\"');
}
}
use of org.klomp.snark.Storage in project i2p.i2p by i2p.
the class I2PSnarkServlet method getResource.
/**
* We override this to set the file relative to the storage dirctory
* for the torrent.
*
* @param pathInContext should always start with /
*/
@Override
public File getResource(String pathInContext) {
if (pathInContext == null || pathInContext.equals("/") || pathInContext.equals("/index.jsp") || !pathInContext.startsWith("/") || pathInContext.length() == 0 || pathInContext.equals("/index.html") || pathInContext.startsWith(WARBASE))
return super.getResource(pathInContext);
// files in the i2psnark/ directory
// get top level
pathInContext = pathInContext.substring(1);
File top = new File(pathInContext);
File parent;
while ((parent = top.getParentFile()) != null) {
top = parent;
}
Snark snark = _manager.getTorrentByBaseName(top.getPath());
if (snark != null) {
Storage storage = snark.getStorage();
if (storage != null) {
File sbase = storage.getBase();
String child = pathInContext.substring(top.getPath().length());
return new File(sbase, child);
}
}
return new File(_resourceBase, pathInContext);
}
Aggregations