Search in sources :

Example 1 with MetaInfo

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("&amp;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("&amp;tr=").append(announce);
            buf.append("\">").append(MagnetURI.MAGNET_FULL).append(hex);
            if (announce != null)
                buf.append("&amp;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>&nbsp;<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>&nbsp;<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("&#8239;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>&nbsp;<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>&nbsp;<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>&nbsp;<span>");
            toThemeImg(buf, "file");
            buf.append("<b>").append(_t("Files")).append(":</b> ").append(fileCount);
        }
        buf.append("</span>&nbsp;<span>");
        toThemeImg(buf, "file");
        buf.append("<b>").append(_t("Pieces")).append(":</b> ").append(pieces);
        buf.append("</span>&nbsp;<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("&hellip; ").append((new DecimalFormat("0.00%")).format(snark.getCheckingProgress())).append("&nbsp;<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("&hellip;</b>");
            } else if (snark.isAllocating()) {
                buf.append("<b>").append(_t("Allocating")).append("&hellip;</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("&nbsp;");
        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();
}
Also used : DecimalFormat(java.text.DecimalFormat) MetaInfo(org.klomp.snark.MetaInfo) ArrayList(java.util.ArrayList) List(java.util.List) ArrayList(java.util.ArrayList) Date(java.util.Date) Storage(org.klomp.snark.Storage) Snark(org.klomp.snark.Snark) SecureFile(net.i2p.util.SecureFile) File(java.io.File) SimpleDateFormat(java.text.SimpleDateFormat)

Example 2 with MetaInfo

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)) + "&hellip;";
    // 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("&nbsp;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 + "&amp;nonce=" + _nonce + getQueryString(req, "", null, null).replace("?", "&amp;") + "\"><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 + "&amp;nonce=" + _nonce + getQueryString(req, "", null, null).replace("?", "&amp;") + "\"><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 + "&amp;nonce=" + _nonce + getQueryString(req, "", null, null).replace("?", "&amp;") + "\"><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 + "&amp;nonce=" + _nonce + getQueryString(req, "", null, null).replace("?", "&amp;") + "\"><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 + "&nbsp;<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>");
        }
    }
}
Also used : DecimalFormat(java.text.DecimalFormat) Peer(org.klomp.snark.Peer) MetaInfo(org.klomp.snark.MetaInfo) Date(java.util.Date) SimpleDateFormat(java.text.SimpleDateFormat) PeerID(org.klomp.snark.PeerID)

Example 3 with MetaInfo

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 + '\"');
    }
}
Also used : Enumeration(java.util.Enumeration) SecureFile(net.i2p.util.SecureFile) MetaInfo(org.klomp.snark.MetaInfo) ArrayList(java.util.ArrayList) IOException(java.io.IOException) ServletException(javax.servlet.ServletException) Storage(org.klomp.snark.Storage) Collection(java.util.Collection) Snark(org.klomp.snark.Snark) List(java.util.List) ArrayList(java.util.ArrayList) SecureFile(net.i2p.util.SecureFile) File(java.io.File)

Aggregations

MetaInfo (org.klomp.snark.MetaInfo)3 File (java.io.File)2 DecimalFormat (java.text.DecimalFormat)2 SimpleDateFormat (java.text.SimpleDateFormat)2 ArrayList (java.util.ArrayList)2 Date (java.util.Date)2 List (java.util.List)2 SecureFile (net.i2p.util.SecureFile)2 Snark (org.klomp.snark.Snark)2 Storage (org.klomp.snark.Storage)2 IOException (java.io.IOException)1 Collection (java.util.Collection)1 Enumeration (java.util.Enumeration)1 ServletException (javax.servlet.ServletException)1 Peer (org.klomp.snark.Peer)1 PeerID (org.klomp.snark.PeerID)1