forked from I2P_Developers/i2p.i2p
Compare commits
1 Commits
i2p-2.6.1
...
i2p-androi
Author | SHA1 | Date | |
---|---|---|---|
0e8e8480ea |
@ -29,4 +29,3 @@ installer/build
|
||||
router/java/build
|
||||
router/build
|
||||
|
||||
override.properties
|
98
.github/workflows/ant.yml
vendored
98
.github/workflows/ant.yml
vendored
@ -5,11 +5,6 @@ name: Java CI
|
||||
|
||||
on: [push]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
@ -17,9 +12,9 @@ jobs:
|
||||
steps:
|
||||
- name: GetText
|
||||
run: sudo apt install gettext
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK 8
|
||||
uses: actions/setup-java@v4
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: '8'
|
||||
distribution: 'temurin'
|
||||
@ -31,92 +26,9 @@ jobs:
|
||||
- name: build with Ant
|
||||
run: ant distclean pkg
|
||||
- name: Upload installer.jar
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: I2P-install-${{ github.sha }}.jar
|
||||
name: I2P-install.jar-${{ github.sha }}
|
||||
path: install.jar
|
||||
|
||||
|
||||
javadoc-latest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v4
|
||||
- name: GetText
|
||||
run: sudo apt install gettext
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
- name : Generate override.properties
|
||||
run: |
|
||||
rm -f override.properties
|
||||
echo "build.built-by=GitHub Actions" >> override.properties
|
||||
echo "noExe=true" >> override.properties
|
||||
- name: test Debian build with Ant
|
||||
run: ant distclean
|
||||
- name: build javadoc with Ant
|
||||
run: ant distclean javadoc updater
|
||||
- name: zip javadoc
|
||||
run: cp i2pupdate.zip build/javadoc/i2pupdate.zip && zip -r javadoc.zip build/javadoc
|
||||
- name: Upload javadoc.zip
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: I2P-javadoc-${{ github.sha }}.zip
|
||||
path: javadoc.zip
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
# Upload javadocs to github page
|
||||
path: 'build/javadoc'
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
|
||||
build-java7:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: GetText
|
||||
run: sudo apt install gettext
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK 8
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '8'
|
||||
distribution: 'temurin'
|
||||
- name : Generate override.properties
|
||||
run: |
|
||||
git clone https://github.com/eyedeekay/openjdk-7 "$HOME/openjdk-7"
|
||||
rm -f override.properties
|
||||
echo "build.built-by=GitHub Actions" >> override.properties
|
||||
echo "noExe=true" >> override.properties
|
||||
echo "javac.compilerargs=-bootclasspath $HOME/openjdk-7/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar:$HOME/openjdk-7/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/jce.jar -Xlint:all" >> override.properties
|
||||
- name: build Maven dev build with Ant
|
||||
run: ./installer/resources/maven-dev-release.sh 1
|
||||
- name: Upload servlet-i2p.jar
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: servlet-i2p-${{ github.sha }}.jar
|
||||
path: pkg-mavencentral/servlet-i2p*.jar
|
||||
- name: Upload streaming.jar
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: streaming-${{ github.sha }}.jar
|
||||
path: pkg-mavencentral/streaming*.jar
|
||||
- name: Upload mstreaming.jar
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: mstreaming-${{ github.sha }}.jar
|
||||
path: pkg-mavencentral/mstreaming*.jar
|
||||
- name: Upload router.jar
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: router-${{ github.sha }}.jar
|
||||
path: pkg-mavencentral/router*.jar
|
||||
- name: Upload i2p.jar
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: i2p-${{ github.sha }}.jar
|
||||
path: pkg-mavencentral/i2p*.jar
|
||||
|
23
.github/workflows/github-sync.yml
vendored
23
.github/workflows/github-sync.yml
vendored
@ -1,23 +0,0 @@
|
||||
# File: .github/workflows/repo-sync.yml
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "*/5 * * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
repo-sync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: repo-sync
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
uses: repo-sync/github-sync@v2
|
||||
with:
|
||||
source_repo: "https://i2pgit.org/i2p-hackers/i2p.i2p"
|
||||
source_branch: "master"
|
||||
destination_branch: "master"
|
||||
github_token: ${{ secrets.PAT }}
|
65
.github/workflows/mirror-release.yml
vendored
65
.github/workflows/mirror-release.yml
vendored
@ -1,65 +0,0 @@
|
||||
name: mirror
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'i2p-*.*.*'
|
||||
|
||||
jobs:
|
||||
dl:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: |
|
||||
changelog.txt
|
||||
- name: download release artifacts
|
||||
run: |
|
||||
sudo apt-get install wget ca-certificates gpg sed curl git
|
||||
git pull --tags
|
||||
while true; do sleep 60m; wget -v https://files.i2p-projekt.de/$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||')/i2pinstall_$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||')_windows.exe && break; done
|
||||
wget -v https://files.i2p-projekt.de/$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||')/I2P-Easy-Install-Bundle-$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||')-signed.exe
|
||||
wget -v https://files.i2p-projekt.de/$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||')/I2P-Easy-Install-Bundle-$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||').exe
|
||||
wget -v https://files.i2p-projekt.de/$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||')/i2pinstall_$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||').jar
|
||||
wget -v https://files.i2p-projekt.de/$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||')/i2pinstall_$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||').jar.sig
|
||||
wget -v https://files.i2p-projekt.de/$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||')/i2pinstall_$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||')_windows.exe
|
||||
wget -v https://files.i2p-projekt.de/$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||')/i2pinstall_$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||')_windows.exe.sig
|
||||
wget -v https://files.i2p-projekt.de/$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||')/i2psource_$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||').tar.bz2
|
||||
wget -v https://files.i2p-projekt.de/$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||')/i2psource_$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||').tar.bz2.sig
|
||||
wget -v https://files.i2p-projekt.de/$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||')/i2pupdate-$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||').su3
|
||||
wget -v https://files.i2p-projekt.de/$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||')/i2pupdate-$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||').su3.torrent
|
||||
wget -v https://files.i2p-projekt.de/$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||')/i2pupdate.su3
|
||||
wget -v https://files.i2p-projekt.de/$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||')/i2pupdate_$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||').zip
|
||||
wget -v https://files.i2p-projekt.de/$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||')/i2pupdate_$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||').zip.sig'
|
||||
echo "$(git describe --abbrev=0 | sed 's|i2p-||g' |sed 's|-.*||')" > CHANGES.md
|
||||
echo "===========" >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
curl https://raw.githubusercontent.com/i2p/i2p.newsxml/master/data/entries.html | sed -n '/<article/,/<\/article/p' | sed -n '1,/<\/article>/p' | sed -n '/<\/details>/,$p' | sed '1d' | sed 's/<\/\{0,1\}p>//g' | sed 's|<\/article>||g' >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
echo '```' >> CHANGES.md
|
||||
head -n 25 changelog.txt >> CHANGES.md
|
||||
echo '```' >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
echo "## Checksums" >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
echo '```' >> CHANGES.md
|
||||
sha256sum * >> CHANGES.md
|
||||
echo '```' >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
echo '```' >> CHANGES.md
|
||||
file * >> CHANGES.md
|
||||
echo '```' >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
cat CHANGES.md
|
||||
- name: Upload artifacts
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: "*"
|
||||
skipIfReleaseExists: true
|
||||
bodyFile: "CHANGES.md"
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -61,5 +61,3 @@ sloccount.sc
|
||||
|
||||
# TODO: why does this file appear?
|
||||
apps/routerconsole/jsp/favicon.ico
|
||||
.tx
|
||||
/*.sh
|
@ -52,7 +52,6 @@ test:ant:
|
||||
- echo junit.home=/usr/share/java >> override.properties
|
||||
- echo hamcrest.home=/usr/share/java >> override.properties
|
||||
- echo mockito.home=/usr/share/java >> override.properties
|
||||
- echo build.built-by=GitHub Actions >> override.properties
|
||||
script:
|
||||
- ant test
|
||||
only:
|
||||
@ -60,55 +59,19 @@ test:ant:
|
||||
- merge_requests
|
||||
- tags
|
||||
|
||||
test:javadoc:
|
||||
stage: test
|
||||
image: debian:unstable-slim
|
||||
variables:
|
||||
SCALA: https://downloads.lightbend.com/scala/2.12.13/scala-2.12.13.deb
|
||||
LIBPREFIX: /usr/share/scala/lib
|
||||
LIB_SCALATEST: https://repo1.maven.org/maven2/org/scalatest/scalatest_2.12/3.0.4/scalatest_2.12-3.0.4.jar
|
||||
LIB_SCALACTIC: https://repo1.maven.org/maven2/org/scalactic/scalactic_2.12/3.0.4/scalactic_2.12-3.0.4.jar
|
||||
before_script:
|
||||
# Fix bug installing openjdk-11-jdk-headless's manuals
|
||||
- mkdir -p /usr/share/man/man1/
|
||||
- apt-get update -q
|
||||
- apt-get install -y wget gettext
|
||||
ant openjdk-21-jdk-headless
|
||||
libmockito-java libhamcrest-java junit4
|
||||
# Install specific version of scala
|
||||
- wget -qO scala.deb "${SCALA}"
|
||||
- dpkg -i scala.deb
|
||||
# link to the scala libs with the name `ant test` expects
|
||||
- ln -s "${LIBPREFIX}/scala-xml_2.12-1.0.6.jar" "${LIBPREFIX}/scala-xml.jar"
|
||||
# Download required scala libs
|
||||
- wget -qO "${LIBPREFIX}/scalactic.jar" "${LIB_SCALACTIC}"
|
||||
- wget -qO "${LIBPREFIX}/scalatest.jar" "${LIB_SCALATEST}"
|
||||
# Point ant to the right directories
|
||||
- echo scalatest.libs=/usr/share/scala/lib > override.properties
|
||||
- echo junit.home=/usr/share/java >> override.properties
|
||||
- echo hamcrest.home=/usr/share/java >> override.properties
|
||||
- echo mockito.home=/usr/share/java >> override.properties
|
||||
- echo build.built-by=GitHub Actions >> override.properties
|
||||
script:
|
||||
- ant javadoc
|
||||
only:
|
||||
- master
|
||||
- merge_requests
|
||||
- tags
|
||||
|
||||
# Make sure we can build a docker image
|
||||
# It's cached for later jobs
|
||||
build_docker:
|
||||
stage: build
|
||||
image: docker:24.0.7
|
||||
image: docker:19.03.12
|
||||
services:
|
||||
- docker:24.0.7-dind
|
||||
- docker:19.03.12-dind
|
||||
script:
|
||||
# Try to load latest branch image from local tar or from registry
|
||||
- docker load -i ci-exports/$CI_COMMIT_REF_SLUG.tar || docker pull $CI_REGISTRY_IMAGE:latest || true
|
||||
- docker build --cache-from $CI_REGISTRY_IMAGE:latest --tag $CI_REGISTRY_IMAGE:latest .
|
||||
- mkdir -p ci-exports/
|
||||
- echo docker save $CI_REGISTRY_IMAGE:latest > ci-exports/$CI_COMMIT_REF_SLUG.tar
|
||||
- docker save $CI_REGISTRY_IMAGE:latest > ci-exports/$CI_COMMIT_REF_SLUG.tar
|
||||
variables:
|
||||
# When using dind service, we need to instruct docker to talk with
|
||||
# the daemon started inside of the service. The daemon is available
|
||||
@ -126,7 +89,7 @@ build_docker:
|
||||
# container, thanks to volume mount from config.toml
|
||||
DOCKER_TLS_CERTDIR: "/certs"
|
||||
# Use TLS https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#tls-enabled
|
||||
# DOCKER_HOST: tcp://docker:2376
|
||||
DOCKER_HOST: tcp://docker:2376
|
||||
cache:
|
||||
# The same key should be used across branches
|
||||
key: "$CI_COMMIT_REF_SLUG"
|
||||
|
90
.tx/config
90
.tx/config
@ -1,12 +1,7 @@
|
||||
;; warning - conversions for all Java bundles:
|
||||
;; id->in, he->iw, iy, yi->ji
|
||||
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
lang_map = ru_RU: ru, sv_SE: sv, tr_TR: tr, uk_UA: uk, zh_CN: zh, et_EE: et, id: in, he: iw
|
||||
|
||||
[o:otf:p:I2P:r:i2ptunnel]
|
||||
file_filter = apps/i2ptunnel/locale/messages_<lang>.po
|
||||
[I2P.i2ptunnel]
|
||||
source_file = apps/i2ptunnel/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/i2ptunnel/locale/messages_ar.po
|
||||
@ -14,7 +9,6 @@ trans.cs = apps/i2ptunnel/locale/messages_cs.po
|
||||
trans.da = apps/i2ptunnel/locale/messages_da.po
|
||||
trans.de = apps/i2ptunnel/locale/messages_de.po
|
||||
trans.es = apps/i2ptunnel/locale/messages_es.po
|
||||
trans.es_AR = apps/i2ptunnel/locale/messages_es_AR.po
|
||||
trans.fa = apps/i2ptunnel/locale/messages_fa.po
|
||||
trans.fi = apps/i2ptunnel/locale/messages_fi.po
|
||||
trans.fr = apps/i2ptunnel/locale/messages_fr.po
|
||||
@ -41,8 +35,7 @@ trans.vi = apps/i2ptunnel/locale/messages_vi.po
|
||||
trans.zh_CN = apps/i2ptunnel/locale/messages_zh.po
|
||||
trans.zh_TW = apps/i2ptunnel/locale/messages_zh_TW.po
|
||||
|
||||
[o:otf:p:I2P:r:proxy]
|
||||
file_filter = apps/i2ptunnel/locale-proxy/messages_<lang>.po
|
||||
[I2P.proxy]
|
||||
source_file = apps/i2ptunnel/locale-proxy/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/i2ptunnel/locale-proxy/messages_ar.po
|
||||
@ -50,7 +43,6 @@ trans.cs = apps/i2ptunnel/locale-proxy/messages_cs.po
|
||||
trans.de = apps/i2ptunnel/locale-proxy/messages_de.po
|
||||
trans.el = apps/i2ptunnel/locale-proxy/messages_el.po
|
||||
trans.es = apps/i2ptunnel/locale-proxy/messages_es.po
|
||||
trans.es_AR = apps/i2ptunnel/locale-proxy/messages_es_AR.po
|
||||
trans.fa = apps/i2ptunnel/locale-proxy/messages_fa.po
|
||||
trans.fi = apps/i2ptunnel/locale-proxy/messages_fi.po
|
||||
trans.fr = apps/i2ptunnel/locale-proxy/messages_fr.po
|
||||
@ -76,8 +68,7 @@ trans.vi = apps/i2ptunnel/locale-proxy/messages_vi.po
|
||||
trans.zh_CN = apps/i2ptunnel/locale-proxy/messages_zh.po
|
||||
trans.zh_TW = apps/i2ptunnel/locale-proxy/messages_zh_TW.po
|
||||
|
||||
[o:otf:p:I2P:r:core]
|
||||
file_filter = core/locale/messages_<lang>.po
|
||||
[I2P.core]
|
||||
type = PO
|
||||
source_file = core/locale/messages_en.po
|
||||
source_lang = en
|
||||
@ -115,8 +106,7 @@ trans.vi = core/locale/messages_vi.po
|
||||
trans.zh_CN = core/locale/messages_zh.po
|
||||
trans.zh_TW = core/locale/messages_zh_TW.po
|
||||
|
||||
[o:otf:p:I2P:r:router]
|
||||
file_filter = router/locale/messages_<lang>.po
|
||||
[I2P.router]
|
||||
type = PO
|
||||
source_file = router/locale/messages_en.po
|
||||
source_lang = en
|
||||
@ -127,7 +117,6 @@ trans.da = router/locale/messages_da.po
|
||||
trans.de = router/locale/messages_de.po
|
||||
trans.el = router/locale/messages_el.po
|
||||
trans.es = router/locale/messages_es.po
|
||||
trans.es_AR = router/locale/messages_es_AR.po
|
||||
trans.et_EE = router/locale/messages_et.po
|
||||
trans.fa = router/locale/messages_fa.po
|
||||
trans.fi = router/locale/messages_fi.po
|
||||
@ -155,8 +144,7 @@ trans.vi = router/locale/messages_vi.po
|
||||
trans.zh_CN = router/locale/messages_zh.po
|
||||
trans.zh_TW = router/locale/messages_zh_TW.po
|
||||
|
||||
[o:otf:p:I2P:r:routerconsole]
|
||||
file_filter = apps/routerconsole/locale/messages_<lang>.po
|
||||
[I2P.routerconsole]
|
||||
source_file = apps/routerconsole/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/routerconsole/locale/messages_ar.po
|
||||
@ -166,7 +154,6 @@ trans.da = apps/routerconsole/locale/messages_da.po
|
||||
trans.de = apps/routerconsole/locale/messages_de.po
|
||||
trans.el = apps/routerconsole/locale/messages_el.po
|
||||
trans.es = apps/routerconsole/locale/messages_es.po
|
||||
trans.es_AR = apps/routerconsole/locale/messages_es_AR.po
|
||||
trans.et_EE = apps/routerconsole/locale/messages_et.po
|
||||
trans.fa = apps/routerconsole/locale/messages_fa.po
|
||||
trans.fi = apps/routerconsole/locale/messages_fi.po
|
||||
@ -191,8 +178,7 @@ trans.vi = apps/routerconsole/locale/messages_vi.po
|
||||
trans.zh_CN = apps/routerconsole/locale/messages_zh.po
|
||||
trans.zh_TW = apps/routerconsole/locale/messages_zh_TW.po
|
||||
|
||||
[o:otf:p:I2P:r:welcome]
|
||||
file_filter = apps/routerconsole/locale-news/messages_<lang>.po
|
||||
[I2P.welcome]
|
||||
source_file = apps/routerconsole/locale-news/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/routerconsole/locale-news/messages_ar.po
|
||||
@ -201,7 +187,6 @@ trans.cs = apps/routerconsole/locale-news/messages_cs.po
|
||||
trans.de = apps/routerconsole/locale-news/messages_de.po
|
||||
trans.el = apps/routerconsole/locale-news/messages_el.po
|
||||
trans.es = apps/routerconsole/locale-news/messages_es.po
|
||||
trans.es_AR = apps/routerconsole/locale-news/messages_es_AR.po
|
||||
trans.fa = apps/routerconsole/locale-news/messages_fa.po
|
||||
trans.fi = apps/routerconsole/locale-news/messages_fi.po
|
||||
trans.fr = apps/routerconsole/locale-news/messages_fr.po
|
||||
@ -234,8 +219,7 @@ trans.uk_UA = apps/routerconsole/locale-news/messages_uk.po
|
||||
trans.zh_CN = apps/routerconsole/locale-news/messages_zh.po
|
||||
trans.zh_TW = apps/routerconsole/locale-news/messages_zh_TW.po
|
||||
|
||||
[o:otf:p:I2P:r:countries]
|
||||
file_filter = apps/routerconsole/locale-countries/messages_<lang>.po
|
||||
[I2P.countries]
|
||||
type = PO
|
||||
source_file = apps/routerconsole/locale-countries/messages_en.po
|
||||
source_lang = en
|
||||
@ -248,7 +232,6 @@ trans.da = apps/routerconsole/locale-countries/messages_da.po
|
||||
trans.de = apps/routerconsole/locale-countries/messages_de.po
|
||||
trans.el = apps/routerconsole/locale-countries/messages_el.po
|
||||
trans.es = apps/routerconsole/locale-countries/messages_es.po
|
||||
trans.es_AR = apps/routerconsole/locale-countries/messages_es_AR.po
|
||||
trans.et_EE = apps/routerconsole/locale-countries/messages_et.po
|
||||
trans.fa = apps/routerconsole/locale-countries/messages_fa.po
|
||||
trans.fi = apps/routerconsole/locale-countries/messages_fi.po
|
||||
@ -285,17 +268,14 @@ trans.vi = apps/routerconsole/locale-countries/messages_vi.po
|
||||
trans.zh_CN = apps/routerconsole/locale-countries/messages_zh.po
|
||||
trans.zh_TW = apps/routerconsole/locale-countries/messages_zh_TW.po
|
||||
|
||||
[o:otf:p:I2P:r:i2psnark]
|
||||
file_filter = apps/i2psnark/locale/messages_<lang>.po
|
||||
[I2P.i2psnark]
|
||||
source_file = apps/i2psnark/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/i2psnark/locale/messages_ar.po
|
||||
trans.cs = apps/i2psnark/locale/messages_cs.po
|
||||
trans.da = apps/i2psnark/locale/messages_da.po
|
||||
trans.de = apps/i2psnark/locale/messages_de.po
|
||||
trans.el = apps/i2psnark/locale/messages_el.po
|
||||
trans.es = apps/i2psnark/locale/messages_es.po
|
||||
trans.es_AR = apps/i2psnark/locale/messages_es_AR.po
|
||||
trans.fa = apps/i2psnark/locale/messages_fa.po
|
||||
trans.fi = apps/i2psnark/locale/messages_fi.po
|
||||
trans.fr = apps/i2psnark/locale/messages_fr.po
|
||||
@ -321,8 +301,7 @@ trans.vi = apps/i2psnark/locale/messages_vi.po
|
||||
trans.zh_CN = apps/i2psnark/locale/messages_zh.po
|
||||
trans.zh_TW = apps/i2psnark/locale/messages_zh_TW.po
|
||||
|
||||
[o:otf:p:I2P:r:susidns]
|
||||
file_filter = apps/susidns/locale/messages_<lang>.po
|
||||
[I2P.susidns]
|
||||
source_file = apps/susidns/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/susidns/locale/messages_ar.po
|
||||
@ -331,7 +310,6 @@ trans.da = apps/susidns/locale/messages_da.po
|
||||
trans.de = apps/susidns/locale/messages_de.po
|
||||
trans.el = apps/susidns/locale/messages_el.po
|
||||
trans.es = apps/susidns/locale/messages_es.po
|
||||
trans.es_AR = apps/susidns/locale/messages_es_AR.po
|
||||
trans.fa = apps/susidns/locale/messages_fa.po
|
||||
trans.fi = apps/susidns/locale/messages_fi.po
|
||||
trans.fr = apps/susidns/locale/messages_fr.po
|
||||
@ -355,8 +333,7 @@ trans.vi = apps/susidns/locale/messages_vi.po
|
||||
trans.zh_CN = apps/susidns/locale/messages_zh.po
|
||||
trans.zh_TW = apps/susidns/locale/messages_zh_TW.po
|
||||
|
||||
[o:otf:p:I2P:r:desktopgui]
|
||||
file_filter = apps/desktopgui/locale/messages_<lang>.po
|
||||
[I2P.desktopgui]
|
||||
source_file = apps/desktopgui/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/desktopgui/locale/messages_ar.po
|
||||
@ -400,8 +377,7 @@ trans.vi = apps/desktopgui/locale/messages_vi.po
|
||||
trans.zh_CN = apps/desktopgui/locale/messages_zh.po
|
||||
trans.zh_TW = apps/desktopgui/locale/messages_zh_TW.po
|
||||
|
||||
[o:otf:p:I2P:r:susimail]
|
||||
file_filter = apps/susimail/locale/messages_<lang>.po
|
||||
[I2P.susimail]
|
||||
source_file = apps/susimail/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/susimail/locale/messages_ar.po
|
||||
@ -413,8 +389,6 @@ trans.da = apps/susimail/locale/messages_da.po
|
||||
trans.de = apps/susimail/locale/messages_de.po
|
||||
trans.el = apps/susimail/locale/messages_el.po
|
||||
trans.es = apps/susimail/locale/messages_es.po
|
||||
trans.es_AR = apps/susimail/locale/messages_es_AR.po
|
||||
trans.et_EE = apps/susimail/locale/messages_et.po
|
||||
trans.fa = apps/susimail/locale/messages_fa.po
|
||||
trans.fi = apps/susimail/locale/messages_fi.po
|
||||
trans.fr = apps/susimail/locale/messages_fr.po
|
||||
@ -428,7 +402,6 @@ trans.id = apps/susimail/locale/messages_in.po
|
||||
trans.it = apps/susimail/locale/messages_it.po
|
||||
trans.ja = apps/susimail/locale/messages_ja.po
|
||||
trans.ko = apps/susimail/locale/messages_ko.po
|
||||
trans.ku = apps/susimail/locale/messages_ku.po
|
||||
trans.mg = apps/susimail/locale/messages_mg.po
|
||||
trans.nb = apps/susimail/locale/messages_nb.po
|
||||
trans.nl = apps/susimail/locale/messages_nl.po
|
||||
@ -438,7 +411,6 @@ trans.pt_BR = apps/susimail/locale/messages_pt_BR.po
|
||||
trans.ro = apps/susimail/locale/messages_ro.po
|
||||
trans.ru_RU = apps/susimail/locale/messages_ru.po
|
||||
trans.sk = apps/susimail/locale/messages_sk.po
|
||||
trans.sl = apps/susimail/locale/messages_sl.po
|
||||
trans.sq = apps/susimail/locale/messages_sq.po
|
||||
trans.sr = apps/susimail/locale/messages_sr.po
|
||||
trans.sv_SE = apps/susimail/locale/messages_sv.po
|
||||
@ -448,8 +420,7 @@ trans.vi = apps/susimail/locale/messages_vi.po
|
||||
trans.zh_CN = apps/susimail/locale/messages_zh.po
|
||||
trans.zh_TW = apps/susimail/locale/messages_zh_TW.po
|
||||
|
||||
[o:otf:p:I2P:r:debconf]
|
||||
file_filter = debian/po/<lang>.po
|
||||
[I2P.debconf]
|
||||
source_file = debian/po/templates.pot
|
||||
source_lang = en
|
||||
trans.ar = debian/po/ar.po
|
||||
@ -458,7 +429,6 @@ trans.cs = debian/po/cs.po
|
||||
trans.de = debian/po/de.po
|
||||
trans.el = debian/po/el.po
|
||||
trans.es = debian/po/es.po
|
||||
trans.es_AR = debian/po/es_AR.po
|
||||
trans.fi = debian/po/fi.po
|
||||
trans.fr = debian/po/fr.po
|
||||
trans.gl = debian/po/gl.po
|
||||
@ -484,20 +454,16 @@ trans.uk_UA = debian/po/uk.po
|
||||
trans.zh_CN = debian/po/zh.po
|
||||
trans.zh_TW = debian/po/zh_TW.po
|
||||
|
||||
[o:otf:p:I2P:r:i2prouter-script]
|
||||
file_filter = installer/resources/locale/po/messages_<lang>.po
|
||||
[I2P.i2prouter-script]
|
||||
source_file = installer/resources/locale/po/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = installer/resources/locale/po/messages_ar.po
|
||||
trans.az = installer/resources/locale/po/messages_az.po
|
||||
trans.ca = installer/resources/locale/po/messages_ca.po
|
||||
trans.cs = installer/resources/locale/po/messages_cs.po
|
||||
trans.de = installer/resources/locale/po/messages_de.po
|
||||
trans.es = installer/resources/locale/po/messages_es.po
|
||||
trans.es_AR = installer/resources/locale/po/messages_es_AR.po
|
||||
trans.fi = installer/resources/locale/po/messages_fi.po
|
||||
trans.fr = installer/resources/locale/po/messages_fr.po
|
||||
trans.hu = installer/resources/locale/po/messages_hu.po
|
||||
trans.id = installer/resources/locale/po/messages_id.po
|
||||
trans.it = installer/resources/locale/po/messages_it.po
|
||||
trans.ja = installer/resources/locale/po/messages_ja.po
|
||||
@ -516,7 +482,7 @@ trans.uk_UA = installer/resources/locale/po/messages_uk.po
|
||||
trans.zh_CN = installer/resources/locale/po/messages_zh.po
|
||||
trans.zh_TW = installer/resources/locale/po/messages_zh_TW.po
|
||||
|
||||
[o:otf:p:I2P:r:getopt]
|
||||
[I2P.getopt]
|
||||
;;
|
||||
;; Java properties files (when not read with our DataHelper methods) must be ISO-8859-1 encoded.
|
||||
;; See https://docs.oracle.com/javase/6/docs/api/java/util/Properties.html
|
||||
@ -533,7 +499,6 @@ trans.zh_TW = installer/resources/locale/po/messages_zh_TW.po
|
||||
;; and should be escaped using native2ascii after downloading:
|
||||
;; gl, pt, pt_BR, sq, sv, tr
|
||||
;;
|
||||
file_filter = core/java/src/gnu/getopt/MessagesBundle_<lang>.properties
|
||||
source_file = core/java/src/gnu/getopt/MessagesBundle.properties
|
||||
source_lang = en
|
||||
type = PROPERTIES
|
||||
@ -542,7 +507,6 @@ trans.az = core/java/src/gnu/getopt/MessagesBundle_az.properties
|
||||
trans.cs = core/java/src/gnu/getopt/MessagesBundle_cs.properties
|
||||
trans.de = core/java/src/gnu/getopt/MessagesBundle_de.properties
|
||||
trans.es = core/java/src/gnu/getopt/MessagesBundle_es.properties
|
||||
trans.es_AR = core/java/src/gnu/getopt/MessagesBundle_es_AR.properties
|
||||
trans.fi = core/java/src/gnu/getopt/MessagesBundle_fi.properties
|
||||
trans.fr = core/java/src/gnu/getopt/MessagesBundle_fr.properties
|
||||
trans.gl = core/java/src/gnu/getopt/MessagesBundle_gl.properties
|
||||
@ -570,8 +534,7 @@ trans.uk_UA = core/java/src/gnu/getopt/MessagesBundle_uk.properties
|
||||
trans.zh_CN = core/java/src/gnu/getopt/MessagesBundle_zh.properties
|
||||
trans.zh_TW = core/java/src/gnu/getopt/MessagesBundle_zh_TW.properties
|
||||
|
||||
[o:otf:p:I2P:r:streaming]
|
||||
file_filter = apps/ministreaming/locale/messages_<lang>.po
|
||||
[I2P.streaming]
|
||||
source_file = apps/ministreaming/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/ministreaming/locale/messages_ar.po
|
||||
@ -580,7 +543,6 @@ trans.ca = apps/ministreaming/locale/messages_ca.po
|
||||
trans.cs = apps/ministreaming/locale/messages_cs.po
|
||||
trans.de = apps/ministreaming/locale/messages_de.po
|
||||
trans.es = apps/ministreaming/locale/messages_es.po
|
||||
trans.es_AR = apps/ministreaming/locale/messages_es_AR.po
|
||||
trans.fa = apps/ministreaming/locale/messages_fa.po
|
||||
trans.fi = apps/ministreaming/locale/messages_fi.po
|
||||
trans.fr = apps/ministreaming/locale/messages_fr.po
|
||||
@ -589,7 +551,6 @@ trans.hu = apps/ministreaming/locale/messages_hu.po
|
||||
;; Java converts id to in
|
||||
trans.id = apps/ministreaming/locale/messages_in.po
|
||||
trans.it = apps/ministreaming/locale/messages_it.po
|
||||
trans.ja = apps/ministreaming/locale/messages_ja.po
|
||||
trans.ko = apps/ministreaming/locale/messages_ko.po
|
||||
trans.nb = apps/ministreaming/locale/messages_nb.po
|
||||
trans.nl = apps/ministreaming/locale/messages_nl.po
|
||||
@ -606,12 +567,11 @@ trans.uk_UA = apps/ministreaming/locale/messages_uk.po
|
||||
trans.zh_CN = apps/ministreaming/locale/messages_zh.po
|
||||
trans.zh_TW = apps/ministreaming/locale/messages_zh_TW.po
|
||||
|
||||
[o:otf:p:I2P:r:manpages]
|
||||
[I2P.manpages]
|
||||
;;
|
||||
;; after adding languages here, add to debian/*.manpages also
|
||||
;; You must run installer/resources/poupdate-man.sh first.
|
||||
;;
|
||||
file_filter = installer/resources/locale-man/man_<lang>.po
|
||||
type = PO
|
||||
source_file = installer/resources/locale-man/man.pot
|
||||
source_lang = en
|
||||
@ -619,7 +579,6 @@ trans.ar = installer/resources/locale-man/man_ar.po
|
||||
trans.az = installer/resources/locale-man/man_az.po
|
||||
trans.de = installer/resources/locale-man/man_de.po
|
||||
trans.es = installer/resources/locale-man/man_es.po
|
||||
trans.es_AR = installer/resources/locale-man/man_es_AR.po
|
||||
trans.fi = installer/resources/locale-man/man_fi.po
|
||||
trans.fr = installer/resources/locale-man/man_fr.po
|
||||
trans.hu = installer/resources/locale-man/man_hu.po
|
||||
@ -638,13 +597,12 @@ trans.tr_TR = installer/resources/locale-man/man_tr.po
|
||||
trans.zh_CN = installer/resources/locale-man/man_zh.po
|
||||
trans.zh_TW = installer/resources/locale-man/man_zh_TW.po
|
||||
|
||||
[o:otf:p:I2P:r:eepsite]
|
||||
[I2P.eepsite]
|
||||
;;
|
||||
;; For any new translations, add links in installer/resources/eepsite/docroot/help/index.html
|
||||
;; and copy new flags in build.xml copyflags-unlesspkg target,
|
||||
;; and add to debian/i2p-router.links and debian-alt/*/i2p-router.links
|
||||
;;
|
||||
file_filter = installer/resources/eepsite/docroot/help/index_<lang>.po
|
||||
type = HTML
|
||||
source_file = installer/resources/eepsite/docroot/help/index.html
|
||||
source_lang = en
|
||||
@ -654,14 +612,14 @@ source_lang = en
|
||||
trans.az = installer/resources/eepsite/docroot/help/index_az.html
|
||||
trans.de = installer/resources/eepsite/docroot/help/index_de.html
|
||||
trans.el = installer/resources/eepsite/docroot/help/index_el.html
|
||||
trans.es = installer/resources/eepsite/docroot/help/index_es.html
|
||||
;; not yet translated on TX, use old page
|
||||
;;trans.es = installer/resources/eepsite/docroot/help/index_es.html
|
||||
trans.fa = installer/resources/eepsite/docroot/help/index_fa.html
|
||||
trans.fr = installer/resources/eepsite/docroot/help/index_fr.html
|
||||
trans.hu = installer/resources/eepsite/docroot/help/index_hu.html
|
||||
;; Java converts id to in
|
||||
trans.id = installer/resources/eepsite/docroot/help/index_in.html
|
||||
trans.it = installer/resources/eepsite/docroot/help/index_it.html
|
||||
trans.ja = installer/resources/eepsite/docroot/help/index_ja.html
|
||||
;; not yet translated on TX, use old page
|
||||
;;trans.nl = installer/resources/eepsite/docroot/help/index_nl.html
|
||||
trans.pl = installer/resources/eepsite/docroot/help/index_pl.html
|
||||
@ -673,19 +631,14 @@ trans.tr_TR = installer/resources/eepsite/docroot/help/index_tr.html
|
||||
trans.uk_UA = installer/resources/eepsite/docroot/help/index_uk.html
|
||||
trans.zh_CN = installer/resources/eepsite/docroot/help/index_zh.html
|
||||
|
||||
[o:otf:p:I2P:r:readme]
|
||||
[I2P.readme]
|
||||
;;
|
||||
;; Text on /console
|
||||
;;
|
||||
;; NOTE: No support for country suffixes right now.
|
||||
;; See ResourceHelper.java
|
||||
;;
|
||||
file_filter = apps/routerconsole/resources/docs/readme_<lang>.html
|
||||
type = HTML
|
||||
source_file = apps/routerconsole/resources/docs/readme.html
|
||||
source_lang = en
|
||||
trans.ar = apps/routerconsole/resources/docs/readme_ar.html
|
||||
trans.cs = apps/routerconsole/resources/docs/readme_cs.html
|
||||
trans.de = apps/routerconsole/resources/docs/readme_de.html
|
||||
trans.fr = apps/routerconsole/resources/docs/readme_fr.html
|
||||
trans.hu = apps/routerconsole/resources/docs/readme_hu.html
|
||||
@ -703,3 +656,6 @@ trans.uk_UA = apps/routerconsole/resources/docs/readme_uk.html
|
||||
trans.zh_CN = apps/routerconsole/resources/docs/readme_zh.html
|
||||
trans.zh_TW = apps/routerconsole/resources/docs/readme_zh_TW.html
|
||||
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
|
||||
|
33
Docker.md
33
Docker.md
@ -10,12 +10,7 @@ version: "3.5"
|
||||
services:
|
||||
i2p:
|
||||
image: geti2p/i2p
|
||||
ports:
|
||||
- 127.0.0.1:4444:4444
|
||||
- 127.0.0.1:6668:6668
|
||||
- 127.0.0.1:7657:7657
|
||||
- 54321:12345
|
||||
- 54321:12345/udp
|
||||
network_mode: host
|
||||
volumes:
|
||||
- ./i2pconfig:/i2p/.i2p
|
||||
- ./i2ptorrents:/i2psnark
|
||||
@ -28,22 +23,11 @@ Note that this quick-start approach is not recommended for production deployment
|
||||
### Building an image
|
||||
There is an i2P image available over at [DockerHub](https://hub.docker.com). If you do not want to use that one, you can build one yourself:
|
||||
```
|
||||
docker build -t geti2p/i2p .
|
||||
docker build -t i2p .
|
||||
```
|
||||
|
||||
### Running a container
|
||||
|
||||
#### Environment Variables
|
||||
|
||||
It is possible to set the IP address where the I2P router is accessible by setting
|
||||
the `IP_ADDR` environment variable in your `docker run` command or your `docker-compose`
|
||||
file. For example, if you want to make your I2P router listen on all addresses, then
|
||||
you should pass `-e IP_ADDR=0.0.0.0` to your `docker run` command.
|
||||
|
||||
It is also possible to configure the memory available to the I2P router using
|
||||
environment variables. To do this, use the: `JVM_XMX` environment variable by passing,
|
||||
for example, `-e JVM_XMX=256m`.
|
||||
|
||||
#### Volumes
|
||||
The container requires a volume for the configuration data to be mounted. Optionally, you can mount a separate volume for torrent ("i2psnark") downloads. See the example below.
|
||||
|
||||
@ -75,19 +59,16 @@ A best-practices guide for cloud deployments is beyond the scope of this documen
|
||||
|
||||
#### Example
|
||||
Here is an example container that mounts `i2phome` as home directory, `i2ptorrents` for torrents, and opens HTTP Proxy, IRC, Router Console and I2NP Protocols. It also limits the memory available to the JVM to 256MB.
|
||||
|
||||
```
|
||||
docker build -t geti2p/i2p .
|
||||
# I2NP port needs TCP and UDP. Change the 54321 to something random, greater than 1024.
|
||||
docker run \
|
||||
-e JVM_XMX=256m \
|
||||
-v i2phome:/i2p/.i2p \
|
||||
-v i2ptorrents:/i2psnark \
|
||||
-p 127.0.0.1:4444:4444 \
|
||||
-p 127.0.0.1:6668:6668 \
|
||||
-p 127.0.0.1:7657:7657 \
|
||||
-p 4444:4444 \
|
||||
-p 6668:6668 \
|
||||
-p 7657:7657 \
|
||||
-p 54321:12345 \
|
||||
-p 54321:12345/udp \
|
||||
geti2p/i2p:latest
|
||||
-p 54321:12345/udp \ # I2NP port needs TCP and UDP. Change the 54321 to something random, greater than 1024.
|
||||
i2p:latest
|
||||
```
|
||||
|
||||
|
16
Dockerfile
16
Dockerfile
@ -1,27 +1,24 @@
|
||||
FROM alpine:3.17.1 as builder
|
||||
FROM jlesage/baseimage:alpine-3.15-glibc as builder
|
||||
|
||||
ENV APP_HOME="/i2p"
|
||||
|
||||
WORKDIR /tmp/build
|
||||
COPY . .
|
||||
|
||||
RUN apk add --virtual build-base gettext tar bzip2 apache-ant openjdk17 \
|
||||
&& echo "build.built-by=Docker" >> override.properties \
|
||||
RUN add-pkg --virtual build-base gettext tar bzip2 apache-ant openjdk8 \
|
||||
&& ant preppkg-linux-only \
|
||||
&& rm -rf pkg-temp/osid pkg-temp/lib/wrapper pkg-temp/lib/wrapper.* \
|
||||
&& apk del build-base gettext tar bzip2 apache-ant openjdk17
|
||||
&& del-pkg build-base gettext tar bzip2 apache-ant openjdk8
|
||||
|
||||
FROM alpine:3.17.1
|
||||
FROM jlesage/baseimage:alpine-3.15-glibc
|
||||
ENV APP_HOME="/i2p"
|
||||
|
||||
RUN apk add openjdk17-jre ttf-dejavu
|
||||
|
||||
RUN add-pkg openjdk8-jre
|
||||
WORKDIR ${APP_HOME}
|
||||
COPY --from=builder /tmp/build/pkg-temp .
|
||||
|
||||
# "install" i2p by copying over installed files
|
||||
COPY --chown=root:root docker/rootfs/ /
|
||||
RUN chmod +x /startapp.sh
|
||||
COPY docker/rootfs/ /
|
||||
|
||||
# Mount home and snark
|
||||
VOLUME ["${APP_HOME}/.i2p"]
|
||||
@ -37,4 +34,3 @@ LABEL \
|
||||
org.label-schema.vcs-url="https://github.com/i2p/i2p.i2p" \
|
||||
org.label-schema.schema-version="1.0"
|
||||
|
||||
ENTRYPOINT ["/startapp.sh"]
|
||||
|
21
LICENSE.txt
21
LICENSE.txt
@ -267,7 +267,7 @@ Applications:
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
See licenses/LICENSE-ECLIPSE-1.0.html
|
||||
|
||||
RRD4J 3.10 (jrobin.jar):
|
||||
RRD4J 3.8 (jrobin.jar):
|
||||
Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor.
|
||||
Copyright (c) 2011 The OpenNMS Group, Inc.
|
||||
Copyright 2011 The RRD4J Authors.
|
||||
@ -316,10 +316,6 @@ Applications:
|
||||
See licenses/LICENSE-NDT.txt
|
||||
Notice: I2P has changed specified portions of the Software, including the package edu.internet2.ndt.
|
||||
|
||||
Router Console Iframe-resizer 4.3.9:
|
||||
Copyright (c) 2013-2023 David J. Bradshaw
|
||||
See licenses/LICENSE-Iframe-resizer.txt
|
||||
|
||||
SAM (sam.jar):
|
||||
Public domain.
|
||||
|
||||
@ -336,19 +332,12 @@ Applications:
|
||||
GPLv2 (or any later version)
|
||||
See licenses/LICENSE-GPLv2.txt
|
||||
|
||||
SusiMail Pagedown:
|
||||
Original Markdown Copyright (c) 2004-2005 John Gruber
|
||||
Original Showdown code copyright (c) 2007 John Fraser
|
||||
Modifications and bugfixes (c) 2009 Dana Robinson
|
||||
Modifications and bugfixes (c) 2009-2014 Stack Exchange Inc.
|
||||
See licenses/LICENSE-pagedown.txt
|
||||
|
||||
Systray (systray.jar):
|
||||
Public domain.
|
||||
|
||||
Tomcat 9.0.88 (jasper-runtime.jar):
|
||||
Tomcat 9.0.62 (jasper-runtime.jar):
|
||||
(not included in most distribution packages)
|
||||
Copyright 1999-2024 The Apache Software Foundation
|
||||
Copyright 1999-2022 The Apache Software Foundation
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
See licenses/NOTICE-Tomcat.txt
|
||||
|
||||
@ -362,7 +351,7 @@ distributions. See the source package for the additional license information.
|
||||
Admin Manager:
|
||||
Public domain
|
||||
|
||||
Gradle wrapper 8.5:
|
||||
Gradle wrapper 5.2.1:
|
||||
(not included in most distribution packages)
|
||||
Copyright (c) 2023 the original author or authors.
|
||||
Copyright (c) 2017 the original author or authors.
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
|
@ -9,7 +9,6 @@
|
||||
<property name="javac.compilerargs" value="" />
|
||||
<property name="javac.version" value="1.8" />
|
||||
<property name="javac.release" value="8" />
|
||||
<property name="manifest.classpath.name" value="Class-Path" />
|
||||
|
||||
<target name="all" depends="jar, emptyWar"/>
|
||||
|
||||
@ -58,14 +57,8 @@
|
||||
<property name="workspace.changes.tr" value="" />
|
||||
<jar basedir="${build}" destfile="${dist}/${jar}">
|
||||
<manifest>
|
||||
<attribute name="${manifest.classpath.name}" value="i2p.jar" />
|
||||
<attribute name="Main-Class" value="net.i2p.addressbook.CommandLine"/>
|
||||
<attribute name="Specification-Title" value="I2P Address Book" />
|
||||
<attribute name="Specification-Version" value="${api.version}" />
|
||||
<attribute name="Specification-Vendor" value="The I2P Project https://geti2p.net/" />
|
||||
<attribute name="Implementation-Title" value="I2P Java Address Book" />
|
||||
<attribute name="Main-Class" value="net.i2p.addressbook.Daemon"/>
|
||||
<attribute name="Implementation-Version" value="${full.version}" />
|
||||
<attribute name="Implementation-Vendor" value="The I2P Project https://geti2p.net/" />
|
||||
<attribute name="Built-By" value="${build.built-by}" />
|
||||
<attribute name="Build-Date" value="${build.timestamp}" />
|
||||
<attribute name="Base-Revision" value="${workspace.version}" />
|
||||
@ -84,36 +77,28 @@
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<!-- actually the jar -->
|
||||
<target name="warUpToDate">
|
||||
<uptodate property="war.uptodate" targetfile="${dist}/${jar}">
|
||||
<srcfiles dir= "." includes="${build}/**/*.class"/>
|
||||
<uptodate property="war.uptodate" targetfile="${dist}/${war}">
|
||||
<srcfiles dir= "." includes="${build}/**/*.class, web.xml"/>
|
||||
</uptodate>
|
||||
<condition property="shouldListChanges" >
|
||||
<and>
|
||||
<not>
|
||||
<isset property="war.uptodate" />
|
||||
</not>
|
||||
<isset property="git.available" />
|
||||
<isset property="mtn.available" />
|
||||
</and>
|
||||
</condition>
|
||||
</target>
|
||||
|
||||
<target name="changes" depends="warUpToDate" if="shouldListChanges" >
|
||||
<exec executable="git" outputproperty="workspace.changes" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="status" />
|
||||
<arg value="-s" />
|
||||
<arg value="--porcelain" />
|
||||
<arg value="-uno" />
|
||||
<arg value="." />
|
||||
</exec>
|
||||
<!-- trim flags -->
|
||||
<exec executable="sed" inputstring="${workspace.changes}" outputproperty="workspace.changes.sed" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="-e" />
|
||||
<arg value="s/^[MTADRCU ]*//" />
|
||||
</exec>
|
||||
<exec executable="mtn" outputproperty="workspace.changes" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="list" />
|
||||
<arg value="changed" />
|
||||
<arg value="." />
|
||||
</exec>
|
||||
<!-- \n in an attribute value generates an invalid manifest -->
|
||||
<exec executable="tr" inputstring="${workspace.changes.sed}" outputproperty="workspace.changes.tr" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<exec executable="tr" inputstring="${workspace.changes}" outputproperty="workspace.changes.tr" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="-s" />
|
||||
<arg value="[:space:]" />
|
||||
<arg value="," />
|
||||
|
@ -136,17 +136,9 @@ class AddressBook implements Iterable<Map.Entry<String, HostTxtEntry>> {
|
||||
File tmp = null;
|
||||
try {
|
||||
tmp = SecureFile.createTempFile("addressbook", null, I2PAppContext.getGlobalContext().getTempDir());
|
||||
// Apache 2.4 mod_deflate etag bug workaround
|
||||
// strip -gzip from the etag
|
||||
// Gitlab #454
|
||||
String loc = subscription.getLocation();
|
||||
String etag = subscription.getEtag();
|
||||
if (loc.startsWith("http://i2p-projekt.i2p/") && etag != null && etag.endsWith("-gzip\""))
|
||||
etag = etag.substring(0, etag.length() - 6) + '"';
|
||||
|
||||
EepGet get = new EepGet(I2PAppContext.getGlobalContext(), true,
|
||||
proxyHost, proxyPort, 0, -1l, MAX_SUB_SIZE, tmp.getAbsolutePath(), null,
|
||||
loc, true, etag, subscription.getLastModified(), null);
|
||||
subscription.getLocation(), true, subscription.getEtag(), subscription.getLastModified(), null);
|
||||
if (get.fetch()) {
|
||||
subscription.setEtag(get.getETag());
|
||||
subscription.setLastModified(get.getLastModified());
|
||||
|
@ -1,42 +0,0 @@
|
||||
package net.i2p.addressbook;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.CoreVersion;
|
||||
|
||||
/**
|
||||
* Simple command line access to various utilities.
|
||||
* Not a public API. Subject to change.
|
||||
* Apps and plugins should use specific classes.
|
||||
*
|
||||
* @since 0.9.55
|
||||
*/
|
||||
public class CommandLine extends net.i2p.util.CommandLine {
|
||||
|
||||
protected static final List<String> ACLASSES = Arrays.asList(new String[] {
|
||||
"net.i2p.addressbook.HostTxtParser",
|
||||
"net.i2p.router.naming.BlockfileNamingService",
|
||||
"net.metanotion.io.block.BlockFile",
|
||||
});
|
||||
|
||||
protected CommandLine() {}
|
||||
|
||||
public static void main(String args[]) {
|
||||
List<String> classes = new ArrayList<String>(ACLASSES.size() + CLASSES.size());
|
||||
classes.addAll(ACLASSES);
|
||||
classes.addAll(CLASSES);
|
||||
if (args.length > 0) {
|
||||
exec(args, classes);
|
||||
}
|
||||
usage(classes);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
private static void usage(List<String> classes) {
|
||||
System.err.println("I2P Address book version " + CoreVersion.VERSION + '\n' +
|
||||
"USAGE: java -jar /path/to/addressbook.jar command [args]");
|
||||
printCommands(classes);
|
||||
}
|
||||
}
|
@ -697,7 +697,7 @@ class Daemon {
|
||||
StringBuilder buf = new StringBuilder(16);
|
||||
final int sz = dests.size();
|
||||
for (int i = 0; i < sz; i++) {
|
||||
buf.append(dests.get(i).toBase64(), 0, 6);
|
||||
buf.append(dests.get(i).toBase64().substring(0, 6));
|
||||
if (i != sz - 1)
|
||||
buf.append(", ");
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ import java.util.Properties;
|
||||
|
||||
import net.i2p.client.naming.HostTxtEntry;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.SecureFile;
|
||||
import net.i2p.util.SecureFileOutputStream;
|
||||
import net.i2p.util.SystemVersion;
|
||||
@ -26,9 +25,9 @@ import net.i2p.util.SystemVersion;
|
||||
* Utility class providing methods to parse and write files in a hosts.txt file
|
||||
* format, and subscription file format.
|
||||
*
|
||||
* @since 0.9.26 modified from ConfigParser, public since 0.9.55 for CLI
|
||||
* @since 0.9.26 modified from ConfigParser
|
||||
*/
|
||||
public class HostTxtParser {
|
||||
class HostTxtParser {
|
||||
|
||||
private static final boolean isWindows = SystemVersion.isWindows();
|
||||
|
||||
@ -256,23 +255,8 @@ public class HostTxtParser {
|
||||
System.exit(2);
|
||||
}
|
||||
if (!e.hasValidSig()) {
|
||||
if (!quiet) {
|
||||
System.err.println("Bad signature for " + e.getName());
|
||||
String dest = e.getDest();
|
||||
try {
|
||||
Destination d = new Destination(dest);
|
||||
System.err.println(dest);
|
||||
System.err.println(d.toString());
|
||||
} catch (Exception ex) {
|
||||
System.err.println("Invalid destination: " + dest);
|
||||
}
|
||||
Properties p = e.getProps();
|
||||
if (p != null) {
|
||||
for (Map.Entry<?,?> m : p.entrySet()) {
|
||||
System.err.println(m.getKey() + "=" + m.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!quiet)
|
||||
System.err.println("Bad signature");
|
||||
System.exit(3);
|
||||
}
|
||||
Properties p = e.getProps();
|
||||
@ -282,30 +266,14 @@ public class HostTxtParser {
|
||||
p.containsKey(HostTxtEntry.PROP_OLDNAME) ||
|
||||
p.containsKey(HostTxtEntry.PROP_OLDSIG)) {
|
||||
if (!e.hasValidSig()) {
|
||||
if (!quiet) {
|
||||
System.err.println("Bad inner signature for " + e.getName());
|
||||
for (Map.Entry<?,?> m : p.entrySet()) {
|
||||
System.err.println(m.getKey() + "=" + m.getValue());
|
||||
}
|
||||
}
|
||||
if (!quiet)
|
||||
System.err.println("Bad inner signature");
|
||||
System.exit(4);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!quiet) {
|
||||
if (!quiet)
|
||||
System.err.println("Good signature for " + e.getName());
|
||||
try {
|
||||
String dest = e.getDest();
|
||||
Destination d = new Destination(dest);
|
||||
System.err.println(dest);
|
||||
System.err.println(d.toString());
|
||||
} catch (Exception ex) {}
|
||||
if (p != null) {
|
||||
for (Map.Entry<?,?> m : p.entrySet()) {
|
||||
System.err.println(m.getKey() + "=" + m.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
|
@ -23,14 +23,11 @@ package net.i2p.addressbook;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.Date;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.SecureFileOutputStream;
|
||||
|
||||
/**
|
||||
* A simple log with automatic time stamping.
|
||||
*
|
||||
@ -60,9 +57,9 @@ class Log {
|
||||
public void append(String entry) {
|
||||
BufferedWriter bw = null;
|
||||
try {
|
||||
bw = new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(this.file,
|
||||
bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(this.file,
|
||||
true), "UTF-8"));
|
||||
String timestamp = DataHelper.formatTime(I2PAppContext.getGlobalContext().clock().now());
|
||||
String timestamp = new Date().toString();
|
||||
bw.write(timestamp + " -- " + entry);
|
||||
bw.newLine();
|
||||
} catch (IOException exp) {
|
||||
|
@ -762,10 +762,6 @@ public class BlockfileNamingService extends DummyNamingService {
|
||||
*/
|
||||
@Override
|
||||
public Destination lookup(String hostname, Properties lookupOptions, Properties storedOptions) {
|
||||
if (hostname.endsWith(".i2p.alt")) {
|
||||
// RFC 9476
|
||||
hostname = hostname.substring(0, hostname.length() - 4);
|
||||
}
|
||||
Destination rv = lookup2(hostname, lookupOptions, storedOptions);
|
||||
if (rv == null) {
|
||||
// if hostname starts with "www.", strip and try again
|
||||
@ -1435,8 +1431,6 @@ public class BlockfileNamingService extends DummyNamingService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Broken prior to 0.9.62, would only return one name.
|
||||
*
|
||||
* @param options If non-null and contains the key "list", get
|
||||
* from that list (default "hosts.txt", NOT all lists)
|
||||
* Key "skip": skip that many entries
|
||||
@ -1508,7 +1502,6 @@ public class BlockfileNamingService extends DummyNamingService {
|
||||
break;
|
||||
}
|
||||
}
|
||||
iter.next();
|
||||
if (search != null && key.indexOf(search) < 0)
|
||||
continue;
|
||||
rv.add(key);
|
||||
|
@ -1,8 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
The BlockfileNamingService based on the Metanotion BlockFile Database.
|
||||
This is the default NamingService for the router.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
@ -1,7 +1,3 @@
|
||||
plugins {
|
||||
id 'java-library'
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
@ -12,10 +8,10 @@ sourceSets {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api project(':core')
|
||||
api project(':router')
|
||||
api project(':installer')
|
||||
api project(':apps:systray')
|
||||
compile project(':core')
|
||||
compile project(':router')
|
||||
compile project(':installer')
|
||||
compile project(':apps:systray')
|
||||
}
|
||||
|
||||
// Create the java files from the po files. The jar task will compile them.
|
||||
|
@ -64,24 +64,17 @@
|
||||
</target>
|
||||
|
||||
<target name="listChangedFiles" depends="jarUpToDate" if="shouldListChanges" >
|
||||
<exec executable="git" outputproperty="workspace.changes" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="status" />
|
||||
<arg value="-s" />
|
||||
<arg value="--porcelain" />
|
||||
<arg value="-uno" />
|
||||
<arg value="." />
|
||||
</exec>
|
||||
<!-- trim flags -->
|
||||
<exec executable="sed" inputstring="${workspace.changes}" outputproperty="workspace.changes.sed" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="-e" />
|
||||
<arg value="s/^[MTADRCU ]*//" />
|
||||
</exec>
|
||||
<!-- \n in an attribute value generates an invalid manifest -->
|
||||
<exec executable="tr" inputstring="${workspace.changes.sed}" outputproperty="workspace.changes.tr" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="-s" />
|
||||
<arg value="[:space:]" />
|
||||
<arg value="," />
|
||||
</exec>
|
||||
<exec executable="mtn" outputproperty="workspace.changes" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="list" />
|
||||
<arg value="changed" />
|
||||
<arg value="." />
|
||||
</exec>
|
||||
<!-- \n in an attribute value generates an invalid manifest -->
|
||||
<exec executable="tr" inputstring="${workspace.changes}" outputproperty="workspace.changes.tr" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="-s" />
|
||||
<arg value="[:space:]" />
|
||||
<arg value="," />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="jar" depends="compile, bundle, listChangedFiles" unless="jar.uptodate" >
|
||||
@ -115,7 +108,7 @@
|
||||
<not>
|
||||
<isset property="jar.uptodate" />
|
||||
</not>
|
||||
<isset property="git.available" />
|
||||
<isset property="mtn.available" />
|
||||
</and>
|
||||
</condition>
|
||||
</target>
|
||||
|
@ -7,15 +7,14 @@
|
||||
# blabla <blabla@trash-mail.com>, 2011
|
||||
# Ettore Atalan <atalanttore@googlemail.com>, 2016
|
||||
# foo <foo@bar>, 2009
|
||||
# Georg Stadler, 2022
|
||||
# Lars Schimmer <echelon@i2pmail.org>, 2016
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-02-09 19:13+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: Georg Stadler, 2022\n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-06-30 21:32+0000\n"
|
||||
"Last-Translator: Lars Schimmer <echelon@i2pmail.org>\n"
|
||||
"Language-Team: German (http://www.transifex.com/otf/I2P/language/de/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@ -30,81 +29,69 @@ msgstr "I2P starten"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P startet gerade!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr "Startend"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "I2P-Browser öffnen"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "I2P System Tray konfigurieren"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:87
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
|
||||
msgid "Enable notifications"
|
||||
msgstr "Benachrichtigungen aktivieren"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Deaktivieren"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:101
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:285
|
||||
msgid "Disable notifications"
|
||||
msgstr "Benachrichtigungen deaktivieren"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:115
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:299
|
||||
msgid "Disable system tray"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:131
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
msgid "Restart I2P"
|
||||
msgstr "I2P neustarten"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
msgid "Stop I2P"
|
||||
msgstr "I2P beenden"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:164
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:348
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "I2P sofort neustarten"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:181
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "I2P sofort beenden"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:195
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:379
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Herunterfahren von I2P abbrechen"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Herunterfahren in {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Herunterfahren bevorstehend"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:444
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
msgid "Network"
|
||||
msgstr "Netzwerk"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:73
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P: Rechtsklick für Menü"
|
||||
|
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P desktopgui\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-03-06 14:52+0000\n"
|
||||
"POT-Creation-Date: 2022-02-09 19:13+0000\n"
|
||||
"PO-Revision-Date: 2010-06-15 14:09+0100\n"
|
||||
"Last-Translator: duck <duck@mail.i2p>\n"
|
||||
"Language-Team: duck <duck@mail.i2p>\n"
|
||||
@ -19,84 +19,87 @@ msgstr ""
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
msgid "Start I2P"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:221
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:242
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:88
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:244
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:87
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
|
||||
msgid "Enable notifications"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:101
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:285
|
||||
msgid "Disable notifications"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:115
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:299
|
||||
msgid "Disable system tray"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:104
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:260
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:131
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
|
||||
msgid "Restart I2P"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:121
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:277
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
|
||||
msgid "Stop I2P"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:137
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:293
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:164
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:348
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:154
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:181
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:168
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:324
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:195
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:379
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:381
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:383
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
|
||||
msgid "Shutdown imminent"
|
||||
msgstr ""
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:388
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:444
|
||||
msgid "Network"
|
||||
msgstr ""
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:75
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:73
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:347
|
||||
msgid "Enable notifications"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:325
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:362
|
||||
msgid "Disable notifications"
|
||||
msgstr ""
|
||||
|
@ -6,22 +6,21 @@
|
||||
# Translators:
|
||||
# ducki2p <ducki2p@gmail.com>, 2011
|
||||
# foo <foo@bar>, 2009
|
||||
# Juan Jaramillo <juanda097@protonmail.ch>, 2022
|
||||
# punkibastardo <transifex.symons@slmail.me>, 2011
|
||||
# punkibastardo <punkibastardo@gmail.com>, 2011
|
||||
# strel, 2016
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-02-09 19:13+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: Juan Jaramillo <juanda097@protonmail.ch>, 2022\n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-06-30 21:32+0000\n"
|
||||
"Last-Translator: strel\n"
|
||||
"Language-Team: Spanish (http://www.transifex.com/otf/I2P/language/es/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: es\n"
|
||||
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
@ -30,81 +29,69 @@ msgstr "Iniciar I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P está iniciando!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr "Iniciando"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Lanzar navegador I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Configurar la bandeja de sistema de I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:87
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
|
||||
msgid "Enable notifications"
|
||||
msgstr "Activar las notificaciones"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Deshabilitar"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:101
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:285
|
||||
msgid "Disable notifications"
|
||||
msgstr "Desactivar las notificaciones"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:115
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:299
|
||||
msgid "Disable system tray"
|
||||
msgstr "Desactivar la bandeja del sistema"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:131
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
msgid "Restart I2P"
|
||||
msgstr "Reiniciar I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
msgid "Stop I2P"
|
||||
msgstr "Detener I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:164
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:348
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "Reiniciar I2P inmediatamente"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:181
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "Detener I2P inmediatamente"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:195
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:379
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Cancelar el cierre de I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Cierre en {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Cierre inminente"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:444
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
msgid "Network"
|
||||
msgstr "Red"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:73
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P: Clic secundario para menú"
|
||||
|
@ -9,15 +9,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-02-09 19:13+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: kaze kaze <kaze@rlab.be>, 2017\n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-11-16 15:29+0000\n"
|
||||
"Last-Translator: kaze kaze <kaze@rlab.be>\n"
|
||||
"Language-Team: Spanish (Argentina) (http://www.transifex.com/otf/I2P/language/es_AR/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: es_AR\n"
|
||||
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
@ -26,81 +26,69 @@ msgstr "Iniciando I2P..."
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P esta iniciando!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr "Iniciando"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Lanzar el Navegador I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Configurar la Bandeja de Sistema de I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:87
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
|
||||
msgid "Enable notifications"
|
||||
msgstr "Activar las notificaciones"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Deshabilitar"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:101
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:285
|
||||
msgid "Disable notifications"
|
||||
msgstr "Desactivar las notificaciones"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:115
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:299
|
||||
msgid "Disable system tray"
|
||||
msgstr "Desactivar la bandeja del sistema"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:131
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
msgid "Restart I2P"
|
||||
msgstr "Riniciar I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
msgid "Stop I2P"
|
||||
msgstr "Detener I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:164
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:348
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr " Reiniciar I2P inmediatamente "
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:181
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr " Detener I2P inmediatamente "
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:195
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:379
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Cancelar el Apagado de I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Apagar en {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Apagado inminente"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:444
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
msgid "Network"
|
||||
msgstr "Red"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:73
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P Clic derecho para el menú"
|
||||
|
@ -13,20 +13,19 @@
|
||||
# AO <ao@localizationlab.org>, 2017
|
||||
# Boxoa590, 2013
|
||||
# Towinet, 2016
|
||||
# vex vex, 2022
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-02-09 19:13+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: vex vex, 2022\n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2019-12-03 16:10+0000\n"
|
||||
"Last-Translator: AO <ao@localizationlab.org>\n"
|
||||
"Language-Team: French (http://www.transifex.com/otf/I2P/language/fr/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: fr\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
@ -35,81 +34,69 @@ msgstr "Démarrer I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P démarre !"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr "Démarrage"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Lancer le navigateur d’I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Configurer la zone de notification d’I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:87
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
|
||||
msgid "Enable notifications"
|
||||
msgstr "Activer les notifications"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Désactiver"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:101
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:285
|
||||
msgid "Disable notifications"
|
||||
msgstr "Désactiver les notifications"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:115
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:299
|
||||
msgid "Disable system tray"
|
||||
msgstr "Désactiver la zone de notification"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:131
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
msgid "Restart I2P"
|
||||
msgstr "Redémarrer I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
msgid "Stop I2P"
|
||||
msgstr "Arrêter I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:164
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:348
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "Redémarrer I2P immédiatement"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:181
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "Arrêter I2P immédiatement"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:195
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:379
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Annuler la fermeture d’I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Fermeture dans {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "La fermeture est imminente"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:444
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
msgid "Network"
|
||||
msgstr "Réseau"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:73
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P : clic droit pour obtenir le menu"
|
||||
|
@ -5,14 +5,13 @@
|
||||
#
|
||||
# Translators:
|
||||
# Hunor Paksy <heds@cock.li>, 2018
|
||||
# vargaviktor <viktor.varga@gmail.com>, 2022
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-02-09 19:13+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: vargaviktor <viktor.varga@gmail.com>, 2022\n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2021-06-20 09:44+0000\n"
|
||||
"Last-Translator: AdminLMH <lehetmashogy@i2pmail.org>\n"
|
||||
"Language-Team: Hungarian (http://www.transifex.com/otf/I2P/language/hu/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@ -27,81 +26,69 @@ msgstr "I2P indítása"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P indul!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr "indítás"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "I2P Böngésző Indítása"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "I2P rendszertálca beállítások"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:87
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
|
||||
msgid "Enable notifications"
|
||||
msgstr "Értesítések engedélyezése"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Kikapcsol"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:101
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:285
|
||||
msgid "Disable notifications"
|
||||
msgstr "Értesítések tiltása"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:115
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:299
|
||||
msgid "Disable system tray"
|
||||
msgstr "Tálcaikon letiltása"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:131
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
msgid "Restart I2P"
|
||||
msgstr "I2P Újraindítása"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
msgid "Stop I2P"
|
||||
msgstr "I2P Leállítása"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:164
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:348
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "I2P Azonnali újraindítása"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:181
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "I2P Azonnali megállítása"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:195
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:379
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "I2P leállításának visszavonása"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Kikapcsolás: {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Kikapcsolás hamarosan"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:444
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
msgid "Network"
|
||||
msgstr "Hálózat"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:73
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P: Jobb-klikk a menüért"
|
||||
|
@ -4,17 +4,16 @@
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
# Adrian Achyar, 2024
|
||||
# Khairul Agasta <khairuldroids@gmail.com>, 2014
|
||||
# Robert Dafis <robertdafis@gmail.com>, 2017
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-03-06 14:52+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: Adrian Achyar, 2024\n"
|
||||
"Language-Team: Indonesian (http://app.transifex.com/otf/I2P/language/id/)\n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-07-27 00:14+0000\n"
|
||||
"Last-Translator: Robert Dafis <robertdafis@gmail.com>\n"
|
||||
"Language-Team: Indonesian (http://www.transifex.com/otf/I2P/language/id/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
@ -22,84 +21,75 @@ msgstr ""
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
msgid "Start I2P"
|
||||
msgstr "Mulai I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P sudah memulai!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "Starting"
|
||||
msgstr "Memulai"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:221
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Luncurkan Peramban I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:242
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Ubah pengaturan I2P System Tray"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:88
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:244
|
||||
msgid "Disable system tray"
|
||||
msgstr "Nonaktifkan system tray"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Matikan"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:104
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:260
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
msgid "Restart I2P"
|
||||
msgstr "Mulai ulang I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:121
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:277
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
msgid "Stop I2P"
|
||||
msgstr "Hentikan I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:137
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:293
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "Ulang kembali I2P sekarang"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:154
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "Hentikan I2P sekarang"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:168
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:324
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Batal tutup I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:381
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Mematikan I2P dalam {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:383
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "I2P sedang dalam proses dimatikan"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:388
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
msgid "Network"
|
||||
msgstr "Jaringan"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:75
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P: klik kanan untuk menampilkan menu"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:347
|
||||
msgid "Enable notifications"
|
||||
msgstr "Aktifkan notifikasi"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:325
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:362
|
||||
msgid "Disable notifications"
|
||||
msgstr "Nonaktifkan notifikasi"
|
||||
|
@ -8,101 +8,91 @@
|
||||
# mkkid <jokjok@hotmail.it>, 2011
|
||||
# Leelium <bovas85@gmail.com>, 2012
|
||||
# mkkid <jokjok@hotmail.it>, 2011
|
||||
# SebastianoPistore <SebastianoPistore.info@protonmail.ch>, 2016-2017
|
||||
# V 41bis, 2023
|
||||
# Sebastiano Pistore <SebastianoPistore.info@protonmail.ch>, 2016-2017
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-03-06 14:52+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: V 41bis, 2023\n"
|
||||
"Language-Team: Italian (http://app.transifex.com/otf/I2P/language/it/)\n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-07-30 07:04+0000\n"
|
||||
"Last-Translator: Sebastiano Pistore <SebastianoPistore.info@protonmail.ch>\n"
|
||||
"Language-Team: Italian (http://www.transifex.com/otf/I2P/language/it/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: it\n"
|
||||
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
msgid "Start I2P"
|
||||
msgstr "Avvia I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "I2P is starting!"
|
||||
msgstr "Avvio di I2P in corso!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "Starting"
|
||||
msgstr "Avvio in corso"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:221
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Lancia il browser I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:242
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Configura icona di I2P nella Barra di notifica"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:88
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:244
|
||||
msgid "Disable system tray"
|
||||
msgstr "Disattiva l'icona nella barra di Notifica"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Disabilita"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:104
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:260
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
msgid "Restart I2P"
|
||||
msgstr "Riavvia I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:121
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:277
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
msgid "Stop I2P"
|
||||
msgstr "Arresta I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:137
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:293
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "Riavvia subito I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:154
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "Arresta subito I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:168
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:324
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Annulla arresto di I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:381
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Arresto in {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:383
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Arresto imminente"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:388
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
msgid "Network"
|
||||
msgstr "Rete"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:75
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P: Fai click destro per aprire il menu"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:347
|
||||
msgid "Enable notifications"
|
||||
msgstr "Attiva le notifiche"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:325
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:362
|
||||
msgid "Disable notifications"
|
||||
msgstr "Disattiva le notifiche"
|
||||
|
@ -6,15 +6,14 @@
|
||||
# Translators:
|
||||
# Allan Nordhøy <epost@anotheragency.no>, 2014
|
||||
# Allan Nordhøy <epost@anotheragency.no>, 2017
|
||||
# Imre Kristoffer Eilertsen <imreeil42@gmail.com>, 2022-2023
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-03-06 14:52+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: Imre Kristoffer Eilertsen <imreeil42@gmail.com>, 2022-2023\n"
|
||||
"Language-Team: Norwegian Bokmål (http://app.transifex.com/otf/I2P/language/nb/)\n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-09-19 14:52+0000\n"
|
||||
"Last-Translator: Allan Nordhøy <epost@anotheragency.no>\n"
|
||||
"Language-Team: Norwegian Bokmål (http://www.transifex.com/otf/I2P/language/nb/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
@ -22,84 +21,75 @@ msgstr ""
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
msgid "Start I2P"
|
||||
msgstr "Start I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P starter opp!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "Starting"
|
||||
msgstr "Starter opp"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:221
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Kjør I2P-nettleser"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:242
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Sett opp I2P-systemkurv"
|
||||
msgstr "Sett opp I2P-systemkruv"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:88
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:244
|
||||
msgid "Disable system tray"
|
||||
msgstr "Skru av systemkurven"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Skru av"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:104
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:260
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
msgid "Restart I2P"
|
||||
msgstr "Omstart av I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:121
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:277
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
msgid "Stop I2P"
|
||||
msgstr "Stopp I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:137
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:293
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "Umiddelbar omstart av I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:154
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "Umiddelbar stopp av I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:168
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:324
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Avbryt nedstenging av I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:381
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Skrur av om {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:383
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Skru av med en gang"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:388
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
msgid "Network"
|
||||
msgstr "Nettverk"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:75
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "Høyreklikk-meny i I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:347
|
||||
msgid "Enable notifications"
|
||||
msgstr "Skru på varsler"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:325
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:362
|
||||
msgid "Disable notifications"
|
||||
msgstr "Skru av varsler"
|
||||
|
@ -6,15 +6,14 @@
|
||||
# Translators:
|
||||
# PolishAnon <b790979@klzlk.com>, 2011
|
||||
# polacco <polacco@i2pmail.org>, 2015
|
||||
# ☆Verdulo, 2016
|
||||
# Waldemar Napora, 2022
|
||||
# Verdulo :-), 2016
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-02-09 19:13+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: Waldemar Napora, 2022\n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-06-30 21:32+0000\n"
|
||||
"Last-Translator: Verdulo :-)\n"
|
||||
"Language-Team: Polish (http://www.transifex.com/otf/I2P/language/pl/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@ -29,81 +28,69 @@ msgstr "Uruchom I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr "Uruchamianie I2P!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr "Uruchamianie"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Uruchom przeglądarkę I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Konfiguruj I2P w zasobniku systemowym"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:87
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
|
||||
msgid "Enable notifications"
|
||||
msgstr "Włącz powiadomenia"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Wyłącz"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:101
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:285
|
||||
msgid "Disable notifications"
|
||||
msgstr "Wyłącz powiadomienia"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:115
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:299
|
||||
msgid "Disable system tray"
|
||||
msgstr "Wyłącz zasobnik systemowy"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:131
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
msgid "Restart I2P"
|
||||
msgstr "Zrestartuj I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
msgid "Stop I2P"
|
||||
msgstr "Zatrzymaj I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:164
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:348
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "Zrestartuj I2P natychmiast"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:181
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "Wyłącz I2P natychmiast"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:195
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:379
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Anuluj zamykanie I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Wyłączenie za {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Zaraz zamknę"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:444
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
msgid "Network"
|
||||
msgstr "Sieć"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:73
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P: kliknij prawym aby otworzyć menu"
|
||||
|
@ -4,102 +4,93 @@
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
# Manuela Silva <mmsrs@sky.com>, 2016
|
||||
# 1c13465e24d91aca4d3ddaa1bc3e7027_ae6ba28, 2013
|
||||
# 1c13465e24d91aca4d3ddaa1bc3e7027_ae6ba28, 2012
|
||||
# Manuela Silva <manuela.silva@sky.com>, 2016
|
||||
# wicked, 2013
|
||||
# wicked, 2012
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-03-06 14:52+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: Manuela Silva <mmsrs@sky.com>, 2016\n"
|
||||
"Language-Team: Portuguese (http://app.transifex.com/otf/I2P/language/pt/)\n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-06-30 21:32+0000\n"
|
||||
"Last-Translator: Manuela Silva <manuela.silva@sky.com>\n"
|
||||
"Language-Team: Portuguese (http://www.transifex.com/otf/I2P/language/pt/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: pt\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
msgid "Start I2P"
|
||||
msgstr "Iniciar I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P está a iniciar!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "Starting"
|
||||
msgstr "A Iniciar"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:221
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Iniciar o browser I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:242
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Configurar Bandeja do Sistema do I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:88
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:244
|
||||
msgid "Disable system tray"
|
||||
msgstr "Desativar bandeja do sistema"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Desativar"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:104
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:260
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
msgid "Restart I2P"
|
||||
msgstr "Reiniciar o I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:121
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:277
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
msgid "Stop I2P"
|
||||
msgstr "Parar o I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:137
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:293
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "Reiniciar o I2P imediatamente"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:154
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "Parar o I2P de imediatamente"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:168
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:324
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Cancelar Encerramento do I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:381
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Encerramento em {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:383
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Encerramento eminente"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:388
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
msgid "Network"
|
||||
msgstr "Rede"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:75
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P: Clique direito para menu"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:347
|
||||
msgid "Enable notifications"
|
||||
msgstr "Ativar notificações"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:325
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:362
|
||||
msgid "Disable notifications"
|
||||
msgstr "Desativar notificações"
|
||||
|
@ -4,105 +4,94 @@
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
# Cauan Henrique Zorzenon <cauanzorzenon@gmail.com>, 2023
|
||||
# testsubject67 <deborinha97@hotmail.com>, 2014
|
||||
# ce4434973f224b33f2ea48f4556be467_f116f03, 2022
|
||||
# L., 2013
|
||||
# L., 2015
|
||||
# blueboy, 2013
|
||||
# blueboy, 2015
|
||||
# Rafael Ferrari, 2016
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-03-06 14:52+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: Cauan Henrique Zorzenon <cauanzorzenon@gmail.com>, 2023\n"
|
||||
"Language-Team: Portuguese (Brazil) (http://app.transifex.com/otf/I2P/language/pt_BR/)\n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-06-30 21:32+0000\n"
|
||||
"Last-Translator: Rafael Ferrari\n"
|
||||
"Language-Team: Portuguese (Brazil) (http://www.transifex.com/otf/I2P/language/pt_BR/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: pt_BR\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
msgid "Start I2P"
|
||||
msgstr "Iniciar I2P"
|
||||
msgstr "Conectar-se à I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "I2P is starting!"
|
||||
msgstr "Conectando-se a I2P!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "Starting"
|
||||
msgstr "Conectando"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:221
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Lançar o navegador I2P "
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:242
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Configurar o ícone de sistema I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:88
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:244
|
||||
msgid "Disable system tray"
|
||||
msgstr "Desativar bandeja do sistema"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Desabilitar"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:104
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:260
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
msgid "Restart I2P"
|
||||
msgstr "Reinicializar o roteador I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:121
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:277
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
msgid "Stop I2P"
|
||||
msgstr "Interromper o roteador I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:137
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:293
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "Reinicializar o I2P Imediatamente"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:154
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "Parar o I2P Imediatamente"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:168
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:324
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Cancelar o desligamento do I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:381
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Desligando em {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:383
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Desligando agora"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:388
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
msgid "Network"
|
||||
msgstr "Rede"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:75
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P: Clique com o botão direito para o menu"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:347
|
||||
msgid "Enable notifications"
|
||||
msgstr "Ativar notificações"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:325
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:362
|
||||
msgid "Disable notifications"
|
||||
msgstr "Desativar notificações"
|
||||
|
@ -9,15 +9,14 @@
|
||||
# foo <foo@bar>, 2009
|
||||
# Foster Snowhill, 2013
|
||||
# brianhopes <voganc-12@live.ru>, 2015
|
||||
# Артём Котлубай <artemkotlubai@yandex.ru>, 2023
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-03-06 14:52+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: Артём Котлубай <artemkotlubai@yandex.ru>, 2023\n"
|
||||
"Language-Team: Russian (Russia) (http://app.transifex.com/otf/I2P/language/ru_RU/)\n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-06-30 21:32+0000\n"
|
||||
"Last-Translator: c4sp3r\n"
|
||||
"Language-Team: Russian (Russia) (http://www.transifex.com/otf/I2P/language/ru_RU/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
@ -25,84 +24,75 @@ msgstr ""
|
||||
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
msgid "Start I2P"
|
||||
msgstr "Запустить I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P запускается!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "Starting"
|
||||
msgstr "Запускается"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:221
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Запустить браузер I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:242
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Настроить область уведомлений"
|
||||
msgstr "Настроить системный трей I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:88
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:244
|
||||
msgid "Disable system tray"
|
||||
msgstr "Убрать значок из области уведомлений"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Отключить"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:104
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:260
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
msgid "Restart I2P"
|
||||
msgstr "Перезапустить I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:121
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:277
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
msgid "Stop I2P"
|
||||
msgstr "Остановить I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:137
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:293
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "Перезапустить I2P немедленно"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:154
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "Остановить I2P немедленно"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:168
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:324
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Отменить выключение I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:381
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Выключение через {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:383
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Неотменяемое выключение"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:388
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
msgid "Network"
|
||||
msgstr "Сеть"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:75
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P: ПКМ для вызова меню"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:347
|
||||
msgid "Enable notifications"
|
||||
msgstr "Включить уведомления"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:325
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:362
|
||||
msgid "Disable notifications"
|
||||
msgstr "Отключить уведомления"
|
||||
msgstr "I2P: Правый щелчок для вызова меню"
|
||||
|
@ -13,9 +13,6 @@ import net.i2p.I2PAppContext;
|
||||
import net.i2p.app.ClientAppManager;
|
||||
import net.i2p.app.ClientApp;
|
||||
import net.i2p.app.ClientAppState;
|
||||
import net.i2p.app.MenuCallback;
|
||||
import net.i2p.app.MenuHandle;
|
||||
import net.i2p.app.MenuService;
|
||||
import net.i2p.app.NotificationService;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SystemVersion;
|
||||
@ -27,7 +24,7 @@ import net.i2p.util.SystemVersion;
|
||||
*
|
||||
* @since 0.9.54
|
||||
*/
|
||||
public class ExternalMain implements ClientApp, NotificationService, MenuService {
|
||||
public class ExternalMain implements ClientApp, NotificationService {
|
||||
|
||||
private final I2PAppContext _appContext;
|
||||
private final ClientAppManager _mgr;
|
||||
@ -63,6 +60,7 @@ public class ExternalMain implements ClientApp, NotificationService, MenuService
|
||||
* @throws AWTException on startup error, including systray not supported
|
||||
*/
|
||||
private synchronized void startUp() throws Exception {
|
||||
final TrayManager trayManager;
|
||||
boolean useSwingDefault = !(SystemVersion.isWindows() || SystemVersion.isMac());
|
||||
boolean useSwing = _appContext.getProperty(PROP_SWING, useSwingDefault);
|
||||
_trayManager = new ExternalTrayManager(_appContext, useSwing);
|
||||
@ -202,89 +200,6 @@ public class ExternalMain implements ClientApp, NotificationService, MenuService
|
||||
return false;
|
||||
}
|
||||
|
||||
/////// MenuService methods
|
||||
|
||||
/**
|
||||
* Menu will start out shown and enabled, in the root menu
|
||||
*
|
||||
* @param message for the menu, translated
|
||||
* @param callback fired on click
|
||||
* @return null on error
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public MenuHandle addMenu(String message, MenuCallback callback) {
|
||||
return addMenu(message, callback, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu will start out enabled, as a submenu
|
||||
*
|
||||
* @param message for the menu, translated
|
||||
* @param callback fired on click
|
||||
* @param parent the parent menu this will be a submenu of, or null for top level
|
||||
* @return null on error
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public MenuHandle addMenu(String message, MenuCallback callback, MenuHandle parent) {
|
||||
if (_trayManager == null)
|
||||
return null;
|
||||
return _trayManager.addMenu(message, callback, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void removeMenu(MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.removeMenu(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void showMenu(MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.showMenu(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void hideMenu(MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.hideMenu(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void enableMenu(MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.enableMenu(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void disableMenu(MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.disableMenu(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void updateMenu(String message, MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.updateMenu(message, item);
|
||||
}
|
||||
|
||||
/////// ClientApp methods
|
||||
|
||||
public synchronized void startup() {
|
||||
|
@ -51,15 +51,11 @@ class ExternalTrayManager extends TrayManager {
|
||||
}
|
||||
});
|
||||
popup.add(startItem);
|
||||
initializeNotificationItems();
|
||||
popup.add(_notificationItem2);
|
||||
popup.add(_notificationItem1);
|
||||
return popup;
|
||||
}
|
||||
|
||||
public JPopupMenu getSwingMainMenu() {
|
||||
JPopupMenu popup = new JPopupMenu();
|
||||
/*
|
||||
JMenuItem startItem = new JMenuItem(_t("Start I2P"));
|
||||
startItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
@ -83,10 +79,6 @@ class ExternalTrayManager extends TrayManager {
|
||||
}
|
||||
});
|
||||
popup.add(startItem);
|
||||
*/
|
||||
initializeJNotificationItems();
|
||||
popup.add(_jnotificationItem2);
|
||||
popup.add(_jnotificationItem1);
|
||||
return popup;
|
||||
}
|
||||
|
||||
@ -94,14 +86,5 @@ class ExternalTrayManager extends TrayManager {
|
||||
* Update the menu
|
||||
* @since 0.9.26
|
||||
*/
|
||||
protected void updateMenu() {
|
||||
if (_notificationItem1 != null)
|
||||
_notificationItem1.setEnabled(_showNotifications);
|
||||
if (_notificationItem2 != null)
|
||||
_notificationItem2.setEnabled(!_showNotifications);
|
||||
if (_jnotificationItem1 != null)
|
||||
_jnotificationItem1.setVisible(_showNotifications);
|
||||
if (_jnotificationItem2 != null)
|
||||
_jnotificationItem2.setVisible(!_showNotifications);
|
||||
}
|
||||
protected void updateMenu() {}
|
||||
}
|
||||
|
@ -32,9 +32,11 @@ class InternalTrayManager extends TrayManager {
|
||||
private final Log log;
|
||||
private final Main _main;
|
||||
private MenuItem _statusItem, _browserItem, _configItem, _restartItem, _stopItem,
|
||||
_restartHardItem, _stopHardItem, _cancelItem;
|
||||
_restartHardItem, _stopHardItem, _cancelItem,
|
||||
_notificationItem1, _notificationItem2;
|
||||
private JMenuItem _jstatusItem, _jbrowserItem, _jconfigItem, _jrestartItem, _jstopItem,
|
||||
_jrestartHardItem, _jstopHardItem, _jcancelItem;
|
||||
_jrestartHardItem, _jstopHardItem, _jcancelItem,
|
||||
_jnotificationItem1, _jnotificationItem2;
|
||||
|
||||
private static final boolean CONSOLE_ENABLED = Desktop.isDesktopSupported() &&
|
||||
Desktop.getDesktop().isSupported(Action.BROWSE);
|
||||
@ -84,6 +86,33 @@ class InternalTrayManager extends TrayManager {
|
||||
}
|
||||
|
||||
PopupMenu desktopguiConfigurationLauncher = new PopupMenu(_t("Configure I2P System Tray"));
|
||||
final MenuItem notificationItem2 = new MenuItem(_t("Enable notifications"));
|
||||
notificationItem2.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
new SwingWorker<Object, Object>() {
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
configureNotifications(true);
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
|
||||
final MenuItem notificationItem1 = new MenuItem(_t("Disable notifications"));
|
||||
notificationItem1.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
new SwingWorker<Object, Object>() {
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
configureNotifications(false);
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
|
||||
MenuItem configSubmenu = new MenuItem(_t("Disable system tray"));
|
||||
configSubmenu.addActionListener(new ActionListener() {
|
||||
@ -185,9 +214,8 @@ class InternalTrayManager extends TrayManager {
|
||||
popup.add(browserLauncher);
|
||||
popup.addSeparator();
|
||||
}
|
||||
initializeNotificationItems();
|
||||
desktopguiConfigurationLauncher.add(_notificationItem2);
|
||||
desktopguiConfigurationLauncher.add(_notificationItem1);
|
||||
desktopguiConfigurationLauncher.add(notificationItem2);
|
||||
desktopguiConfigurationLauncher.add(notificationItem1);
|
||||
desktopguiConfigurationLauncher.add(configSubmenu);
|
||||
popup.add(desktopguiConfigurationLauncher);
|
||||
popup.addSeparator();
|
||||
@ -202,6 +230,8 @@ class InternalTrayManager extends TrayManager {
|
||||
_statusItem = statusItem;
|
||||
_browserItem = browserLauncher;
|
||||
_configItem = desktopguiConfigurationLauncher;
|
||||
_notificationItem1 = notificationItem1;
|
||||
_notificationItem2 = notificationItem2;
|
||||
_restartItem = restartItem;
|
||||
_stopItem = stopItem;
|
||||
_restartHardItem = restartItem2;
|
||||
@ -240,6 +270,33 @@ class InternalTrayManager extends TrayManager {
|
||||
}
|
||||
|
||||
JMenu desktopguiConfigurationLauncher = new JMenu(_t("Configure I2P System Tray"));
|
||||
final JMenuItem notificationItem2 = new JMenuItem(_t("Enable notifications"));
|
||||
notificationItem2.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
new SwingWorker<Object, Object>() {
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
configureNotifications(true);
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
|
||||
final JMenuItem notificationItem1 = new JMenuItem(_t("Disable notifications"));
|
||||
notificationItem1.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
new SwingWorker<Object, Object>() {
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
configureNotifications(false);
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
|
||||
JMenuItem configSubmenu = new JMenuItem(_t("Disable system tray"));
|
||||
configSubmenu.addActionListener(new ActionListener() {
|
||||
@ -341,9 +398,8 @@ class InternalTrayManager extends TrayManager {
|
||||
popup.add(browserLauncher);
|
||||
popup.addSeparator();
|
||||
}
|
||||
initializeJNotificationItems();
|
||||
desktopguiConfigurationLauncher.add(_jnotificationItem2);
|
||||
desktopguiConfigurationLauncher.add(_jnotificationItem1);
|
||||
desktopguiConfigurationLauncher.add(notificationItem2);
|
||||
desktopguiConfigurationLauncher.add(notificationItem1);
|
||||
desktopguiConfigurationLauncher.add(configSubmenu);
|
||||
popup.add(desktopguiConfigurationLauncher);
|
||||
popup.addSeparator();
|
||||
@ -358,6 +414,8 @@ class InternalTrayManager extends TrayManager {
|
||||
_jstatusItem = statusItem;
|
||||
_jbrowserItem = browserLauncher;
|
||||
_jconfigItem = desktopguiConfigurationLauncher;
|
||||
_jnotificationItem1 = notificationItem1;
|
||||
_jnotificationItem2 = notificationItem2;
|
||||
_jrestartItem = restartItem;
|
||||
_jstopItem = stopItem;
|
||||
_jrestartHardItem = restartItem2;
|
||||
@ -453,8 +511,7 @@ class InternalTrayManager extends TrayManager {
|
||||
/**
|
||||
* @since 0.9.53
|
||||
*/
|
||||
@Override
|
||||
protected void configureNotifications(boolean enable) {
|
||||
private void configureNotifications(boolean enable) {
|
||||
_showNotifications = enable;
|
||||
String value = Boolean.toString(enable);
|
||||
if (!_context.router().saveConfig(PROP_NOTIFICATIONS, value))
|
||||
|
@ -17,9 +17,6 @@ import net.i2p.I2PAppContext;
|
||||
import net.i2p.app.ClientAppManager;
|
||||
import net.i2p.app.ClientAppState;
|
||||
import static net.i2p.app.ClientAppState.*;
|
||||
import net.i2p.app.MenuCallback;
|
||||
import net.i2p.app.MenuHandle;
|
||||
import net.i2p.app.MenuService;
|
||||
import net.i2p.app.NotificationService;
|
||||
import net.i2p.desktopgui.router.RouterManager;
|
||||
import net.i2p.router.RouterContext;
|
||||
@ -32,7 +29,7 @@ import net.i2p.util.I2PProperties.I2PPropertyCallback;
|
||||
/**
|
||||
* The main class of the application.
|
||||
*/
|
||||
public class Main implements RouterApp, NotificationService, MenuService {
|
||||
public class Main implements RouterApp, NotificationService {
|
||||
|
||||
// non-null
|
||||
private final I2PAppContext _appContext;
|
||||
@ -248,89 +245,6 @@ public class Main implements RouterApp, NotificationService, MenuService {
|
||||
return false;
|
||||
}
|
||||
|
||||
/////// MenuService methods
|
||||
|
||||
/**
|
||||
* Menu will start out shown and enabled, in the root menu
|
||||
*
|
||||
* @param message for the menu, translated
|
||||
* @param callback fired on click
|
||||
* @return null on error
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public MenuHandle addMenu(String message, MenuCallback callback) {
|
||||
return addMenu(message, callback, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu will start out enabled, as a submenu
|
||||
*
|
||||
* @param message for the menu, translated
|
||||
* @param callback fired on click
|
||||
* @param parent the parent menu this will be a submenu of, or null for top level
|
||||
* @return null on error
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public MenuHandle addMenu(String message, MenuCallback callback, MenuHandle parent) {
|
||||
if (_trayManager == null)
|
||||
return null;
|
||||
return _trayManager.addMenu(message, callback, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void removeMenu(MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.removeMenu(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void showMenu(MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.showMenu(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void hideMenu(MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.hideMenu(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void enableMenu(MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.enableMenu(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void disableMenu(MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.disableMenu(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void updateMenu(String message, MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.updateMenu(message, item);
|
||||
}
|
||||
|
||||
/////// ClientApp methods
|
||||
|
||||
/** @since 0.9.26 */
|
||||
|
@ -4,7 +4,6 @@ import java.awt.AWTException;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Image;
|
||||
import java.awt.MenuItem;
|
||||
import java.awt.PopupMenu;
|
||||
import java.awt.SystemTray;
|
||||
import java.awt.Toolkit;
|
||||
@ -17,12 +16,8 @@ import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.SwingWorker;
|
||||
import javax.swing.event.MenuKeyEvent;
|
||||
@ -31,8 +26,6 @@ import javax.swing.event.PopupMenuEvent;
|
||||
import javax.swing.event.PopupMenuListener;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.app.MenuCallback;
|
||||
import net.i2p.app.MenuHandle;
|
||||
import net.i2p.apps.systray.UrlLauncher;
|
||||
import net.i2p.desktopgui.i18n.DesktopguiTranslator;
|
||||
import net.i2p.util.Log;
|
||||
@ -50,11 +43,6 @@ abstract class TrayManager {
|
||||
///Our tray icon, or null if unsupported
|
||||
protected TrayIcon trayIcon;
|
||||
protected volatile boolean _showNotifications;
|
||||
protected MenuItem _notificationItem1, _notificationItem2;
|
||||
protected JMenuItem _jnotificationItem1, _jnotificationItem2;
|
||||
private final AtomicInteger _id = new AtomicInteger();
|
||||
private final List<MenuInternal> _menus;
|
||||
private JPopupMenu _jPopupMenu;
|
||||
|
||||
private static final String PNG_DIR = "/desktopgui/resources/images/";
|
||||
private static final String MAC_ICON = "itoopie_black_24.png";
|
||||
@ -69,7 +57,6 @@ abstract class TrayManager {
|
||||
protected TrayManager(I2PAppContext ctx, boolean useSwing) {
|
||||
_appContext = ctx;
|
||||
_useSwing = useSwing;
|
||||
_menus = new ArrayList<MenuInternal>();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,7 +105,6 @@ abstract class TrayManager {
|
||||
frame.setMinimumSize(new Dimension(0, 0));
|
||||
frame.setSize(0, 0);
|
||||
final JPopupMenu menu = getSwingMainMenu();
|
||||
_jPopupMenu = menu;
|
||||
menu.setFocusable(true);
|
||||
frame.add(menu);
|
||||
TrayIcon ti = new TrayIcon(getTrayImage(), tooltip, null);
|
||||
@ -302,248 +288,6 @@ abstract class TrayManager {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does not save. See InternalTrayManager.
|
||||
*
|
||||
* @since 0.9.58 moved up from InternalTrayManager
|
||||
*/
|
||||
protected void configureNotifications(boolean enable) {
|
||||
_showNotifications = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes _notificationItem 1 and 2
|
||||
*
|
||||
* @since 0.9.58 pulled out of InternalTrayManager
|
||||
*/
|
||||
protected void initializeNotificationItems() {
|
||||
final MenuItem notificationItem2 = new MenuItem(_t("Enable notifications"));
|
||||
notificationItem2.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
new SwingWorker<Object, Object>() {
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
configureNotifications(true);
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
_notificationItem2 = notificationItem2;
|
||||
|
||||
final MenuItem notificationItem1 = new MenuItem(_t("Disable notifications"));
|
||||
notificationItem1.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
new SwingWorker<Object, Object>() {
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
configureNotifications(false);
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
_notificationItem1 = notificationItem1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes _jnotificationItem 1 and 2
|
||||
*
|
||||
* @since 0.9.58 pulled out of InternalTrayManager
|
||||
*/
|
||||
protected void initializeJNotificationItems() {
|
||||
final JMenuItem notificationItem2 = new JMenuItem(_t("Enable notifications"));
|
||||
notificationItem2.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
new SwingWorker<Object, Object>() {
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
configureNotifications(true);
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
_jnotificationItem2 = notificationItem2;
|
||||
|
||||
final JMenuItem notificationItem1 = new JMenuItem(_t("Disable notifications"));
|
||||
notificationItem1.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
new SwingWorker<Object, Object>() {
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
configureNotifications(false);
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
_jnotificationItem1 = notificationItem1;
|
||||
}
|
||||
|
||||
/////// MenuService delegation methods
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public MenuHandle addMenu(String message, final MenuCallback callback, MenuHandle p) {
|
||||
MenuInternal parent = p != null ? (MenuInternal) p : null;
|
||||
final int id = _id.incrementAndGet();
|
||||
final MenuInternal rv;
|
||||
if (_useSwing) {
|
||||
final JMenuItem m = new JMenuItem(message);
|
||||
rv = new MenuInternal(null, m, callback, id);
|
||||
m.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
new SwingWorker<Object, Object>() {
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
rv.cb.clicked(rv);
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
_jPopupMenu.add(m);
|
||||
} else {
|
||||
final MenuItem m = new MenuItem(message);
|
||||
rv = new MenuInternal(m, null, callback, id);
|
||||
m.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
new SwingWorker<Object, Object>() {
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
rv.cb.clicked(rv);
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
trayIcon.getPopupMenu().add(m);
|
||||
}
|
||||
synchronized(_menus) {
|
||||
_menus.add(rv);
|
||||
}
|
||||
updateMenu();
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void removeMenu(MenuHandle item) {
|
||||
MenuInternal mi = (MenuInternal) item;
|
||||
if (_useSwing) {
|
||||
_jPopupMenu.remove(mi.jm);
|
||||
} else {
|
||||
trayIcon.getPopupMenu().remove(mi.m);
|
||||
}
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void showMenu(MenuHandle item) {
|
||||
MenuInternal mi = (MenuInternal) item;
|
||||
mi.setVisible(true);
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void hideMenu(MenuHandle item) {
|
||||
MenuInternal mi = (MenuInternal) item;
|
||||
mi.setVisible(false);
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void enableMenu(MenuHandle item) {
|
||||
MenuInternal mi = (MenuInternal) item;
|
||||
mi.setEnabled(true);
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void disableMenu(MenuHandle item) {
|
||||
MenuInternal mi = (MenuInternal) item;
|
||||
mi.setEnabled(false);
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void updateMenu(String message, MenuHandle item) {
|
||||
MenuInternal mi = (MenuInternal) item;
|
||||
mi.setText(message);
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
/////// MenuService internals
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
private MenuInternal getMenu(int id) {
|
||||
synchronized(_menus) {
|
||||
for (MenuInternal mi : _menus) {
|
||||
if (mi.getID() == id)
|
||||
return mi;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
private static class MenuInternal implements MenuHandle {
|
||||
private final MenuItem m;
|
||||
private final JMenuItem jm;
|
||||
private final MenuCallback cb;
|
||||
private final int id;
|
||||
|
||||
public MenuInternal(MenuItem mm, JMenuItem jmm, MenuCallback cbb, int idd) {
|
||||
m = mm; jm = jmm; cb = cbb; id = idd;
|
||||
}
|
||||
|
||||
public int getID() { return id; }
|
||||
|
||||
private void setEnabled(boolean yes) {
|
||||
if (m != null)
|
||||
m.setEnabled(yes);
|
||||
else
|
||||
jm.setEnabled(yes);
|
||||
}
|
||||
|
||||
private void setVisible(boolean yes) {
|
||||
if (m != null)
|
||||
m.setEnabled(yes);
|
||||
else
|
||||
jm.setVisible(yes);
|
||||
}
|
||||
|
||||
private void setText(String text) {
|
||||
if (m != null)
|
||||
m.setLabel(text);
|
||||
else
|
||||
jm.setText(text);
|
||||
}
|
||||
}
|
||||
|
||||
protected String _t(String s) {
|
||||
return DesktopguiTranslator._t(_appContext, s);
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
plugins {
|
||||
id 'java-library'
|
||||
id 'war'
|
||||
}
|
||||
|
||||
@ -12,15 +11,13 @@ sourceSets {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api project(':router')
|
||||
api project(':apps:jetty')
|
||||
api files('../../installer/lib/wrapper/all/wrapper.jar')
|
||||
api fileTree("../jetty/apache-tomcat-${tomcatVersion}")
|
||||
api fileTree("../jetty/jetty-distribution-${jettyVersion}")
|
||||
providedCompile project(':router')
|
||||
providedCompile project(':apps:jetty')
|
||||
providedCompile files('../../installer/lib/wrapper/all/wrapper.jar')
|
||||
}
|
||||
|
||||
war {
|
||||
archiveBaseName.set('jsonrpc')
|
||||
archiveName 'jsonrpc.war'
|
||||
webXml = file('web.xml')
|
||||
}
|
||||
|
||||
|
@ -92,29 +92,7 @@
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="listChangedFiles" if="git.available" >
|
||||
<exec executable="git" outputproperty="workspace.changes" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="status" />
|
||||
<arg value="-s" />
|
||||
<arg value="--porcelain" />
|
||||
<arg value="-uno" />
|
||||
<arg value="." />
|
||||
<arg value="../resources" />
|
||||
</exec>
|
||||
<!-- trim flags -->
|
||||
<exec executable="sed" inputstring="${workspace.changes}" outputproperty="workspace.changes.sed" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="-e" />
|
||||
<arg value="s/^[MTADRCU ]*//" />
|
||||
</exec>
|
||||
<!-- \n in an attribute value generates an invalid manifest -->
|
||||
<exec executable="tr" inputstring="${workspace.changes.sed}" outputproperty="workspace.changes.tr" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="-s" />
|
||||
<arg value="[:space:]" />
|
||||
<arg value="," />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="jar" depends="compile, listChangedFiles">
|
||||
<target name="jar" depends="compile">
|
||||
<!-- set if unset -->
|
||||
<property name="workspace.changes.tr" value="" />
|
||||
<jar destfile="build/i2pcontrol.jar" basedir="./build/obj" includes="**/*.class" >
|
||||
@ -130,7 +108,7 @@
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="socketJar" depends="compileSocketJar, listChangedFiles">
|
||||
<target name="socketJar" depends="compileSocketJar">
|
||||
<!-- set if unset -->
|
||||
<property name="workspace.changes.tr" value="" />
|
||||
<jar destfile="build/i2pcontrol.jar" basedir="./build/obj" includes="**/*.class" >
|
||||
@ -146,7 +124,7 @@
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="war" depends="compile, listChangedFiles" >
|
||||
<target name="war" depends="compile" >
|
||||
<!-- set if unset -->
|
||||
<property name="workspace.changes.tr" value="" />
|
||||
<war destfile="build/jsonrpc.war" webxml="web.xml" >
|
||||
|
@ -170,7 +170,7 @@ public class RouterInfoHandler implements RequestHandler {
|
||||
&& (!_context.router().gracefulShutdownInProgress())
|
||||
&& !_context.clientManager().isAlive())
|
||||
return (NETWORK_STATUS.ERROR_I2CP);
|
||||
long skew = _context.commSystem().getFramedAveragePeerClockSkew(10);
|
||||
long skew = _context.commSystem().getFramedAveragePeerClockSkew(33);
|
||||
// Display the actual skew, not the offset
|
||||
if (Math.abs(skew) > 60 * 1000)
|
||||
return NETWORK_STATUS.ERROR_CLOCK_SKEW;
|
||||
@ -200,7 +200,7 @@ public class RouterInfoHandler implements RequestHandler {
|
||||
case CommSystemFacade.STATUS_IPV4_DISABLED_IPV6_FIREWALLED:
|
||||
if (_context.router().getRouterInfo().getTargetAddress("NTCP2") != null)
|
||||
return NETWORK_STATUS.WARN_FIREWALLED_WITH_INBOUND_TCP;
|
||||
if (_context.netDb().floodfillEnabled())
|
||||
if (((FloodfillNetworkDatabaseFacade) _context.netDb()).floodfillEnabled())
|
||||
return NETWORK_STATUS.WARN_FIREWALLED_AND_FLOODFILL;
|
||||
if (_context.router().getRouterInfo().getCapabilities().indexOf('O') >= 0)
|
||||
return NETWORK_STATUS.WARN_FIREWALLED_AND_FAST;
|
||||
|
@ -1,5 +1,4 @@
|
||||
plugins {
|
||||
id 'java-library'
|
||||
id 'war'
|
||||
}
|
||||
|
||||
@ -13,14 +12,11 @@ sourceSets {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api project(':core')
|
||||
api project(':apps:systray')
|
||||
api 'gnu.getopt:java-getopt:1.0.13'
|
||||
api project(':apps:ministreaming')
|
||||
api project(':apps:jetty')
|
||||
// this is not needed except for standalone,
|
||||
// but we build the standalone classes even for non-standalone
|
||||
api project(':apps:desktopgui')
|
||||
compile project(':core')
|
||||
providedCompile project(':apps:systray')
|
||||
compile 'gnu.getopt:java-getopt:1.0.13'
|
||||
providedCompile project(':apps:ministreaming')
|
||||
providedCompile project(':apps:jetty')
|
||||
}
|
||||
|
||||
task i2psnarkJar(type: Jar) {
|
||||
|
@ -10,5 +10,3 @@
|
||||
#routerconsole.browser=firefox
|
||||
# disable system tray
|
||||
#desktopgui.enabled=false
|
||||
# disable system tray notification popups
|
||||
#desktopgui.showNotifications=false
|
||||
|
@ -68,20 +68,13 @@
|
||||
</target>
|
||||
|
||||
<target name="listChangedFiles" depends="jarUpToDate" if="shouldListChanges" >
|
||||
<exec executable="git" outputproperty="workspace.changes" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="status" />
|
||||
<arg value="-s" />
|
||||
<arg value="--porcelain" />
|
||||
<arg value="-uno" />
|
||||
<exec executable="mtn" outputproperty="workspace.changes" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="list" />
|
||||
<arg value="changed" />
|
||||
<arg value=".." />
|
||||
</exec>
|
||||
<!-- trim flags -->
|
||||
<exec executable="sed" inputstring="${workspace.changes}" outputproperty="workspace.changes.sed" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="-e" />
|
||||
<arg value="s/^[MTADRCU ]*//" />
|
||||
</exec>
|
||||
<!-- \n in an attribute value generates an invalid manifest -->
|
||||
<exec executable="tr" inputstring="${workspace.changes.sed}" outputproperty="workspace.changes.tr" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<exec executable="tr" inputstring="${workspace.changes}" outputproperty="workspace.changes.tr" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="-s" />
|
||||
<arg value="[:space:]" />
|
||||
<arg value="," />
|
||||
@ -118,7 +111,7 @@
|
||||
<not>
|
||||
<isset property="war.uptodate" />
|
||||
</not>
|
||||
<isset property="git.available" />
|
||||
<isset property="mtn.available" />
|
||||
</and>
|
||||
</condition>
|
||||
</target>
|
||||
@ -259,12 +252,10 @@
|
||||
<attribute name="Build-Date" value="${build.timestamp}" />
|
||||
<attribute name="Base-Revision" value="${workspace.version}" />
|
||||
<attribute name="Workspace-Changes" value="${workspace.changes.tr}" />
|
||||
<attribute name="X-Compile-Source-JDK" value="${javac.version}" />
|
||||
<attribute name="X-Compile-Target-JDK" value="${javac.version}" />
|
||||
<!-- this is so Jetty will report its version correctly -->
|
||||
<section name="org/eclipse/jetty/server/" >
|
||||
<attribute name="Implementation-Vendor" value="Eclipse.org - Jetty" />
|
||||
<attribute name="Implementation-Version" value="${jetty.ver}" />
|
||||
<attribute name="Implementation-Version" value="8.1.17.v20150415" />
|
||||
</section>
|
||||
</manifest>
|
||||
</jar>
|
||||
@ -307,12 +298,6 @@
|
||||
value="url(/i2psnark/.resources/themes/ubergine/images/" >
|
||||
<include name="**/*.css" />
|
||||
</replace>
|
||||
<replace dir="build/standalone-resources/.resources/themes"
|
||||
summary="true"
|
||||
token="url(/themes/console/images/buttons/"
|
||||
value="url(/i2psnark/.resources/icons/" >
|
||||
<include name="**/*.css" />
|
||||
</replace>
|
||||
|
||||
<!-- Rather than pulling in all the console theme images, let's just specify the ones we need -->
|
||||
<copy file="../../routerconsole/jsp/themes/console/images/transparent.gif"
|
||||
@ -323,8 +308,6 @@
|
||||
todir="build/standalone-resources/.resources/themes/light/images" />
|
||||
<copy file="../../routerconsole/jsp/themes/console/images/info/errortriangle.png"
|
||||
todir="build/standalone-resources/.resources/themes/ubergine/images" />
|
||||
<copy file="../../routerconsole/jsp/themes/console/images/buttons/search.png"
|
||||
todir="build/standalone-resources/.resources/icons" />
|
||||
|
||||
<mkdir dir="build/standalone-resources/.resources/js" />
|
||||
<copy file="../../routerconsole/jsp/js/ajax.js" todir="build/standalone-resources/.resources/js" />
|
||||
|
@ -6,7 +6,6 @@ package org.klomp.snark;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.client.I2PSession;
|
||||
@ -33,9 +32,7 @@ class BWLimits {
|
||||
session.connect();
|
||||
rv = session.bandwidthLimits();
|
||||
session.destroySession();
|
||||
} catch (I2PSessionException ise) {
|
||||
I2PAppContext.getGlobalContext().logManager().getLog(BWLimits.class).warn("BWL fail", ise);
|
||||
}
|
||||
} catch (I2PSessionException ise) {}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -1,63 +0,0 @@
|
||||
package org.klomp.snark;
|
||||
|
||||
/**
|
||||
* Bandwidth and bandwidth limits
|
||||
*
|
||||
* Maintain three bandwidth estimators:
|
||||
* Sent, received, and requested.
|
||||
*
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public interface BandwidthListener {
|
||||
|
||||
/**
|
||||
* The average rate in Bps
|
||||
*/
|
||||
public long getUploadRate();
|
||||
|
||||
/**
|
||||
* The average rate in Bps
|
||||
*/
|
||||
public long getDownloadRate();
|
||||
|
||||
/**
|
||||
* We unconditionally sent this many bytes
|
||||
*/
|
||||
public void uploaded(int size);
|
||||
|
||||
/**
|
||||
* We unconditionally received this many bytes
|
||||
*/
|
||||
public void downloaded(int size);
|
||||
|
||||
/**
|
||||
* Should we send this many bytes?
|
||||
* Do NOT call uploaded() if this returns true.
|
||||
*/
|
||||
public boolean shouldSend(int size);
|
||||
|
||||
/**
|
||||
* Should we request this many bytes?
|
||||
*/
|
||||
public boolean shouldRequest(Peer peer, int size);
|
||||
|
||||
/**
|
||||
* Current limit in BPS
|
||||
*/
|
||||
public long getUpBWLimit();
|
||||
|
||||
/**
|
||||
* Current limit in BPS
|
||||
*/
|
||||
public long getDownBWLimit();
|
||||
|
||||
/**
|
||||
* Are we currently over the limit?
|
||||
*/
|
||||
public boolean overUpBWLimit();
|
||||
|
||||
/**
|
||||
* Are we currently over the limit?
|
||||
*/
|
||||
public boolean overDownBWLimit();
|
||||
}
|
@ -1,179 +0,0 @@
|
||||
package org.klomp.snark;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SyntheticREDQueue;
|
||||
|
||||
/**
|
||||
* Bandwidth and bandwidth limits
|
||||
*
|
||||
* Maintain three bandwidth estimators:
|
||||
* Sent, received, and requested.
|
||||
*
|
||||
* There are three layers of BandwidthListeners:
|
||||
*<pre>
|
||||
* BandwidthManager (total)
|
||||
* PeerCoordinator (per-torrent)
|
||||
* Peer/WebPeer (per-connection)
|
||||
*</pre>
|
||||
*
|
||||
* Here at the top, we use SyntheticRedQueues for accurate
|
||||
* and current moving averages of up, down, and requested bandwidth.
|
||||
*
|
||||
* At the lower layers, simple weighted moving averages of
|
||||
* three buckets of 40 seconds each (2 minutes total) are used
|
||||
* for up and down, and requested is delegated here.
|
||||
*
|
||||
* The lower layers must report to the next-higher layer.
|
||||
*
|
||||
* At the Peer layer, we report inbound piece data per-read,
|
||||
* not per-piece, to get a smoother inbound estimate.
|
||||
*
|
||||
* Only the following data are counted by the BandwidthListeners:
|
||||
*<ul><li>Pieces (both Peer and WebPeer)
|
||||
*<li>ut_metadata
|
||||
*</ul>
|
||||
*
|
||||
* No overhead at any layer is accounted for.
|
||||
*
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public class BandwidthManager implements BandwidthListener {
|
||||
|
||||
private final I2PAppContext _context;
|
||||
private final Log _log;
|
||||
private SyntheticREDQueue _up, _down, _req;
|
||||
|
||||
BandwidthManager(I2PAppContext ctx, int upLimit, int downLimit) {
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(BandwidthManager.class);
|
||||
_up = new SyntheticREDQueue(ctx, upLimit);
|
||||
_down = new SyntheticREDQueue(ctx, downLimit);
|
||||
// Allow down limit a little higher based on testing
|
||||
// Allow req limit a little higher still because it uses RED
|
||||
// so it actually kicks in sooner.
|
||||
_req = new SyntheticREDQueue(ctx, downLimit * 110 / 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Current limit in Bps
|
||||
*/
|
||||
void setUpBWLimit(long upLimit) {
|
||||
int limit = (int) Math.min(upLimit, Integer.MAX_VALUE);
|
||||
if (limit != getUpBWLimit())
|
||||
_up = new SyntheticREDQueue(_context, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Current limit in Bps
|
||||
*/
|
||||
void setDownBWLimit(long downLimit) {
|
||||
int limit = (int) Math.min(downLimit, Integer.MAX_VALUE);
|
||||
if (limit != getDownBWLimit()) {
|
||||
_down = new SyntheticREDQueue(_context, limit);
|
||||
_req = new SyntheticREDQueue(_context, limit * 110 / 100);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The average rate in Bps
|
||||
*/
|
||||
long getRequestRate() {
|
||||
return (long) (1000f * _req.getBandwidthEstimate());
|
||||
}
|
||||
|
||||
// begin BandwidthListener interface
|
||||
|
||||
|
||||
/**
|
||||
* The average rate in Bps
|
||||
*/
|
||||
public long getUploadRate() {
|
||||
return (long) (1000f * _up.getBandwidthEstimate());
|
||||
}
|
||||
|
||||
/**
|
||||
* The average rate in Bps
|
||||
*/
|
||||
public long getDownloadRate() {
|
||||
return (long) (1000f * _down.getBandwidthEstimate());
|
||||
}
|
||||
|
||||
/**
|
||||
* We unconditionally sent this many bytes
|
||||
*/
|
||||
public void uploaded(int size) {
|
||||
_up.addSample(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* We received this many bytes
|
||||
*/
|
||||
public void downloaded(int size) {
|
||||
_down.addSample(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we send this many bytes?
|
||||
* Do NOT call uploaded() if this returns true.
|
||||
*/
|
||||
public boolean shouldSend(int size) {
|
||||
boolean rv = _up.offer(size, 1.0f);
|
||||
if (!rv && _log.shouldWarn())
|
||||
_log.warn("Deny sending " + size + " bytes, upload rate " + DataHelper.formatSize(getUploadRate()) + "Bps");
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we request this many bytes?
|
||||
*
|
||||
* @param peer ignored
|
||||
*/
|
||||
public boolean shouldRequest(Peer peer, int size) {
|
||||
boolean rv = !overDownBWLimit() && _req.offer(size, 1.0f);
|
||||
if (!rv && _log.shouldWarn())
|
||||
_log.warn("Deny requesting " + size + " bytes, download rate " + DataHelper.formatSize(getDownloadRate()) + "Bps" +
|
||||
", request rate " + DataHelper.formatSize(getRequestRate()) + "Bps");
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Current limit in BPS
|
||||
*/
|
||||
public long getUpBWLimit() {
|
||||
return _up.getMaxBandwidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Current limit in BPS
|
||||
*/
|
||||
public long getDownBWLimit() {
|
||||
return _down.getMaxBandwidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Are we currently over the limit?
|
||||
*/
|
||||
public boolean overUpBWLimit() {
|
||||
return getUploadRate() > getUpBWLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Are we currently over the limit?
|
||||
*/
|
||||
public boolean overDownBWLimit() {
|
||||
return getDownloadRate() > getDownBWLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* In HTML for debug page
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<br><b>Bandwidth Limiters</b><br><b>Up:</b> " + _up +
|
||||
"<br><b>Down:</b> " + _down +
|
||||
"<br><b>Req:</b> " + _req +
|
||||
"<br>";
|
||||
}
|
||||
}
|
@ -4,6 +4,8 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.CoreVersion;
|
||||
|
||||
/**
|
||||
* Simple command line access to various utilities.
|
||||
* Not a public API. Subject to change.
|
||||
@ -36,7 +38,7 @@ public class CommandLine extends net.i2p.util.CommandLine {
|
||||
}
|
||||
|
||||
private static void usage(List<String> classes) {
|
||||
System.err.println("I2PSnark version " + SnarkManager.FULL_VERSION + '\n' +
|
||||
System.err.println("I2PSnark version " + CoreVersion.VERSION + '\n' +
|
||||
"USAGE: java -jar /path/to/i2psnark.jar command [args]");
|
||||
printCommands(classes);
|
||||
}
|
||||
|
@ -83,9 +83,4 @@ public interface CompleteListener {
|
||||
* @since 0.9.42
|
||||
*/
|
||||
public boolean shouldAutoStart();
|
||||
|
||||
/**
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public BandwidthListener getBandwidthListener();
|
||||
}
|
||||
|
@ -42,5 +42,15 @@ interface CoordinatorListener
|
||||
*/
|
||||
public boolean overUploadLimit(int uploaders);
|
||||
|
||||
/**
|
||||
* Is i2psnark as a whole over its limit?
|
||||
*/
|
||||
public boolean overUpBWLimit();
|
||||
|
||||
/**
|
||||
* Is a particular peer who has this recent download rate (in Bps) over our upstream bandwidth limit?
|
||||
*/
|
||||
public boolean overUpBWLimit(long total);
|
||||
|
||||
public void addMessage(String message);
|
||||
}
|
||||
|
@ -190,8 +190,6 @@ abstract class ExtensionHandler {
|
||||
}
|
||||
if (log.shouldLog(Log.INFO))
|
||||
log.info("Request chunk " + chk + " from " + peer);
|
||||
// ignore the rv, always request
|
||||
peer.shouldRequest(state.chunkSize(chk));
|
||||
sendRequest(peer, chk);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@ -232,6 +230,7 @@ abstract class ExtensionHandler {
|
||||
sendPiece(peer, piece, pc, totalSize);
|
||||
// Do this here because PeerConnectionOut only reports for PIECE messages
|
||||
peer.uploaded(pc.length);
|
||||
listener.uploaded(peer, pc.length);
|
||||
} else if (type == TYPE_DATA) {
|
||||
// On close reading of BEP 9, this is the total metadata size.
|
||||
// Prior to 0.9.21, we sent the piece size, so we can't count on it.
|
||||
@ -246,6 +245,7 @@ abstract class ExtensionHandler {
|
||||
return;
|
||||
int len = is.available();
|
||||
peer.downloaded(len);
|
||||
listener.downloaded(peer, len);
|
||||
// this checks the size
|
||||
done = state.saveChunk(piece, bs, bs.length - len, len);
|
||||
if (log.shouldLog(Log.INFO))
|
||||
@ -264,8 +264,6 @@ abstract class ExtensionHandler {
|
||||
// get the next chunk
|
||||
if (log.shouldLog(Log.INFO))
|
||||
log.info("Request chunk " + chk + " from " + peer);
|
||||
// ignore the rv, always request
|
||||
peer.shouldRequest(state.chunkSize(chk));
|
||||
sendRequest(peer, chk);
|
||||
}
|
||||
} else if (type == TYPE_REJECT) {
|
||||
|
@ -1,15 +1,8 @@
|
||||
package org.klomp.snark;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Arrays;
|
||||
@ -20,7 +13,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
@ -36,7 +28,6 @@ import net.i2p.client.streaming.I2PSocketManagerFactory;
|
||||
import net.i2p.client.streaming.I2PSocketOptions;
|
||||
import net.i2p.data.Base32;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.util.ConcurrentHashSet;
|
||||
@ -45,9 +36,7 @@ import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SecureDirectory;
|
||||
import net.i2p.util.SecureFile;
|
||||
import net.i2p.util.SecureFileOutputStream;
|
||||
import net.i2p.util.SimpleTimer;
|
||||
import net.i2p.util.SystemVersion;
|
||||
import net.i2p.util.Translate;
|
||||
|
||||
import org.klomp.snark.dht.DHT;
|
||||
@ -88,7 +77,6 @@ public class I2PSnarkUtil implements DisconnectListener {
|
||||
private DHT _dht;
|
||||
private long _startedTime;
|
||||
private final DisconnectListener _discon;
|
||||
private int _maxFilesPerTorrent = SnarkManager.DEFAULT_MAX_FILES_PER_TORRENT;
|
||||
|
||||
private static final int EEPGET_CONNECT_TIMEOUT = 45*1000;
|
||||
private static final int EEPGET_CONNECT_TIMEOUT_SHORT = 5*1000;
|
||||
@ -114,7 +102,7 @@ public class I2PSnarkUtil implements DisconnectListener {
|
||||
*/
|
||||
public I2PSnarkUtil(I2PAppContext ctx, String baseName, DisconnectListener discon) {
|
||||
_context = ctx;
|
||||
_log = _context.logManager().getLog(I2PSnarkUtil.class);
|
||||
_log = _context.logManager().getLog(Snark.class);
|
||||
_baseName = baseName;
|
||||
_discon = discon;
|
||||
_opts = new HashMap<String, String>();
|
||||
@ -254,11 +242,6 @@ public class I2PSnarkUtil implements DisconnectListener {
|
||||
/** @since 0.9.1 */
|
||||
public File getTempDir() { return _tmpDir; }
|
||||
|
||||
/** @since 0.9.58 */
|
||||
public int getMaxFilesPerTorrent() { return _maxFilesPerTorrent; }
|
||||
/** @since 0.9.58 */
|
||||
public void setMaxFilesPerTorrent(int max) { _maxFilesPerTorrent = Math.max(max, 1); }
|
||||
|
||||
/**
|
||||
* Connect to the router, if we aren't already
|
||||
*/
|
||||
@ -364,10 +347,6 @@ public class I2PSnarkUtil implements DisconnectListener {
|
||||
synchronized(this) {
|
||||
_manager = null;
|
||||
_connecting = false;
|
||||
if (_dht != null) {
|
||||
_dht.stop();
|
||||
_dht = null;
|
||||
}
|
||||
}
|
||||
if (_discon != null)
|
||||
_discon.sessionDisconnected();
|
||||
@ -577,9 +556,6 @@ public class I2PSnarkUtil implements DisconnectListener {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Full Base64 of Destination
|
||||
*/
|
||||
public String getOurIPString() {
|
||||
Destination dest = getMyDestination();
|
||||
if (dest != null)
|
||||
@ -846,90 +822,4 @@ public class I2PSnarkUtil implements DisconnectListener {
|
||||
public String getString(int n, String s, String p) {
|
||||
return Translate.getString(n, s, p, _context, BUNDLE_NAME);
|
||||
}
|
||||
|
||||
private static final boolean SHOULD_SYNC = !(SystemVersion.isAndroid() || SystemVersion.isARM());
|
||||
private static final Pattern ILLEGAL_KEY = Pattern.compile("[#=\\r\\n;]");
|
||||
private static final Pattern ILLEGAL_VALUE = Pattern.compile("[\\r\\n]");
|
||||
|
||||
/**
|
||||
* Same as DataHelper.loadProps() but allows '#' in values,
|
||||
* so we can have filenames with '#' in them in torrent config files.
|
||||
* '#' must be in column 1 for a comment.
|
||||
*
|
||||
* @since 0.9.58
|
||||
*/
|
||||
static void loadProps(Properties props, File f) throws IOException {
|
||||
BufferedReader in = null;
|
||||
try {
|
||||
in = new BufferedReader(new InputStreamReader(new FileInputStream(f), "UTF-8"), 1024);
|
||||
String line = null;
|
||||
while ( (line = in.readLine()) != null) {
|
||||
if (line.trim().length() <= 0) continue;
|
||||
if (line.charAt(0) == '#') continue;
|
||||
if (line.charAt(0) == ';') continue;
|
||||
int split = line.indexOf('=');
|
||||
if (split <= 0) continue;
|
||||
String key = line.substring(0, split);
|
||||
String val = line.substring(split+1).trim();
|
||||
props.setProperty(key, val);
|
||||
}
|
||||
} finally {
|
||||
if (in != null) try { in.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as DataHelper.loadProps() but allows '#' in values,
|
||||
* so we can have filenames with '#' in them in torrent config files.
|
||||
* '#' must be in column 1 for a comment.
|
||||
*
|
||||
* @since 0.9.58
|
||||
*/
|
||||
static void storeProps(Properties props, File file) throws IOException {
|
||||
FileOutputStream fos = null;
|
||||
PrintWriter out = null;
|
||||
IOException ioe = null;
|
||||
File tmpFile = new File(file.getPath() + ".tmp");
|
||||
try {
|
||||
fos = new SecureFileOutputStream(tmpFile);
|
||||
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(fos, "UTF-8")));
|
||||
out.println("# NOTE: This I2P config file must use UTF-8 encoding");
|
||||
out.println("# Last saved: " + DataHelper.formatTime(System.currentTimeMillis()));
|
||||
for (Map.Entry<Object, Object> entry : props.entrySet()) {
|
||||
String name = (String) entry.getKey();
|
||||
String val = (String) entry.getValue();
|
||||
if (ILLEGAL_KEY.matcher(name).find()) {
|
||||
if (ioe == null)
|
||||
ioe = new IOException("Invalid character (one of \"#;=\\r\\n\") in key: \"" +
|
||||
name + "\" = \"" + val + '\"');
|
||||
continue;
|
||||
}
|
||||
if (ILLEGAL_VALUE.matcher(val).find()) {
|
||||
if (ioe == null)
|
||||
ioe = new IOException("Invalid character (one of \"\\r\\n\") in value: \"" +
|
||||
name + "\" = \"" + val + '\"');
|
||||
continue;
|
||||
}
|
||||
out.println(name + "=" + val);
|
||||
}
|
||||
if (SHOULD_SYNC) {
|
||||
out.flush();
|
||||
fos.getFD().sync();
|
||||
}
|
||||
out.close();
|
||||
if (out.checkError()) {
|
||||
out = null;
|
||||
tmpFile.delete();
|
||||
throw new IOException("Failed to write properties to " + tmpFile);
|
||||
}
|
||||
out = null;
|
||||
if (!FileUtil.rename(tmpFile, file))
|
||||
throw new IOException("Failed rename from " + tmpFile + " to " + file);
|
||||
} finally {
|
||||
if (out != null) out.close();
|
||||
if (fos != null) try { fos.close(); } catch (IOException e) {}
|
||||
}
|
||||
if (ioe != null)
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ public class MetaInfo
|
||||
private final int piece_length;
|
||||
private final byte[] piece_hashes;
|
||||
private final long length;
|
||||
private final int privateTorrent; // 0: not present; 1: = 1; -1: = 0
|
||||
private final boolean privateTorrent;
|
||||
private final List<List<String>> announce_list;
|
||||
private final String comment;
|
||||
private final String created_by;
|
||||
@ -97,7 +97,7 @@ public class MetaInfo
|
||||
this.piece_length = piece_length;
|
||||
this.piece_hashes = piece_hashes;
|
||||
this.length = length;
|
||||
this.privateTorrent = privateTorrent ? 1 : 0;
|
||||
this.privateTorrent = privateTorrent;
|
||||
this.announce_list = announce_list;
|
||||
this.comment = comment;
|
||||
this.created_by = created_by;
|
||||
@ -117,37 +117,9 @@ public class MetaInfo
|
||||
//infoMap = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preserves privateTorrent int value, for main()
|
||||
*
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public MetaInfo(String announce, String name, String name_utf8, List<List<String>> files, List<Long> lengths,
|
||||
int piece_length, byte[] piece_hashes, long length, int privateTorrent,
|
||||
List<List<String>> announce_list, String created_by, List<String> url_list, String comment)
|
||||
{
|
||||
this.announce = announce;
|
||||
this.name = name;
|
||||
this.name_utf8 = name_utf8;
|
||||
this.files = files == null ? null : Collections.unmodifiableList(files);
|
||||
this.files_utf8 = null;
|
||||
this.lengths = lengths == null ? null : Collections.unmodifiableList(lengths);
|
||||
this.piece_length = piece_length;
|
||||
this.piece_hashes = piece_hashes;
|
||||
this.length = length;
|
||||
this.privateTorrent = privateTorrent;
|
||||
this.announce_list = announce_list;
|
||||
this.comment = comment;
|
||||
this.created_by = created_by;
|
||||
this.creation_date = I2PAppContext.getGlobalContext().clock().now();
|
||||
this.url_list = url_list;
|
||||
this.attributes = null;
|
||||
this.info_hash = calculateInfoHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new MetaInfo from the given InputStream. The
|
||||
* InputStream must start with a correctly bencoded dictionary
|
||||
* InputStream must start with a correctly bencoded dictonary
|
||||
* describing the torrent.
|
||||
* Caller must close the stream.
|
||||
*/
|
||||
@ -172,7 +144,7 @@ public class MetaInfo
|
||||
|
||||
/**
|
||||
* Creates a new MetaInfo from a Map of BEValues and the SHA1 over
|
||||
* the original bencoded info dictionary (this is a hack, we could
|
||||
* the original bencoded info dictonary (this is a hack, we could
|
||||
* reconstruct the bencoded stream and recalculate the hash). Will
|
||||
* NOT throw a InvalidBEncodingException if the given map does not
|
||||
* contain a valid announce string.
|
||||
@ -214,20 +186,11 @@ public class MetaInfo
|
||||
if (val == null) {
|
||||
this.url_list = null;
|
||||
} else {
|
||||
List<String> urllist;
|
||||
try {
|
||||
List<BEValue> bl1 = val.getList();
|
||||
urllist = new ArrayList<String>(bl1.size());
|
||||
for (BEValue bev : bl1) {
|
||||
urllist.add(bev.getString());
|
||||
}
|
||||
} catch (InvalidBEncodingException ibee) {
|
||||
// BEP 19 says it's a list but the example there
|
||||
// is for a single byte string, and we've seen this
|
||||
// in the wild.
|
||||
urllist = Collections.singletonList(val.getString());
|
||||
List<BEValue> bl1 = val.getList();
|
||||
this.url_list = new ArrayList<String>(bl1.size());
|
||||
for (BEValue bev : bl1) {
|
||||
this.url_list.add(bev.getString());
|
||||
}
|
||||
this.url_list = urllist;
|
||||
}
|
||||
|
||||
// misc. optional top-level stuff
|
||||
@ -285,11 +248,10 @@ public class MetaInfo
|
||||
// Transmission does numbers. So does libtorrent.
|
||||
// We handle both as of 0.9.9.
|
||||
// We switch to storing as number as of 0.9.14.
|
||||
boolean privat = "1".equals(o) ||
|
||||
privateTorrent = "1".equals(o) ||
|
||||
((o instanceof Number) && ((Number) o).intValue() == 1);
|
||||
privateTorrent = privat ? 1 : -1;
|
||||
} else {
|
||||
privateTorrent = 0;
|
||||
privateTorrent = false;
|
||||
}
|
||||
|
||||
val = info.get("piece length");
|
||||
@ -506,14 +468,6 @@ public class MetaInfo
|
||||
* @since 0.9
|
||||
*/
|
||||
public boolean isPrivate() {
|
||||
return privateTorrent > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 0 (default), 1 (set to 1), -1 (set to 0)
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public int getPrivateTrackerStatus() {
|
||||
return privateTorrent;
|
||||
}
|
||||
|
||||
@ -775,10 +729,10 @@ public class MetaInfo
|
||||
if (name_utf8 != null)
|
||||
info.put("name.utf-8", new BEValue(DataHelper.getUTF8(name_utf8)));
|
||||
// BEP 27
|
||||
if (privateTorrent != 0)
|
||||
if (privateTorrent)
|
||||
// switched to number in 0.9.14
|
||||
//info.put("private", new BEValue(DataHelper.getUTF8("1")));
|
||||
info.put("private", new BEValue(Integer.valueOf(privateTorrent > 0 ? 1 : 0)));
|
||||
info.put("private", new BEValue(Integer.valueOf(1)));
|
||||
|
||||
info.put("piece length", new BEValue(Integer.valueOf(piece_length)));
|
||||
info.put("pieces", new BEValue(piece_hashes));
|
||||
@ -856,7 +810,7 @@ public class MetaInfo
|
||||
String announce = null;
|
||||
List<String> url_list = null;
|
||||
String comment = null;
|
||||
Getopt g = new Getopt("MetaInfo", args, "a:c:m:w:");
|
||||
Getopt g = new Getopt("Storage", args, "a:c:m:w:");
|
||||
try {
|
||||
int c;
|
||||
while ((c = g.getopt()) != -1) {
|
||||
@ -913,7 +867,7 @@ public class MetaInfo
|
||||
List<String> urls = url_list != null ? url_list : meta.getWebSeedURLs();
|
||||
// changes/adds creation date
|
||||
MetaInfo meta2 = new MetaInfo(an, meta.getName(), null, meta.getFiles(), meta.getLengths(),
|
||||
meta.getPieceLength(0), meta.getPieceHashes(), meta.getTotalLength(), meta.getPrivateTrackerStatus(),
|
||||
meta.getPieceLength(0), meta.getPieceHashes(), meta.getTotalLength(), meta.isPrivate(),
|
||||
meta.getAnnounceList(), cb, urls, cm);
|
||||
java.io.File from = new java.io.File(args[i]);
|
||||
java.io.File to = new java.io.File(args[i] + ".bak");
|
||||
|
@ -2,7 +2,6 @@ package org.klomp.snark;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutput;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
@ -44,7 +43,6 @@ class PartialPiece implements Comparable<PartialPiece> {
|
||||
private RandomAccessFile raf;
|
||||
private final int pclen;
|
||||
private final File tempDir;
|
||||
private final BitField bitfield;
|
||||
|
||||
private static final int BUFSIZE = PeerState.PARTSIZE;
|
||||
private static final ByteCache _cache = ByteCache.getInstance(16, BUFSIZE);
|
||||
@ -68,7 +66,6 @@ class PartialPiece implements Comparable<PartialPiece> {
|
||||
this.pclen = len;
|
||||
//this.createdTime = 0;
|
||||
this.tempDir = tempDir;
|
||||
bitfield = new BitField((len + PeerState.PARTSIZE - 1) / PeerState.PARTSIZE);
|
||||
|
||||
// temps for finals
|
||||
byte[] tbs = null;
|
||||
@ -101,27 +98,22 @@ class PartialPiece implements Comparable<PartialPiece> {
|
||||
//tfile = SecureFile.createTempFile("piece", null, tempDir);
|
||||
// debug
|
||||
tempfile = SecureFile.createTempFile("piece_" + piece.getId() + '_', null, tempDir);
|
||||
//I2PAppContext.getGlobalContext().logManager().getLog(PartialPiece.class).warn("Created " + tempfile);
|
||||
// tfile.deleteOnExit() ???
|
||||
raf = new RandomAccessFile(tempfile, "rw");
|
||||
// Do not preallocate the file space.
|
||||
// Not necessary to call setLength(), file is extended when written
|
||||
//traf.setLength(len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert this PartialPiece to a request for the next chunk.
|
||||
* Used by PeerState only.
|
||||
*
|
||||
* @return null if complete
|
||||
* Used by PeerState only. This depends on the downloaded value
|
||||
* as set by setDownloaded() or read().
|
||||
*/
|
||||
|
||||
public synchronized Request getRequest() {
|
||||
int chunk = off / PeerState.PARTSIZE;
|
||||
int sz = bitfield.size();
|
||||
for (int i = chunk; i < sz; i++) {
|
||||
if (!bitfield.get(i))
|
||||
return new Request(this, off, Math.min(pclen - off, PeerState.PARTSIZE));
|
||||
if (i == sz - 1)
|
||||
off = pclen;
|
||||
else
|
||||
off += PeerState.PARTSIZE;
|
||||
}
|
||||
return null;
|
||||
return new Request(this, this.off, Math.min(this.pclen - this.off, PeerState.PARTSIZE));
|
||||
}
|
||||
|
||||
/** piece number */
|
||||
@ -137,45 +129,28 @@ class PartialPiece implements Comparable<PartialPiece> {
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public synchronized boolean isComplete() {
|
||||
return bitfield.complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Have any chunks been downloaded?
|
||||
*
|
||||
* @since 0.9.63
|
||||
*/
|
||||
public synchronized boolean hasData() {
|
||||
return bitfield.count() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has this chunk been downloaded?
|
||||
*
|
||||
* @since 0.9.63
|
||||
*/
|
||||
public synchronized boolean hasChunk(int chunk) {
|
||||
return bitfield.get(chunk);
|
||||
}
|
||||
|
||||
/**
|
||||
* How many bytes are good - as set by read().
|
||||
* As of 0.9.63, accurately counts good bytes after "holes".
|
||||
* How many bytes are good - as set by setDownloaded() or read()
|
||||
*/
|
||||
public synchronized int getDownloaded() {
|
||||
if (bitfield.complete())
|
||||
return pclen;
|
||||
int sz = bitfield.count();
|
||||
int rv = sz * PeerState.PARTSIZE;
|
||||
int rem = pclen % PeerState.PARTSIZE;
|
||||
if (rem != 0 && bitfield.get(sz - 1))
|
||||
rv -= PeerState.PARTSIZE - rem;
|
||||
return rv;
|
||||
return this.off;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this if necessary before returning a PartialPiece to the PeerCoordinator.
|
||||
* We do not use a bitmap to track individual chunks received.
|
||||
* Any chunks after a 'hole' will be lost.
|
||||
* @since 0.9.1
|
||||
*/
|
||||
public synchronized void setDownloaded(int offset) {
|
||||
this.off = offset;
|
||||
}
|
||||
|
||||
/****
|
||||
public long getCreated() {
|
||||
return this.createdTime;
|
||||
}
|
||||
****/
|
||||
|
||||
/**
|
||||
* Piece must be complete.
|
||||
* The SHA1 hash of the completely read data.
|
||||
@ -225,47 +200,13 @@ class PartialPiece implements Comparable<PartialPiece> {
|
||||
*
|
||||
* @since 0.9.1
|
||||
*/
|
||||
public void read(DataInputStream din, int offset, int len, BandwidthListener bwl) throws IOException {
|
||||
if (offset % PeerState.PARTSIZE != 0)
|
||||
throw new IOException("Bad offset " + offset);
|
||||
int chunk = offset / PeerState.PARTSIZE;
|
||||
// We read the data before checking if we have the chunk,
|
||||
// because otherwise we'd have to break the peer connection
|
||||
public void read(DataInputStream din, int offset, int len) throws IOException {
|
||||
if (bs != null) {
|
||||
// Don't use readFully() so we may update the BandwidthListener as we go
|
||||
//in.readFully(bs, offset, len);
|
||||
int offs = offset;
|
||||
int toRead = len;
|
||||
while (toRead > 0) {
|
||||
int numRead = din.read(bs, offs, toRead);
|
||||
if (numRead < 0)
|
||||
throw new EOFException();
|
||||
offs += numRead;
|
||||
toRead -= numRead;
|
||||
bwl.downloaded(numRead);
|
||||
}
|
||||
din.readFully(bs, offset, len);
|
||||
synchronized (this) {
|
||||
if (bitfield.get(chunk)) {
|
||||
warn("Already have chunk " + chunk + " on " + this);
|
||||
} else {
|
||||
bitfield.set(chunk);
|
||||
if (this.off == offset) {
|
||||
this.off += len;
|
||||
// if this filled in a hole, advance off
|
||||
int sz = bitfield.size();
|
||||
for (int i = chunk + 1; i < sz; i++) {
|
||||
if (!bitfield.get(i))
|
||||
break;
|
||||
warn("Hole filled in before chunk " + i + " on " + this + ' ' + bitfield);
|
||||
if (i == sz - 1)
|
||||
off = pclen;
|
||||
else
|
||||
off += PeerState.PARTSIZE;
|
||||
}
|
||||
} else {
|
||||
warn("Out of order chunk " + chunk + " on " + this + ' ' + bitfield);
|
||||
}
|
||||
}
|
||||
// only works for in-order chunks
|
||||
if (this.off == offset)
|
||||
this.off += len;
|
||||
}
|
||||
} else {
|
||||
// read in fully before synching on raf
|
||||
@ -278,46 +219,15 @@ class PartialPiece implements Comparable<PartialPiece> {
|
||||
ba = null;
|
||||
tmp = new byte[len];
|
||||
}
|
||||
|
||||
// Don't use readFully() so we may update the BandwidthListener as we go
|
||||
//din.readFully(tmp);
|
||||
int offs = 0;
|
||||
int toRead = len;
|
||||
while (toRead > 0) {
|
||||
int numRead = din.read(tmp, offs, toRead);
|
||||
if (numRead < 0)
|
||||
throw new EOFException();
|
||||
offs += numRead;
|
||||
toRead -= numRead;
|
||||
bwl.downloaded(numRead);
|
||||
}
|
||||
|
||||
din.readFully(tmp);
|
||||
synchronized (this) {
|
||||
if (bitfield.get(chunk)) {
|
||||
warn("Already have chunk " + chunk + " on " + this);
|
||||
} else {
|
||||
if (raf == null)
|
||||
createTemp();
|
||||
raf.seek(offset);
|
||||
raf.write(tmp);
|
||||
bitfield.set(chunk);
|
||||
if (this.off == offset) {
|
||||
this.off += len;
|
||||
// if this filled in a hole, advance off
|
||||
int sz = bitfield.size();
|
||||
for (int i = chunk + 1; i < sz; i++) {
|
||||
if (!bitfield.get(i))
|
||||
break;
|
||||
warn("Hole filled in before chunk " + i + " on " + this + ' ' + bitfield);
|
||||
if (i == sz - 1)
|
||||
off = pclen;
|
||||
else
|
||||
off += PeerState.PARTSIZE;
|
||||
}
|
||||
} else {
|
||||
warn("Out of order chunk " + chunk + " on " + this + ' ' + bitfield);
|
||||
}
|
||||
}
|
||||
if (raf == null)
|
||||
createTemp();
|
||||
raf.seek(offset);
|
||||
raf.write(tmp);
|
||||
// only works for in-order chunks
|
||||
if (this.off == offset)
|
||||
this.off += len;
|
||||
}
|
||||
if (ba != null)
|
||||
_cache.release(ba, false);
|
||||
@ -373,10 +283,8 @@ class PartialPiece implements Comparable<PartialPiece> {
|
||||
public void release() {
|
||||
if (bs == null) {
|
||||
synchronized (this) {
|
||||
if (raf != null) {
|
||||
if (raf != null)
|
||||
locked_release();
|
||||
raf = null;
|
||||
}
|
||||
}
|
||||
//if (raf != null)
|
||||
// I2PAppContext.getGlobalContext().logManager().getLog(PartialPiece.class).warn("Released " + tempfile);
|
||||
@ -392,6 +300,7 @@ class PartialPiece implements Comparable<PartialPiece> {
|
||||
try {
|
||||
raf.close();
|
||||
} catch (IOException ioe) {
|
||||
I2PAppContext.getGlobalContext().logManager().getLog(PartialPiece.class).warn("Error closing " + raf, ioe);
|
||||
}
|
||||
tempfile.delete();
|
||||
}
|
||||
@ -405,7 +314,7 @@ class PartialPiece implements Comparable<PartialPiece> {
|
||||
int d = this.piece.compareTo(opp.piece);
|
||||
if (d != 0)
|
||||
return d;
|
||||
return opp.getDownloaded() - getDownloaded(); // reverse
|
||||
return opp.off - this.off; // reverse
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -428,13 +337,6 @@ class PartialPiece implements Comparable<PartialPiece> {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Partial(" + piece.getId() + ',' + off + ',' + getDownloaded() + ',' + pclen + ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public static void warn(String s) {
|
||||
I2PAppContext.getGlobalContext().logManager().getLog(PartialPiece.class).warn(s);
|
||||
return "Partial(" + piece.getId() + ',' + off + ',' + pclen + ')';
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ import net.i2p.util.Log;
|
||||
import org.klomp.snark.bencode.BEValue;
|
||||
import org.klomp.snark.bencode.InvalidBEncodingException;
|
||||
|
||||
public class Peer implements Comparable<Peer>, BandwidthListener
|
||||
public class Peer implements Comparable<Peer>
|
||||
{
|
||||
protected final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(getClass());
|
||||
// Identifying property, the peer id of the other side.
|
||||
@ -96,8 +96,6 @@ public class Peer implements Comparable<Peer>, BandwidthListener
|
||||
private final boolean _isIncoming;
|
||||
private int _totalCommentsSent;
|
||||
private int _maxPipeline = PeerState.MIN_PIPELINE;
|
||||
private long connected;
|
||||
private long pexLastSent;
|
||||
|
||||
/**
|
||||
* Outgoing connection.
|
||||
@ -241,7 +239,7 @@ public class Peer implements Comparable<Peer>, BandwidthListener
|
||||
*
|
||||
* @param uploadOnly if we are complete with skipped files, i.e. a partial seed
|
||||
*/
|
||||
public void runConnection(I2PSnarkUtil util, PeerListener listener, BandwidthListener bwl, BitField bitfield,
|
||||
public void runConnection(I2PSnarkUtil util, PeerListener listener, BitField bitfield,
|
||||
MagnetState mState, boolean uploadOnly) {
|
||||
if (state != null)
|
||||
throw new IllegalStateException("Peer already started");
|
||||
@ -290,7 +288,7 @@ public class Peer implements Comparable<Peer>, BandwidthListener
|
||||
|
||||
PeerConnectionIn in = new PeerConnectionIn(this, din);
|
||||
PeerConnectionOut out = new PeerConnectionOut(this, dout);
|
||||
PeerState s = new PeerState(this, listener, bwl, metainfo, in, out);
|
||||
PeerState s = new PeerState(this, listener, metainfo, in, out);
|
||||
|
||||
if ((options & OPTION_EXTENSION) != 0) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
@ -309,7 +307,6 @@ public class Peer implements Comparable<Peer>, BandwidthListener
|
||||
// We are up and running!
|
||||
state = s;
|
||||
magnetState = mState;
|
||||
connected = util.getContext().clock().now();
|
||||
listener.connected(this);
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
@ -654,17 +651,12 @@ public class Peer implements Comparable<Peer>, BandwidthListener
|
||||
return (s == null) || s.choked;
|
||||
}
|
||||
|
||||
/////// begin BandwidthListener interface ///////
|
||||
|
||||
/**
|
||||
* Increment the counter.
|
||||
* @since 0.8.4
|
||||
*/
|
||||
public void downloaded(int size) {
|
||||
downloaded.addAndGet(size);
|
||||
PeerState s = state;
|
||||
if (s != null)
|
||||
s.getBandwidthListener().downloaded(size);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -673,9 +665,6 @@ public class Peer implements Comparable<Peer>, BandwidthListener
|
||||
*/
|
||||
public void uploaded(int size) {
|
||||
uploaded.addAndGet(size);
|
||||
PeerState s = state;
|
||||
if (s != null)
|
||||
s.getBandwidthListener().uploaded(size);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -699,115 +688,13 @@ public class Peer implements Comparable<Peer>, BandwidthListener
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the average rate in Bps
|
||||
*/
|
||||
public long getUploadRate()
|
||||
{
|
||||
return PeerCoordinator.getRate(uploaded_old);
|
||||
}
|
||||
|
||||
public long getDownloadRate()
|
||||
{
|
||||
return PeerCoordinator.getRate(downloaded_old);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we send this many bytes?
|
||||
* Do NOT call uploaded() after this.
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public boolean shouldSend(int size) {
|
||||
PeerState s = state;
|
||||
if (s != null) {
|
||||
boolean rv = s.getBandwidthListener().shouldSend(size);
|
||||
if (rv)
|
||||
uploaded.addAndGet(size);
|
||||
return rv;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we request this many bytes?
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public boolean shouldRequest(int size) {
|
||||
PeerState s = state;
|
||||
if (s != null)
|
||||
return s.getBandwidthListener().shouldRequest(this, size);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we request this many bytes?
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public boolean shouldRequest(Peer peer, int size) {
|
||||
if (peer != this)
|
||||
return false;
|
||||
PeerState s = state;
|
||||
if (s != null)
|
||||
return s.getBandwidthListener().shouldRequest(this, size);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Current limit in Bps
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public long getUpBWLimit() {
|
||||
PeerState s = state;
|
||||
if (s != null)
|
||||
return s.getBandwidthListener().getUpBWLimit();
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is snark as a whole over its limit?
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public boolean overUpBWLimit()
|
||||
{
|
||||
PeerState s = state;
|
||||
if (s != null)
|
||||
return s.getBandwidthListener().overUpBWLimit();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Current limit in Bps
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public long getDownBWLimit() {
|
||||
PeerState s = state;
|
||||
if (s != null)
|
||||
return s.getBandwidthListener().getDownBWLimit();
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Are we currently over the limit?
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public boolean overDownBWLimit() {
|
||||
PeerState s = state;
|
||||
if (s != null)
|
||||
return s.getBandwidthListener().overDownBWLimit();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push the total uploaded/downloaded onto a RATE_DEPTH deep stack
|
||||
* Resets the downloaded and uploaded counters to zero.
|
||||
*/
|
||||
void setRateHistory() {
|
||||
long up = uploaded.getAndSet(0);
|
||||
PeerCoordinator.setRate(up, uploaded_old);
|
||||
long down = downloaded.getAndSet(0);
|
||||
PeerCoordinator.setRate(down, downloaded_old);
|
||||
public void resetCounters()
|
||||
{
|
||||
downloaded.set(0);
|
||||
uploaded.set(0);
|
||||
}
|
||||
|
||||
/////// end BandwidthListener interface ///////
|
||||
|
||||
public long getInactiveTime() {
|
||||
PeerState s = state;
|
||||
@ -874,6 +761,28 @@ public class Peer implements Comparable<Peer>, BandwidthListener
|
||||
return s.bitfield.complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Push the total uploaded/downloaded onto a RATE_DEPTH deep stack
|
||||
*/
|
||||
public void setRateHistory(long up, long down)
|
||||
{
|
||||
PeerCoordinator.setRate(up, uploaded_old);
|
||||
PeerCoordinator.setRate(down, downloaded_old);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 4-minute-average rate in Bps
|
||||
*/
|
||||
public long getUploadRate()
|
||||
{
|
||||
return PeerCoordinator.getRate(uploaded_old);
|
||||
}
|
||||
|
||||
public long getDownloadRate()
|
||||
{
|
||||
return PeerCoordinator.getRate(downloaded_old);
|
||||
}
|
||||
|
||||
/** @since 0.9.31 */
|
||||
int getTotalCommentsSent() {
|
||||
return _totalCommentsSent;
|
||||
@ -891,28 +800,4 @@ public class Peer implements Comparable<Peer>, BandwidthListener
|
||||
public boolean isWebPeer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* when did handshake complete?
|
||||
* @since 0.9.63
|
||||
*/
|
||||
public long getWhenConnected() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* when did we last send pex peers?
|
||||
* @since 0.9.63
|
||||
*/
|
||||
public long getPexLastSent() {
|
||||
return pexLastSent;
|
||||
}
|
||||
|
||||
/**
|
||||
* when did we last send pex peers?
|
||||
* @since 0.9.63
|
||||
*/
|
||||
public void setPexLastSent(long now) {
|
||||
pexLastSent = now;
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +113,8 @@ class PeerCheckerTask implements Runnable
|
||||
uploaded += upload;
|
||||
long download = peer.getDownloaded();
|
||||
downloaded += download;
|
||||
peer.setRateHistory();
|
||||
peer.setRateHistory(upload, download);
|
||||
peer.resetCounters();
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug(peer + ":"
|
||||
@ -126,9 +127,10 @@ class PeerCheckerTask implements Runnable
|
||||
}
|
||||
|
||||
// Choke a percentage of them rather than all so it isn't so drastic...
|
||||
// choke 3/8 of the time when seeding and 1/4 when leeching
|
||||
// unless this torrent is over the limit all by itself.
|
||||
// choke 5/8 of the time when seeding and 3/8 when leeching
|
||||
boolean overBWLimitChoke = upload > 0 &&
|
||||
((overBWLimit && (random.nextInt(8) > (coordinator.completed() ? 4 : 5))) ||
|
||||
((overBWLimit && (random.nextInt(8) > (coordinator.completed() ? 2 : 4))) ||
|
||||
(coordinator.overUpBWLimit(uploaded)));
|
||||
|
||||
// If we are at our max uploaders and we have lots of other
|
||||
|
@ -157,7 +157,7 @@ class PeerConnectionIn implements Runnable
|
||||
Request req = ps.getOutstandingRequest(piece, begin, len);
|
||||
if (req != null)
|
||||
{
|
||||
req.read(din, peer);
|
||||
req.read(din);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Received data(" + piece + "," + begin + ") from " + peer);
|
||||
ps.pieceMessage(req);
|
||||
|
@ -73,7 +73,6 @@ class PeerConnectionOut implements Runnable
|
||||
{
|
||||
try
|
||||
{
|
||||
boolean shouldThrottleRequests = false;
|
||||
while (!quit && peer.isConnected())
|
||||
{
|
||||
Message m = null;
|
||||
@ -90,7 +89,7 @@ class PeerConnectionOut implements Runnable
|
||||
|
||||
synchronized(sendQueue)
|
||||
{
|
||||
while (!quit && peer.isConnected() && (shouldThrottleRequests || sendQueue.isEmpty()))
|
||||
while (!quit && peer.isConnected() && sendQueue.isEmpty())
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -99,13 +98,12 @@ class PeerConnectionOut implements Runnable
|
||||
// dout.flush();
|
||||
|
||||
// Wait till more data arrives.
|
||||
sendQueue.wait(shouldThrottleRequests ? 5000 : 60*1000);
|
||||
sendQueue.wait(60*1000);
|
||||
}
|
||||
catch (InterruptedException ie)
|
||||
{
|
||||
/* ignored */
|
||||
}
|
||||
shouldThrottleRequests = false;
|
||||
}
|
||||
state = peer.state;
|
||||
if (!quit && state != null && peer.isConnected())
|
||||
@ -127,6 +125,7 @@ class PeerConnectionOut implements Runnable
|
||||
{
|
||||
if (state.choking) {
|
||||
it.remove();
|
||||
//SimpleTimer.getInstance().removeEvent(nm.expireEvent);
|
||||
if (peer.supportsFast()) {
|
||||
Message r = new Message(Message.REJECT, nm.piece, nm.begin, nm.length);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
@ -136,50 +135,23 @@ class PeerConnectionOut implements Runnable
|
||||
}
|
||||
nm = null;
|
||||
}
|
||||
else if (nm.type == Message.REQUEST)
|
||||
else if (nm.type == Message.REQUEST && state.choked)
|
||||
{
|
||||
if (state.choked) {
|
||||
it.remove();
|
||||
nm = null;
|
||||
} else if (shouldThrottleRequests) {
|
||||
// previous request in queue throttled, skip this one too
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Additional throttle: " + nm + " to " + peer);
|
||||
nm = null;
|
||||
} else if (!peer.shouldRequest(nm.length)) {
|
||||
// request throttle, skip this and all others in this loop
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Throttle: " + nm + " to " + peer);
|
||||
shouldThrottleRequests = true;
|
||||
nm = null;
|
||||
}
|
||||
it.remove();
|
||||
//SimpleTimer.getInstance().removeEvent(nm.expireEvent);
|
||||
nm = null;
|
||||
}
|
||||
|
||||
if (nm != null)
|
||||
{
|
||||
m = nm;
|
||||
//SimpleTimer.getInstance().removeEvent(nm.expireEvent);
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
if (m == null) {
|
||||
m = sendQueue.peek();
|
||||
if (m != null && m.type == Message.PIECE) {
|
||||
// bandwidth limiting
|
||||
// Pieces are the last thing in the queue to be sent so we can
|
||||
// simply wait right here and then loop
|
||||
if (!peer.shouldSend(Math.min(m.length, PeerState.PARTSIZE))) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Throttle: " + m + " to " + peer);
|
||||
try {
|
||||
sendQueue.wait(5000);
|
||||
} catch (InterruptedException ie) {}
|
||||
continue;
|
||||
}
|
||||
} else if (m != null && m.type == Message.REQUEST) {
|
||||
if (shouldThrottleRequests)
|
||||
continue;
|
||||
}
|
||||
m = sendQueue.poll();
|
||||
m = sendQueue.poll();
|
||||
//SimpleTimer.getInstance().removeEvent(m.expireEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -206,14 +178,17 @@ class PeerConnectionOut implements Runnable
|
||||
// only count the rest of the upload after sendMessage().
|
||||
int remainder = 0;
|
||||
if (m.type == Message.PIECE) {
|
||||
// first PARTSIZE was signalled in shouldSend() above
|
||||
if (m.len > PeerState.PARTSIZE)
|
||||
if (m.len <= PeerState.PARTSIZE) {
|
||||
state.uploaded(m.len);
|
||||
} else {
|
||||
state.uploaded(PeerState.PARTSIZE);
|
||||
remainder = m.len - PeerState.PARTSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
m.sendMessage(dout);
|
||||
if (remainder > 0)
|
||||
peer.uploaded(remainder);
|
||||
state.uploaded(remainder);
|
||||
m = null;
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ import org.klomp.snark.dht.DHT;
|
||||
/**
|
||||
* Coordinates what peer does what.
|
||||
*/
|
||||
class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
class PeerCoordinator implements PeerListener
|
||||
{
|
||||
private final Log _log;
|
||||
|
||||
@ -124,12 +124,6 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
/** Timer to handle all periodical tasks. */
|
||||
private final CheckEvent timer;
|
||||
|
||||
// RerequestEvent and related values
|
||||
private final SimpleTimer2.TimedEvent rerequestTimer;
|
||||
private final Object rerequestLock = new Object();
|
||||
private boolean wasRequestAllowed;
|
||||
private boolean isRerequestScheduled;
|
||||
|
||||
private final byte[] id;
|
||||
private final byte[] infohash;
|
||||
|
||||
@ -151,7 +145,6 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
|
||||
private final MagnetState magnetState;
|
||||
private final CoordinatorListener listener;
|
||||
private final BandwidthListener bwListener;
|
||||
private final I2PSnarkUtil _util;
|
||||
private final RandomSource _random;
|
||||
|
||||
@ -170,7 +163,7 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
* @param storage null if in magnet mode
|
||||
*/
|
||||
public PeerCoordinator(I2PSnarkUtil util, byte[] id, byte[] infohash, MetaInfo metainfo, Storage storage,
|
||||
CoordinatorListener listener, Snark torrent, BandwidthListener bwl)
|
||||
CoordinatorListener listener, Snark torrent)
|
||||
{
|
||||
_util = util;
|
||||
_random = util.getContext().random();
|
||||
@ -181,7 +174,6 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
this.storage = storage;
|
||||
this.listener = listener;
|
||||
this.snark = torrent;
|
||||
bwListener = bwl;
|
||||
|
||||
wantedPieces = new ArrayList<Piece>();
|
||||
setWantedPieces();
|
||||
@ -196,9 +188,6 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
timer = new CheckEvent(_util.getContext(), new PeerCheckerTask(_util, this));
|
||||
timer.schedule((CHECK_PERIOD / 2) + _random.nextInt((int) CHECK_PERIOD));
|
||||
|
||||
// NOT scheduled until needed
|
||||
rerequestTimer = new RerequestEvent();
|
||||
|
||||
// we don't store the last-requested time, so just delay a random amount
|
||||
_commentsLastRequested.set(util.getContext().clock().now() - (COMMENT_REQ_INTERVAL - _random.nextLong(COMMENT_REQ_DELAY)));
|
||||
}
|
||||
@ -219,42 +208,6 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rerequest after unthrottled
|
||||
* @since 0.9.62
|
||||
*/
|
||||
private class RerequestEvent extends SimpleTimer2.TimedEvent {
|
||||
/** caller must schedule */
|
||||
public RerequestEvent() {
|
||||
super(_util.getContext().simpleTimer2());
|
||||
}
|
||||
|
||||
public void timeReached() {
|
||||
if (bwListener.shouldRequest(null, 0)) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Now unthrottled, rerequest timer poking all peers");
|
||||
// so shouldRequest() won't fire us up again
|
||||
synchronized(rerequestLock) {
|
||||
wasRequestAllowed = true;
|
||||
}
|
||||
for (Peer p : peers) {
|
||||
if (p.isInteresting() && !p.isChoked())
|
||||
p.request();
|
||||
}
|
||||
synchronized(rerequestLock) {
|
||||
isRerequestScheduled = false;
|
||||
}
|
||||
} else {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Still throttled, rerequest timer reschedule");
|
||||
synchronized(rerequestLock) {
|
||||
wasRequestAllowed = false;
|
||||
}
|
||||
schedule(2*1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Only called externally from Storage after the double-check fails.
|
||||
* Sets wantedBytes too.
|
||||
@ -375,78 +328,6 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
return downloaded.get();
|
||||
}
|
||||
|
||||
/////// begin BandwidthListener interface ///////
|
||||
|
||||
/**
|
||||
* Called when a peer has uploaded some bytes of a piece.
|
||||
* @since 0.9.62 params changed
|
||||
*/
|
||||
public void uploaded(int size) {
|
||||
uploaded.addAndGet(size);
|
||||
bwListener.uploaded(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a peer has downloaded some bytes of a piece.
|
||||
* @since 0.9.62 params changed
|
||||
*/
|
||||
public void downloaded(int size) {
|
||||
downloaded.addAndGet(size);
|
||||
bwListener.downloaded(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we send this many bytes?
|
||||
* Do NOT call uploaded() if this returns true.
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public boolean shouldSend(int size) {
|
||||
boolean rv = bwListener.shouldSend(size);
|
||||
if (rv)
|
||||
uploaded.addAndGet(size);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we request this many bytes?
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public boolean shouldRequest(Peer peer, int size) {
|
||||
boolean rv;
|
||||
synchronized(rerequestLock) {
|
||||
rv = bwListener.shouldRequest(peer, size);
|
||||
if (!wasRequestAllowed && rv) {
|
||||
// we weren't allowed and now we are
|
||||
if (isRerequestScheduled) {
|
||||
// just let the timer run when scheduled, do not pull it in
|
||||
// to prevent thrashing
|
||||
//if (_log.shouldWarn())
|
||||
// _log.warn("Now unthrottled, BUT DON'T reschedule rerequest timer");
|
||||
} else {
|
||||
// schedule the timer
|
||||
// we still have to throw it to the timer so we don't loop
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Now unthrottled, schedule rerequest timer");
|
||||
isRerequestScheduled = true;
|
||||
// no rush, wait at little while
|
||||
rerequestTimer.reschedule(1000);
|
||||
}
|
||||
wasRequestAllowed = true;
|
||||
} else if (wasRequestAllowed && !rv) {
|
||||
// we were allowed and now we aren't
|
||||
if (!isRerequestScheduled) {
|
||||
// schedule the timer
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Now throttled, schedule rerequest timer");
|
||||
isRerequestScheduled = true;
|
||||
rerequestTimer.schedule(3*1000);
|
||||
}
|
||||
wasRequestAllowed = false;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push the total uploaded/downloaded onto a RATE_DEPTH deep stack
|
||||
*/
|
||||
@ -521,49 +402,6 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
return rate / (factor * CHECK_PERIOD / 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Current limit in Bps
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public long getUpBWLimit() {
|
||||
return bwListener.getUpBWLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is snark as a whole over its limit?
|
||||
*/
|
||||
public boolean overUpBWLimit()
|
||||
{
|
||||
return bwListener.overUpBWLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is a particular peer who has downloaded this many bytes from us
|
||||
* in the last CHECK_PERIOD over its limit?
|
||||
*/
|
||||
public boolean overUpBWLimit(long total)
|
||||
{
|
||||
return total * 1000 / CHECK_PERIOD > getUpBWLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Current limit in Bps
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public long getDownBWLimit() {
|
||||
return bwListener.getDownBWLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Are we currently over the limit?
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public boolean overDownBWLimit() {
|
||||
return bwListener.overDownBWLimit();
|
||||
}
|
||||
|
||||
/////// end BandwidthListener interface ///////
|
||||
|
||||
public MetaInfo getMetaInfo()
|
||||
{
|
||||
return metainfo;
|
||||
@ -614,12 +452,10 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
if (metainfo == null)
|
||||
return 6;
|
||||
int pieces = metainfo.getPieces();
|
||||
if (pieces <= 10)
|
||||
if (pieces <= 2)
|
||||
return 4;
|
||||
if (pieces <= 25)
|
||||
return 10;
|
||||
if (pieces <= 80)
|
||||
return 16;
|
||||
if (pieces <= 5)
|
||||
return 6;
|
||||
//int size = metainfo.getPieceLength(0);
|
||||
int max = _util.getMaxConnections();
|
||||
// Now that we use temp files, no memory concern
|
||||
@ -821,7 +657,7 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
peer.runConnection(_util, listener, PeerCoordinator.this, bitfield, magnetState, partialComplete);
|
||||
peer.runConnection(_util, listener, bitfield, magnetState, partialComplete);
|
||||
}
|
||||
};
|
||||
String threadName = "Snark peer " + peer.toString();
|
||||
@ -845,8 +681,6 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
{
|
||||
if (storage == null || storage.getBitField().size() == 0)
|
||||
return;
|
||||
if (overUpBWLimit())
|
||||
return;
|
||||
|
||||
// linked list will contain all interested peers that we choke.
|
||||
// At the start are the peers that have us unchoked at the end the
|
||||
@ -944,6 +778,15 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
*/
|
||||
private static final int MAX_PARALLEL_REQUESTS = 4;
|
||||
|
||||
/**
|
||||
* Returns one of pieces in the given BitField that is still wanted or
|
||||
* -1 if none of the given pieces are wanted.
|
||||
*/
|
||||
public int wantPiece(Peer peer, BitField havePieces) {
|
||||
Piece pc = wantPiece(peer, havePieces, true);
|
||||
return pc != null ? pc.getId() : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns one of pieces in the given BitField that is still wanted or
|
||||
* null if none of the given pieces are wanted.
|
||||
@ -1160,6 +1003,28 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a peer has uploaded some bytes of a piece.
|
||||
*/
|
||||
public void uploaded(Peer peer, int size)
|
||||
{
|
||||
uploaded.addAndGet(size);
|
||||
|
||||
//if (listener != null)
|
||||
// listener.peerChange(this, peer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a peer has downloaded some bytes of a piece.
|
||||
*/
|
||||
public void downloaded(Peer peer, int size)
|
||||
{
|
||||
downloaded.addAndGet(size);
|
||||
|
||||
//if (listener != null)
|
||||
// listener.peerChange(this, peer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false if the piece is no good (according to the hash).
|
||||
* In that case the peer that supplied the piece should probably be
|
||||
@ -1294,7 +1159,7 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
}
|
||||
if (uploaders.get() < allowedUploaders())
|
||||
{
|
||||
if(peer.isChoking() && !overUpBWLimit())
|
||||
if(peer.isChoking())
|
||||
{
|
||||
uploaders.incrementAndGet();
|
||||
interestedUploaders.incrementAndGet();
|
||||
@ -1352,7 +1217,7 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
* Also mark the piece unrequested if this peer was the only one.
|
||||
*
|
||||
* @param peer partials, must include the zero-offset (empty) ones too.
|
||||
* No dup pieces.
|
||||
* No dup pieces, piece.setDownloaded() must be set.
|
||||
* len field in Requests is ignored.
|
||||
* @since 0.8.2
|
||||
*/
|
||||
@ -1370,14 +1235,14 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
synchronized(wantedPieces) {
|
||||
for (Request req : partials) {
|
||||
PartialPiece pp = req.getPartialPiece();
|
||||
if (pp.hasData()) {
|
||||
if (req.off > 0) {
|
||||
// PartialPiece.equals() only compares piece number, which is what we want
|
||||
int idx = partialPieces.indexOf(pp);
|
||||
if (idx < 0) {
|
||||
partialPieces.add(pp);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Saving orphaned partial piece (new) " + pp);
|
||||
} else if (pp.getDownloaded() > partialPieces.get(idx).getDownloaded()) {
|
||||
} else if (idx >= 0 && pp.getDownloaded() > partialPieces.get(idx).getDownloaded()) {
|
||||
// replace what's there now
|
||||
partialPieces.get(idx).release();
|
||||
partialPieces.set(idx, pp);
|
||||
@ -1434,9 +1299,7 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
for(Piece piece : wantedPieces) {
|
||||
if (piece.getId() == savedPiece) {
|
||||
if (peer.isCompleted() && piece.getPeerCount() > 1 &&
|
||||
wantedPieces.size() > 2*END_GAME_THRESHOLD &&
|
||||
partialPieces.size() < 4 &&
|
||||
_random.nextInt(4) != 0) {
|
||||
wantedPieces.size() > 2*END_GAME_THRESHOLD) {
|
||||
// Try to preserve rarest-first
|
||||
// by not requesting a partial piece that at least two non-seeders also have
|
||||
// from a seeder
|
||||
@ -1464,7 +1327,7 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
iter.remove();
|
||||
piece.setRequested(peer, true);
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("Restoring orphaned partial piece " + pp + " to " + peer +
|
||||
_log.info("Restoring orphaned partial piece " + pp +
|
||||
" Partial list size now: " + partialPieces.size());
|
||||
}
|
||||
return pp;
|
||||
@ -1576,9 +1439,7 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
}
|
||||
}
|
||||
} else if (id == ExtensionHandler.ID_HANDSHAKE) {
|
||||
// We may not have the bitfield yet, but if we do, don't send PEX to seeds
|
||||
if (!peer.isCompleted())
|
||||
sendPeers(peer);
|
||||
sendPeers(peer);
|
||||
sendDHT(peer);
|
||||
if (_util.utCommentsEnabled())
|
||||
sendCommentReq(peer);
|
||||
@ -1587,8 +1448,8 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
|
||||
/**
|
||||
* Send a PEX message to the peer, if he supports PEX.
|
||||
* This sends everybody we have connected to since the
|
||||
* last time we sent PEX to him.
|
||||
* This just sends everybody we are connected to, we don't
|
||||
* track new vs. old peers yet.
|
||||
* @since 0.8.4
|
||||
*/
|
||||
void sendPeers(Peer peer) {
|
||||
@ -1602,25 +1463,14 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
return;
|
||||
try {
|
||||
if (bev.getMap().get(ExtensionHandler.TYPE_PEX) != null) {
|
||||
List<Peer> pList = new ArrayList<Peer>();
|
||||
long t = peer.getPexLastSent();
|
||||
for (Peer p : peers) {
|
||||
if (p.equals(peer))
|
||||
continue;
|
||||
if (p.isWebPeer())
|
||||
continue;
|
||||
if (p.getWhenConnected() > t)
|
||||
pList.add(p);
|
||||
List<Peer> pList = peerList();
|
||||
pList.remove(peer);
|
||||
for (Iterator<Peer> iter = pList.iterator(); iter.hasNext(); ) {
|
||||
if (iter.next().isWebPeer())
|
||||
iter.remove();
|
||||
}
|
||||
if (!pList.isEmpty()) {
|
||||
if (!pList.isEmpty())
|
||||
ExtensionHandler.sendPEX(peer, pList);
|
||||
peer.setPexLastSent(_util.getContext().clock().now());
|
||||
//if (_log.shouldDebug())
|
||||
// _log.debug("Pex: sent " + pList.size() + " new peers to " + peer);
|
||||
//} else {
|
||||
//if (_log.shouldDebug())
|
||||
// _log.debug("Pex: no new peers to send to " + peer);
|
||||
}
|
||||
}
|
||||
} catch (InvalidBEncodingException ibee) {}
|
||||
}
|
||||
@ -1888,6 +1738,27 @@ class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
interestedAndChoking.addAndGet(toAdd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is snark as a whole over its limit?
|
||||
*/
|
||||
public boolean overUpBWLimit()
|
||||
{
|
||||
if (listener != null)
|
||||
return listener.overUpBWLimit();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is a particular peer who has downloaded this many bytes from us
|
||||
* in the last CHECK_PERIOD over its limit?
|
||||
*/
|
||||
public boolean overUpBWLimit(long total)
|
||||
{
|
||||
if (listener != null)
|
||||
return listener.overUpBWLimit(total * 1000 / CHECK_PERIOD);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience
|
||||
* @since 0.9.2
|
||||
|
@ -120,6 +120,36 @@ interface PeerListener
|
||||
*/
|
||||
ByteArray gotRequest(Peer peer, int piece, int off, int len);
|
||||
|
||||
/**
|
||||
* Called when a (partial) piece has been downloaded from the peer.
|
||||
*
|
||||
* @param peer the Peer from which size bytes where downloaded.
|
||||
* @param size the number of bytes that where downloaded.
|
||||
*/
|
||||
void downloaded(Peer peer, int size);
|
||||
|
||||
/**
|
||||
* Called when a (partial) piece has been uploaded to the peer.
|
||||
*
|
||||
* @param peer the Peer to which size bytes where uploaded.
|
||||
* @param size the number of bytes that where uploaded.
|
||||
*/
|
||||
void uploaded(Peer peer, int size);
|
||||
|
||||
/**
|
||||
* Called when we are downloading from the peer and need to ask for
|
||||
* a new piece. Might be called multiple times before
|
||||
* <code>gotPiece()</code> is called.
|
||||
*
|
||||
* @param peer the Peer that will be asked to provide the piece.
|
||||
* @param bitfield a BitField containing the pieces that the other
|
||||
* side has.
|
||||
*
|
||||
* @return one of the pieces from the bitfield that we want or -1 if
|
||||
* we are no longer interested in the peer.
|
||||
*/
|
||||
int wantPiece(Peer peer, BitField bitfield);
|
||||
|
||||
/**
|
||||
* Called when we are downloading from the peer and may need to ask for
|
||||
* a new piece. Returns true if wantPiece() or getPartialPiece() would return a piece.
|
||||
|
@ -41,7 +41,6 @@ class PeerState implements DataLoader
|
||||
private final Peer peer;
|
||||
/** Fixme, used by Peer.disconnect() to get to the coordinator */
|
||||
final PeerListener listener;
|
||||
private final BandwidthListener bwListener;
|
||||
/** Null before we have it. locking: this */
|
||||
private MetaInfo metainfo;
|
||||
/** Null unless needed. Contains -1 for all. locking: this */
|
||||
@ -67,8 +66,7 @@ class PeerState implements DataLoader
|
||||
// Outstanding request
|
||||
private final List<Request> outstandingRequests = new ArrayList<Request>();
|
||||
/** the tail (NOT the head) of the request queue */
|
||||
private Request lastRequest;
|
||||
private int currentMaxPipeline;
|
||||
private Request lastRequest = null;
|
||||
|
||||
// FIXME if piece size < PARTSIZE, pipeline could be bigger
|
||||
/** @since 0.9.47 */
|
||||
@ -83,23 +81,17 @@ class PeerState implements DataLoader
|
||||
/**
|
||||
* @param metainfo null if in magnet mode
|
||||
*/
|
||||
PeerState(Peer peer, PeerListener listener, BandwidthListener bwl, MetaInfo metainfo,
|
||||
PeerState(Peer peer, PeerListener listener, MetaInfo metainfo,
|
||||
PeerConnectionIn in, PeerConnectionOut out)
|
||||
{
|
||||
this.peer = peer;
|
||||
this.listener = listener;
|
||||
bwListener = bwl;
|
||||
this.metainfo = metainfo;
|
||||
|
||||
this.in = in;
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.62
|
||||
*/
|
||||
BandwidthListener getBandwidthListener() { return bwListener; }
|
||||
|
||||
// NOTE Methods that inspect or change the state synchronize (on this).
|
||||
|
||||
void keepAliveMessage()
|
||||
@ -397,6 +389,7 @@ class PeerState implements DataLoader
|
||||
void uploaded(int size)
|
||||
{
|
||||
peer.uploaded(size);
|
||||
listener.uploaded(peer, size);
|
||||
}
|
||||
|
||||
// This is used to flag that we have to back up from the firstOutstandingRequest
|
||||
@ -415,8 +408,8 @@ class PeerState implements DataLoader
|
||||
void pieceMessage(Request req)
|
||||
{
|
||||
int size = req.len;
|
||||
// Now reported byte-by-byte in PartialPiece
|
||||
//peer.downloaded(size);
|
||||
peer.downloaded(size);
|
||||
listener.downloaded(peer, size);
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("got end of Chunk("
|
||||
@ -424,12 +417,11 @@ class PeerState implements DataLoader
|
||||
+ peer);
|
||||
|
||||
// Last chunk needed for this piece?
|
||||
PartialPiece pp = req.getPartialPiece();
|
||||
boolean complete = pp.isComplete();
|
||||
if (complete)
|
||||
// FIXME if priority changed to skip, we will think we're done when we aren't
|
||||
if (getFirstOutstandingRequest(req.getPiece()) == -1)
|
||||
{
|
||||
// warning - may block here for a while
|
||||
if (listener.gotPiece(peer, pp))
|
||||
if (listener.gotPiece(peer, req.getPartialPiece()))
|
||||
{
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Got " + req.getPiece() + ": " + peer);
|
||||
@ -450,31 +442,9 @@ class PeerState implements DataLoader
|
||||
synchronized(this) {
|
||||
pendingRequest = null;
|
||||
}
|
||||
|
||||
// getOutstandingRequest() was called by PeerConnectionIn at the start of the chunk;
|
||||
// if the bandwidth limiter throttled us to zero requests then, try again now
|
||||
if (outstandingRequests.isEmpty()) {
|
||||
addRequest();
|
||||
if (!complete) {
|
||||
synchronized(this) {
|
||||
if (outstandingRequests.isEmpty()) {
|
||||
// we MUST return the partial piece to PeerCoordinator,
|
||||
// or else we will lose it and leak the data
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Throttled, returned to coord. w/ data " + req);
|
||||
List<Request> pcs = Collections.singletonList(req);
|
||||
listener.savePartialPieces(this.peer, pcs);
|
||||
lastRequest = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO this is how we tell we got all the chunks in pieceMessage() above.
|
||||
*
|
||||
*
|
||||
* @return index in outstandingRequests or -1
|
||||
*/
|
||||
synchronized private int getFirstOutstandingRequest(int piece)
|
||||
@ -597,8 +567,15 @@ class PeerState implements DataLoader
|
||||
List<Request> rv = new ArrayList<Request>(pcs.size());
|
||||
for (Integer p : pcs) {
|
||||
Request req = getLowestOutstandingRequest(p.intValue());
|
||||
if (req != null)
|
||||
if (req != null) {
|
||||
PartialPiece pp = req.getPartialPiece();
|
||||
synchronized(pp) {
|
||||
int dl = pp.getDownloaded();
|
||||
if (req.off != dl)
|
||||
req = new Request(pp, dl);
|
||||
}
|
||||
rv.add(req);
|
||||
}
|
||||
}
|
||||
outstandingRequests.clear();
|
||||
pendingRequest = null;
|
||||
@ -722,6 +699,12 @@ class PeerState implements DataLoader
|
||||
|
||||
/**
|
||||
* BEP 6
|
||||
* If the peer rejects lower chunks but not higher ones, thus creating holes,
|
||||
* we won't figure it out and the piece will fail, since we don't currently
|
||||
* keep a chunk bitmap in PartialPiece.
|
||||
* As long as the peer rejects all the chunks, or rejects only the last chunks,
|
||||
* no holes are created and we will be fine. The reject messages may be in any order,
|
||||
* just don't make a hole when it's over.
|
||||
*
|
||||
* @since 0.9.21
|
||||
*/
|
||||
@ -745,10 +728,19 @@ class PeerState implements DataLoader
|
||||
}
|
||||
}
|
||||
if (deletedRequest != null && !haveMoreRequests) {
|
||||
List<Request> pcs = Collections.singletonList(deletedRequest);
|
||||
// We must return the piece to the coordinator
|
||||
// Create a new fake request so we can set the offset correctly
|
||||
PartialPiece pp = deletedRequest.getPartialPiece();
|
||||
int downloaded = pp.getDownloaded();
|
||||
Request req;
|
||||
if (deletedRequest.off == downloaded)
|
||||
req = deletedRequest;
|
||||
else
|
||||
req = new Request(pp, downloaded, 1);
|
||||
List<Request> pcs = Collections.singletonList(req);
|
||||
listener.savePartialPieces(this.peer, pcs);
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Returned to coord. w/ data " + deletedRequest.getPartialPiece().getDownloaded() + " due to reject(" + piece + ',' + begin + ',' + length + ") from " + peer);
|
||||
_log.warn("Returned to coord. w/ offset " + pp.getDownloaded() + " due to reject(" + piece + ',' + begin + ',' + length + ") from " + peer);
|
||||
}
|
||||
if (lastRequest != null && lastRequest.getPiece() == piece &&
|
||||
lastRequest.off == begin && lastRequest.len == length)
|
||||
@ -874,108 +866,72 @@ class PeerState implements DataLoader
|
||||
*
|
||||
* This is called from several places:
|
||||
*<pre>
|
||||
* By getOutstandingRequest() when the first part of a chunk comes in
|
||||
* By getOustandingRequest() when the first part of a chunk comes in
|
||||
* By havePiece() when somebody got a new piece completed
|
||||
* By chokeMessage() when we receive an unchoke
|
||||
* By setInteresting() when we are now interested
|
||||
* By PeerCoordinator.updatePiecePriorities()
|
||||
*</pre>
|
||||
*/
|
||||
void addRequest()
|
||||
synchronized void addRequest()
|
||||
{
|
||||
// no bitfield yet? nothing to request then.
|
||||
if (bitfield == null)
|
||||
return;
|
||||
if (metainfo == null)
|
||||
return;
|
||||
// Initial bw check. We do the actual accounting in PeerConnectionOut.
|
||||
// Implement a simple AIMD slow-start on the request queue size with
|
||||
// currentMaxPipeline counter.
|
||||
// Avoid cross-peer deadlocks from PeerCoordinator, call this outside the lock
|
||||
if (!bwListener.shouldRequest(peer, 0)) {
|
||||
synchronized(this) {
|
||||
// Due to changes elsewhere we can let this go down to zero now
|
||||
currentMaxPipeline /= 2;
|
||||
}
|
||||
if (_log.shouldWarn())
|
||||
_log.warn(peer + " throttle request, interesting? " + interesting + " choked? " + choked +
|
||||
" reqq: " + outstandingRequests.size() + " maxp: " + currentMaxPipeline);
|
||||
return;
|
||||
}
|
||||
synchronized(this) {
|
||||
// adjust currentMaxPipeline
|
||||
long rate = bwListener.getDownloadRate();
|
||||
long limit = bwListener.getDownBWLimit();
|
||||
if (rate < limit * 7 / 10) {
|
||||
if (currentMaxPipeline < peer.getMaxPipeline())
|
||||
currentMaxPipeline++;
|
||||
} else if (rate > limit * 9 / 10) {
|
||||
currentMaxPipeline = 1;
|
||||
} else if (currentMaxPipeline < 2) {
|
||||
currentMaxPipeline++;
|
||||
}
|
||||
boolean more_pieces = true;
|
||||
while (more_pieces)
|
||||
{
|
||||
more_pieces = outstandingRequests.size() < currentMaxPipeline;
|
||||
// We want something and we don't have outstanding requests?
|
||||
if (more_pieces && lastRequest == null) {
|
||||
// we have nothing in the queue right now
|
||||
if (!interesting) {
|
||||
// If we need something, set interesting but delay pulling
|
||||
// a request from the PeerCoordinator until unchoked.
|
||||
if (listener.needPiece(this.peer, bitfield)) {
|
||||
setInteresting(true);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(peer + " addRequest() we need something, setting interesting, delaying requestNextPiece()");
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(peer + " addRequest() needs nothing");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (choked) {
|
||||
// If choked, delay pulling
|
||||
// a request from the PeerCoordinator until unchoked.
|
||||
boolean more_pieces = true;
|
||||
while (more_pieces)
|
||||
{
|
||||
more_pieces = outstandingRequests.size() < peer.getMaxPipeline();
|
||||
// We want something and we don't have outstanding requests?
|
||||
if (more_pieces && lastRequest == null) {
|
||||
// we have nothing in the queue right now
|
||||
if (!interesting) {
|
||||
// If we need something, set interesting but delay pulling
|
||||
// a request from the PeerCoordinator until unchoked.
|
||||
if (listener.needPiece(this.peer, bitfield)) {
|
||||
setInteresting(true);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(peer + " addRequest() we are choked, delaying requestNextPiece()");
|
||||
return;
|
||||
_log.debug(peer + " addRequest() we need something, setting interesting, delaying requestNextPiece()");
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(peer + " addRequest() needs nothing");
|
||||
}
|
||||
more_pieces = requestNextPiece();
|
||||
} else if (more_pieces) // We want something
|
||||
{
|
||||
int pieceLength;
|
||||
boolean isLastChunk;
|
||||
pieceLength = metainfo.getPieceLength(lastRequest.getPiece());
|
||||
isLastChunk = lastRequest.off + lastRequest.len == pieceLength;
|
||||
return;
|
||||
}
|
||||
if (choked) {
|
||||
// If choked, delay pulling
|
||||
// a request from the PeerCoordinator until unchoked.
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(peer + " addRequest() we are choked, delaying requestNextPiece()");
|
||||
return;
|
||||
}
|
||||
// huh? rv unused
|
||||
more_pieces = requestNextPiece();
|
||||
} else if (more_pieces) // We want something
|
||||
{
|
||||
int pieceLength;
|
||||
boolean isLastChunk;
|
||||
pieceLength = metainfo.getPieceLength(lastRequest.getPiece());
|
||||
isLastChunk = lastRequest.off + lastRequest.len == pieceLength;
|
||||
|
||||
// Last part of a piece?
|
||||
if (isLastChunk) {
|
||||
more_pieces = requestNextPiece();
|
||||
} else {
|
||||
// Last part of a piece?
|
||||
if (isLastChunk)
|
||||
more_pieces = requestNextPiece();
|
||||
else
|
||||
{
|
||||
PartialPiece nextPiece = lastRequest.getPartialPiece();
|
||||
int nextBegin = lastRequest.off + PARTSIZE;
|
||||
while (true) {
|
||||
// don't rerequest chunks we already have
|
||||
if (!nextPiece.hasChunk(nextBegin / PARTSIZE)) {
|
||||
int maxLength = pieceLength - nextBegin;
|
||||
int nextLength = maxLength > PARTSIZE ? PARTSIZE
|
||||
: maxLength;
|
||||
Request req = new Request(nextPiece,nextBegin, nextLength);
|
||||
outstandingRequests.add(req);
|
||||
if (!choked)
|
||||
out.sendRequest(req);
|
||||
lastRequest = req;
|
||||
break;
|
||||
} else {
|
||||
nextBegin += PARTSIZE;
|
||||
if (nextBegin >= pieceLength) {
|
||||
more_pieces = requestNextPiece();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int maxLength = pieceLength - nextBegin;
|
||||
int nextLength = maxLength > PARTSIZE ? PARTSIZE
|
||||
: maxLength;
|
||||
Request req
|
||||
= new Request(nextPiece,nextBegin, nextLength);
|
||||
outstandingRequests.add(req);
|
||||
if (!choked)
|
||||
out.sendRequest(req);
|
||||
lastRequest = req;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1016,6 +972,47 @@ class PeerState implements DataLoader
|
||||
pp.release();
|
||||
}
|
||||
}
|
||||
|
||||
/******* getPartialPiece() does it all now
|
||||
// Note that in addition to the bitfield, PeerCoordinator uses
|
||||
// its request tracking and isRequesting() to determine
|
||||
// what piece to give us next.
|
||||
int nextPiece = listener.wantPiece(peer, bitfield);
|
||||
if (nextPiece != -1
|
||||
&& (lastRequest == null || lastRequest.getPiece() != nextPiece)) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(peer + " want piece " + nextPiece);
|
||||
// Fail safe to make sure we are interested
|
||||
// When we transition into the end game we may not be interested...
|
||||
if (!interesting) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(peer + " transition to end game, setting interesting");
|
||||
interesting = true;
|
||||
out.sendInterest(true);
|
||||
}
|
||||
|
||||
int piece_length = metainfo.getPieceLength(nextPiece);
|
||||
//Catch a common place for OOMs esp. on 1MB pieces
|
||||
byte[] bs;
|
||||
try {
|
||||
bs = new byte[piece_length];
|
||||
} catch (OutOfMemoryError oom) {
|
||||
_log.warn("Out of memory, can't request piece " + nextPiece, oom);
|
||||
return false;
|
||||
}
|
||||
|
||||
int length = Math.min(piece_length, PARTSIZE);
|
||||
Request req = new Request(nextPiece, bs, 0, length);
|
||||
outstandingRequests.add(req);
|
||||
if (!choked)
|
||||
out.sendRequest(req);
|
||||
lastRequest = req;
|
||||
return true;
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(peer + " no more pieces to request");
|
||||
}
|
||||
*******/
|
||||
}
|
||||
|
||||
// failsafe
|
||||
|
@ -74,8 +74,8 @@ class Request
|
||||
/**
|
||||
* @since 0.9.1
|
||||
*/
|
||||
public void read(DataInputStream din, BandwidthListener bwl) throws IOException {
|
||||
piece.read(din, off, len, bwl);
|
||||
public void read(DataInputStream din) throws IOException {
|
||||
piece.read(din, off, len);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -608,7 +608,7 @@ public class Snark
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Starting PeerCoordinator, ConnectionAcceptor, and TrackerClient");
|
||||
activity = "Collecting pieces";
|
||||
coordinator = new PeerCoordinator(_util, id, infoHash, meta, storage, this, this, completeListener.getBandwidthListener());
|
||||
coordinator = new PeerCoordinator(_util, id, infoHash, meta, storage, this, this);
|
||||
coordinator.setUploaded(savedUploaded);
|
||||
if (_peerCoordinatorSet != null) {
|
||||
// multitorrent
|
||||
@ -1335,9 +1335,6 @@ public class Snark
|
||||
*/
|
||||
public void replaceMetaInfo(MetaInfo metainfo) {
|
||||
meta = metainfo;
|
||||
TrackerClient tc = trackerclient;
|
||||
if (tc != null)
|
||||
tc.reinitialize();
|
||||
}
|
||||
|
||||
///////////// Begin StorageListener methods
|
||||
@ -1470,6 +1467,31 @@ public class Snark
|
||||
return totalUploaders > limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is i2psnark as a whole over its limit?
|
||||
*/
|
||||
public boolean overUpBWLimit() {
|
||||
if (_peerCoordinatorSet == null)
|
||||
return false;
|
||||
long total = 0;
|
||||
for (PeerCoordinator c : _peerCoordinatorSet) {
|
||||
if (!c.halted())
|
||||
total += c.getCurrentUploadRate();
|
||||
}
|
||||
long limit = 1024l * _util.getMaxUpBW();
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Total up bw: " + total + " Limit: " + limit);
|
||||
return total > limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is a particular peer who has this recent download rate (in Bps) over our upstream bandwidth limit?
|
||||
*/
|
||||
public boolean overUpBWLimit(long total) {
|
||||
long limit = 1024l * _util.getMaxUpBW();
|
||||
return total > limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* A unique ID for this torrent, useful for RPC
|
||||
* @return positive value unless you wrap around
|
||||
|
@ -25,12 +25,10 @@ import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.i2p.CoreVersion;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.app.ClientApp;
|
||||
import net.i2p.app.ClientAppManager;
|
||||
import net.i2p.app.ClientAppState;
|
||||
import net.i2p.app.NavService;
|
||||
import net.i2p.app.NotificationService;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.client.streaming.I2PSocketManager.DisconnectListener;
|
||||
@ -89,7 +87,6 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
private final I2PSnarkUtil _util;
|
||||
private final PeerCoordinatorSet _peerCoordinatorSet;
|
||||
private final ConnectionAcceptor _connectionAcceptor;
|
||||
private final BandwidthManager _bwManager;
|
||||
private Thread _monitor;
|
||||
private volatile boolean _running;
|
||||
private volatile boolean _stopping;
|
||||
@ -105,8 +102,6 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
//public static final String PROP_EEP_PORT = "i2psnark.eepPort";
|
||||
public static final String PROP_UPLOADERS_TOTAL = "i2psnark.uploaders.total";
|
||||
public static final String PROP_UPBW_MAX = "i2psnark.upbw.max";
|
||||
/** @since 0.9.62 */
|
||||
public static final String PROP_DOWNBW_MAX = "i2psnark.downbw.max";
|
||||
public static final String PROP_DIR = "i2psnark.dir";
|
||||
private static final String PROP_META_PREFIX = "i2psnark.zmeta.";
|
||||
private static final String PROP_META_RUNNING = "running";
|
||||
@ -132,7 +127,7 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
private static final String PROP_META_ACTIVITY = "activity";
|
||||
|
||||
private static final String CONFIG_FILE_SUFFIX = ".config";
|
||||
public static final String CONFIG_FILE = "i2psnark" + CONFIG_FILE_SUFFIX;
|
||||
private static final String CONFIG_FILE = "i2psnark" + CONFIG_FILE_SUFFIX;
|
||||
private static final String COMMENT_FILE_SUFFIX = ".comments.txt.gz";
|
||||
public static final String PROP_FILES_PUBLIC = "i2psnark.filesPublic";
|
||||
public static final String PROP_OLD_AUTO_START = "i2snark.autoStart"; // oops
|
||||
@ -167,25 +162,17 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
private static final String PROP_COMMENTS = "i2psnark.comments";
|
||||
/** @since 0.9.31 */
|
||||
private static final String PROP_COMMENTS_NAME = "i2psnark.commentsName";
|
||||
/** @since 0.9.58 */
|
||||
public static final String PROP_MAX_FILES_PER_TORRENT = "i2psnark.maxFilesPerTorrent";
|
||||
|
||||
public static final int MIN_UP_BW = 10;
|
||||
public static final int MIN_DOWN_BW = 2 * MIN_UP_BW;
|
||||
public static final int DEFAULT_MAX_UP_BW = 25;
|
||||
private static final int DEFAULT_MAX_DOWN_BW = 200;
|
||||
public static final int DEFAULT_STARTUP_DELAY = 3;
|
||||
public static final int DEFAULT_REFRESH_DELAY_SECS = 15;
|
||||
private static final int DEFAULT_PAGE_SIZE = 50;
|
||||
public static final int DEFAULT_TUNNEL_QUANTITY = 3;
|
||||
public static final int DEFAULT_MAX_FILES_PER_TORRENT = 2000;
|
||||
public static final String CONFIG_DIR_SUFFIX = ".d";
|
||||
private static final String SUBDIR_PREFIX = "s";
|
||||
private static final String B64 = Base64.ALPHABET_I2P;
|
||||
private static final int MAX_MESSAGES = 100;
|
||||
private static final String EXTRA = "";
|
||||
/** @since 0.9.58 */
|
||||
public static final String FULL_VERSION = CoreVersion.VERSION + EXTRA;
|
||||
|
||||
/**
|
||||
* "name", "announceURL=websiteURL" pairs
|
||||
@ -242,9 +229,7 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
// psi go - unregistered
|
||||
"uajd4nctepxpac4c4bdyrdw7qvja2a5u3x25otfhkptcjgd53ioq.b32.i2p",
|
||||
// Vuze - unregistered
|
||||
"crs2nugpvoqygnpabqbopwyjqettwszth6ubr2fh7whstlos3a6q.b32.i2p",
|
||||
"opentracker.r4sas.i2p", "punzipidirfqspstvzpj6gb4tkuykqp6quurj6e23bgxcxhdoe7q.b32.i2p",
|
||||
"opentracker.skank.i2p", "by7luzwhx733fhc5ug2o75dcaunblq2ztlshzd7qvptaoa73nqua.b32.i2p"
|
||||
"crs2nugpvoqygnpabqbopwyjqettwszth6ubr2fh7whstlos3a6q.b32.i2p"
|
||||
}));
|
||||
|
||||
static {
|
||||
@ -288,7 +273,6 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
_util = new I2PSnarkUtil(_context, ctxName, this);
|
||||
_peerCoordinatorSet = new PeerCoordinatorSet();
|
||||
_connectionAcceptor = new ConnectionAcceptor(_util, _peerCoordinatorSet);
|
||||
_bwManager = new BandwidthManager(ctx, DEFAULT_MAX_UP_BW * 1024, DEFAULT_MAX_DOWN_BW * 1024);
|
||||
DEFAULT_AUTO_START = !ctx.isRouterContext();
|
||||
String cfile = ctxName + CONFIG_FILE_SUFFIX;
|
||||
File configFile = new File(cfile);
|
||||
@ -307,21 +291,12 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
*/
|
||||
public void start() {
|
||||
_running = true;
|
||||
ClientAppManager cmgr = _context.clientAppManager();
|
||||
if ("i2psnark".equals(_contextName)) {
|
||||
// Register with the ClientAppManager so the rpc plugin can find us
|
||||
// only if default instance
|
||||
ClientAppManager cmgr = _context.clientAppManager();
|
||||
if (cmgr != null)
|
||||
cmgr.register(this);
|
||||
} else {
|
||||
// Register link with NavHelper
|
||||
if (cmgr != null) {
|
||||
NavService nav = (NavService) cmgr.getRegisteredApp("NavHelper");
|
||||
if (nav != null) {
|
||||
String name = DataHelper.stripHTML(_contextPath.substring(1));
|
||||
nav.registerApp(name, name, _contextPath, null, "/themes/console/images/i2psnark.png");
|
||||
}
|
||||
}
|
||||
}
|
||||
_monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor", true);
|
||||
_monitor.start();
|
||||
@ -402,20 +377,11 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
_connectionAcceptor.halt();
|
||||
_idleChecker.cancel();
|
||||
stopAllTorrents(true);
|
||||
ClientAppManager cmgr = _context.clientAppManager();
|
||||
if ("i2psnark".equals(_contextName)) {
|
||||
// only if default instance
|
||||
ClientAppManager cmgr = _context.clientAppManager();
|
||||
if (cmgr != null)
|
||||
cmgr.unregister(this);
|
||||
} else {
|
||||
// Unregister link with NavHelper
|
||||
if (cmgr != null) {
|
||||
NavService nav = (NavService) cmgr.getRegisteredApp("NavHelper");
|
||||
if (nav != null) {
|
||||
String name = DataHelper.stripHTML(_contextPath.substring(1));
|
||||
nav.unregisterApp(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Snark stop() end");
|
||||
@ -467,14 +433,6 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
/** hook to I2PSnarkUtil for the servlet */
|
||||
public I2PSnarkUtil util() { return _util; }
|
||||
|
||||
/**
|
||||
* The BandwidthManager.
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public BandwidthListener getBandwidthListener() {
|
||||
return _bwManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use if it does not include a link.
|
||||
* Escapes '<' and '>' before queueing
|
||||
@ -743,7 +701,7 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
File conf = configFile(_configDir, ih);
|
||||
synchronized(_configLock) { // one lock for all
|
||||
try {
|
||||
I2PSnarkUtil.loadProps(rv, conf);
|
||||
DataHelper.loadProps(rv, conf);
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
return rv;
|
||||
@ -984,21 +942,13 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
* @return true if we got a response from the router
|
||||
*/
|
||||
private boolean getBWLimit() {
|
||||
int[] limits = BWLimits.getBWLimits(_util.getI2CPHost(), _util.getI2CPPort());
|
||||
if (limits == null)
|
||||
return false;
|
||||
int up = limits[1];
|
||||
if (up > 0) {
|
||||
int maxup = getInt(PROP_UPBW_MAX, DEFAULT_MAX_UP_BW);
|
||||
if (maxup > up)
|
||||
maxup = up;
|
||||
_util.setMaxUpBW(maxup);
|
||||
_bwManager.setUpBWLimit(maxup * 1000L);
|
||||
}
|
||||
int down = limits[0];
|
||||
if (down > 0) {
|
||||
int maxdown = getInt(PROP_DOWNBW_MAX, DEFAULT_MAX_DOWN_BW);
|
||||
_bwManager.setDownBWLimit(Math.min(down, maxdown) * 1000L);
|
||||
boolean shouldSet = !_config.containsKey(PROP_UPBW_MAX);
|
||||
if (shouldSet || !_context.isRouterContext()) {
|
||||
int[] limits = BWLimits.getBWLimits(_util.getI2CPHost(), _util.getI2CPPort());
|
||||
if (limits == null)
|
||||
return false;
|
||||
if (shouldSet && limits[1] > 0)
|
||||
_util.setMaxUpBW(limits[1]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1027,7 +977,6 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
// _util.setProxy(eepHost, eepPort);
|
||||
_util.setMaxUploaders(getInt(PROP_UPLOADERS_TOTAL, Snark.MAX_TOTAL_UPLOADERS));
|
||||
_util.setMaxUpBW(getInt(PROP_UPBW_MAX, DEFAULT_MAX_UP_BW));
|
||||
_util.setMaxFilesPerTorrent(getInt(PROP_MAX_FILES_PER_TORRENT, DEFAULT_MAX_FILES_PER_TORRENT));
|
||||
_util.setStartupDelay(getInt(PROP_STARTUP_DELAY, DEFAULT_STARTUP_DELAY));
|
||||
_util.setFilesPublic(areFilesPublic());
|
||||
_util.setOpenTrackers(getListConfig(PROP_OPENTRACKERS, DEFAULT_OPENTRACKERS));
|
||||
@ -1070,13 +1019,13 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
public void updateConfig(String dataDir, boolean filesPublic, boolean autoStart, boolean smartSort, String refreshDelay,
|
||||
String startDelay, String pageSize, String seedPct, String eepHost,
|
||||
String eepPort, String i2cpHost, String i2cpPort, String i2cpOpts,
|
||||
String upLimit, String upBW, String downBW, boolean useOpenTrackers, boolean useDHT, String theme,
|
||||
String upLimit, String upBW, boolean useOpenTrackers, boolean useDHT, String theme,
|
||||
String lang, boolean enableRatings, boolean enableComments, String commentName, boolean collapsePanels) {
|
||||
synchronized(_configLock) {
|
||||
locked_updateConfig(dataDir, filesPublic, autoStart, smartSort, refreshDelay,
|
||||
startDelay, pageSize, seedPct, eepHost,
|
||||
eepPort, i2cpHost, i2cpPort, i2cpOpts,
|
||||
upLimit, upBW, downBW, useOpenTrackers, useDHT, theme,
|
||||
upLimit, upBW, useOpenTrackers, useDHT, theme,
|
||||
lang, enableRatings, enableComments, commentName, collapsePanels);
|
||||
}
|
||||
}
|
||||
@ -1084,7 +1033,7 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
private void locked_updateConfig(String dataDir, boolean filesPublic, boolean autoStart, boolean smartSort, String refreshDelay,
|
||||
String startDelay, String pageSize, String seedPct, String eepHost,
|
||||
String eepPort, String i2cpHost, String i2cpPort, String i2cpOpts,
|
||||
String upLimit, String upBW, String downBW, boolean useOpenTrackers, boolean useDHT, String theme,
|
||||
String upLimit, String upBW, boolean useOpenTrackers, boolean useDHT, String theme,
|
||||
String lang, boolean enableRatings, boolean enableComments, String commentName, boolean collapsePanels) {
|
||||
boolean changed = false;
|
||||
boolean interruptMonitor = false;
|
||||
@ -1122,7 +1071,6 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
if ( limit != _util.getMaxUpBW()) {
|
||||
if ( limit >= MIN_UP_BW ) {
|
||||
_util.setMaxUpBW(limit);
|
||||
_bwManager.setUpBWLimit(limit * 1000L);
|
||||
changed = true;
|
||||
_config.setProperty(PROP_UPBW_MAX, Integer.toString(limit));
|
||||
addMessage(_t("Up BW limit changed to {0}KBps", limit));
|
||||
@ -1131,20 +1079,6 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
}
|
||||
}
|
||||
}
|
||||
if (downBW != null) {
|
||||
int limit = (int) (_bwManager.getDownBWLimit() / 1024);
|
||||
try { limit = Integer.parseInt(downBW.trim()); } catch (NumberFormatException nfe) {}
|
||||
if ( limit != _bwManager.getDownBWLimit()) {
|
||||
if ( limit >= MIN_DOWN_BW ) {
|
||||
_bwManager.setDownBWLimit(limit * 1000L);
|
||||
changed = true;
|
||||
_config.setProperty(PROP_DOWNBW_MAX, Integer.toString(limit));
|
||||
//addMessage(_t("Up BW limit changed to {0}KBps", limit));
|
||||
} else {
|
||||
//addMessage(_t("Minimum up bandwidth limit is {0}KBps", MIN_UP_BW));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (startDelay != null && _context.isRouterContext()) {
|
||||
int minutes = _util.getStartupDelay();
|
||||
@ -1201,9 +1135,7 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
if (dataDir != null && !dataDir.equals(getDataDir().getAbsolutePath())) {
|
||||
dataDir = DataHelper.stripHTML(dataDir.trim());
|
||||
File dd = areFilesPublic() ? new File(dataDir) : new SecureDirectory(dataDir);
|
||||
if (_util.connected()) {
|
||||
addMessage(_t("Stop all torrents before changing data directory"));
|
||||
} else if (!dd.isAbsolute()) {
|
||||
if (!dd.isAbsolute()) {
|
||||
addMessage(_t("Data directory must be an absolute path") + ": " + dataDir);
|
||||
} else if (!dd.exists() && !dd.mkdirs()) {
|
||||
// save this tag for now, may need it again
|
||||
@ -1219,16 +1151,10 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
addMessage(_t("No write permissions for data directory") + ": " + dataDir);
|
||||
changed = true;
|
||||
interruptMonitor = true;
|
||||
synchronized (_snarks) {
|
||||
for (Snark snark : _snarks.values()) {
|
||||
// leave magnets alone, remove everything else
|
||||
if (snark.getMetaInfo() != null)
|
||||
stopTorrent(snark, true);
|
||||
}
|
||||
_config.setProperty(PROP_DIR, dataDir);
|
||||
}
|
||||
_config.setProperty(PROP_DIR, dataDir);
|
||||
addMessage(_t("Data directory changed to {0}", dataDir));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Standalone (app context) language.
|
||||
@ -1306,9 +1232,7 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
Properties p = new Properties();
|
||||
p.putAll(opts);
|
||||
_util.setI2CPConfig(i2cpHost, port, p);
|
||||
int max = getInt(PROP_UPBW_MAX, DEFAULT_MAX_UP_BW);
|
||||
_util.setMaxUpBW(max);
|
||||
_bwManager.setUpBWLimit(max * 1000);
|
||||
_util.setMaxUpBW(getInt(PROP_UPBW_MAX, DEFAULT_MAX_UP_BW));
|
||||
addMessage(_t("I2CP and tunnel changes will take effect after stopping all torrents"));
|
||||
} else if (!reconnect) {
|
||||
// The usual case, the other two are if not in router context
|
||||
@ -1323,9 +1247,7 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
}
|
||||
addMessage(_t("I2CP settings changed to {0}", i2cpHost + ':' + port + ' ' + i2cpOpts));
|
||||
_util.setI2CPConfig(i2cpHost, port, opts);
|
||||
int max = getInt(PROP_UPBW_MAX, DEFAULT_MAX_UP_BW);
|
||||
_util.setMaxUpBW(max);
|
||||
_bwManager.setUpBWLimit(max * 1000);
|
||||
_util.setMaxUpBW(getInt(PROP_UPBW_MAX, DEFAULT_MAX_UP_BW));
|
||||
boolean ok = _util.connect();
|
||||
if (!ok) {
|
||||
addMessage(_t("Unable to connect with the new settings, reverting to the old I2CP settings"));
|
||||
@ -1534,6 +1456,9 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
}
|
||||
}
|
||||
|
||||
/** hardcoded for sanity. perhaps this should be customizable, for people who increase their ulimit, etc. */
|
||||
public static final int MAX_FILES_PER_TORRENT = 2000;
|
||||
|
||||
/**
|
||||
* Set of canonical .torrent filenames that we are dealing with.
|
||||
* An unsynchronized copy.
|
||||
@ -2360,7 +2285,7 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
if (!subdir.exists())
|
||||
subdir.mkdirs();
|
||||
try {
|
||||
I2PSnarkUtil.storeProps(config, conf);
|
||||
DataHelper.storeProps(config, conf);
|
||||
if (_log.shouldInfo())
|
||||
_log.info("Saved config to " + conf /* , new Exception() */ );
|
||||
} catch (IOException ioe) {
|
||||
@ -2502,11 +2427,8 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
*/
|
||||
private String validateTorrent(MetaInfo info) {
|
||||
List<List<String>> files = info.getFiles();
|
||||
if (files != null && files.size() > _util.getMaxFilesPerTorrent()) {
|
||||
return _t("Too many files in \"{0}\" ({1})!", info.getName(), files.size()) +
|
||||
" - limit is " + _util.getMaxFilesPerTorrent() + ", zip them or set " +
|
||||
PROP_MAX_FILES_PER_TORRENT + '=' + files.size() + " in " +
|
||||
_configFile.getAbsolutePath() + " and restart";
|
||||
if ( (files != null) && (files.size() > MAX_FILES_PER_TORRENT) ) {
|
||||
return _t("Too many files in \"{0}\" ({1})!", info.getName(), files.size());
|
||||
} else if ( (files == null) && (info.getName().endsWith(".torrent")) ) {
|
||||
return _t("Torrent file \"{0}\" cannot end in \".torrent\"!", info.getName());
|
||||
} else if (info.getPieces() <= 0) {
|
||||
@ -2625,9 +2547,6 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
|
||||
// Remove that first message
|
||||
_messages.clearThrough(id);
|
||||
} else if (_context.isRouterContext()) {
|
||||
// to wait for client manager to be up so we can get bandwidth limits
|
||||
try { Thread.sleep(3000); } catch (InterruptedException ie) {}
|
||||
}
|
||||
|
||||
// here because we need to delay until I2CP is up
|
||||
@ -2695,8 +2614,7 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
}
|
||||
}
|
||||
if (routerOK)
|
||||
addMessage(_t("Down bandwidth limit is {0} KBps", _bwManager.getUpBWLimit() / 1024) + "; " +
|
||||
_t("Up bandwidth limit is {0} KBps", _util.getMaxUpBW()));
|
||||
addMessage(_t("Up bandwidth limit is {0} KBps", _util.getMaxUpBW()));
|
||||
}
|
||||
} else {
|
||||
autostart = false;
|
||||
@ -2962,7 +2880,6 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("DirMon found: " + DataHelper.toString(foundNames) + " existing: " + DataHelper.toString(existingNames));
|
||||
// lets find new ones first...
|
||||
int count = 0;
|
||||
for (String name : foundNames) {
|
||||
if (existingNames.contains(name)) {
|
||||
// already known. noop
|
||||
@ -2990,10 +2907,6 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
disableTorrentFile(name);
|
||||
rv = false;
|
||||
}
|
||||
if (shouldStart && (count++ & 0x0f) == 15) {
|
||||
// try to prevent OOMs at startup
|
||||
try { Thread.sleep(250); } catch (InterruptedException ie) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Don't remove magnet torrents that don't have a torrent file yet
|
||||
@ -3173,19 +3086,21 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
}
|
||||
|
||||
/**
|
||||
* Always thread it
|
||||
* If not connected, thread it, otherwise inline
|
||||
* @since 0.9.1
|
||||
*/
|
||||
public void startAllTorrents() {
|
||||
if (!_util.connected()) {
|
||||
if (_util.connected()) {
|
||||
startAll();
|
||||
} else {
|
||||
addMessage(_t("Opening the I2P tunnel and starting all torrents."));
|
||||
for (Snark snark : _snarks.values()) {
|
||||
// mark it for the UI
|
||||
snark.setStarting();
|
||||
}
|
||||
(new I2PAppThread(new ThreadedStarter(null), "TorrentStarterAll", true)).start();
|
||||
try { Thread.sleep(200); } catch (InterruptedException ie) {}
|
||||
}
|
||||
(new I2PAppThread(new ThreadedStarter(null), "TorrentStarterAll", true)).start();
|
||||
try { Thread.sleep(200); } catch (InterruptedException ie) {}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3215,7 +3130,6 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
* @since 0.9.1
|
||||
*/
|
||||
private void startAll() {
|
||||
int count = 0;
|
||||
for (Snark snark : _snarks.values()) {
|
||||
if (snark.isStopped()) {
|
||||
try {
|
||||
@ -3223,10 +3137,6 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
} catch (RuntimeException re) {
|
||||
// Snark.fatal() will log and call fatal() here for user message before throwing
|
||||
}
|
||||
if ((count++ & 0x0f) == 15) {
|
||||
// try to prevent OOMs
|
||||
try { Thread.sleep(250); } catch (InterruptedException ie) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3245,29 +3155,7 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
if (finalShutdown && _log.shouldLog(Log.WARN))
|
||||
_log.warn("SnarkManager final shutdown");
|
||||
int count = 0;
|
||||
Collection<Snark> snarks = _snarks.values();
|
||||
// We do two passes so we shutdown the high-priority snarks first.
|
||||
// Pass 1: All running, incomplete torrents,
|
||||
// to make sure the status gets saved so there will be no recheck on restart.
|
||||
for (Snark snark : snarks) {
|
||||
if (!snark.isStopped()) {
|
||||
Storage storage = snark.getStorage();
|
||||
if (storage != null && !storage.complete()) {
|
||||
if (count == 0)
|
||||
addMessage(_t("Stopping all torrents and closing the I2P tunnel."));
|
||||
count++;
|
||||
if (finalShutdown)
|
||||
snark.stopTorrent(true);
|
||||
else
|
||||
stopTorrent(snark, false);
|
||||
if (count % 8 == 0) {
|
||||
try { Thread.sleep(20); } catch (InterruptedException ie) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Pass 2: All the rest of the torrents
|
||||
for (Snark snark : snarks) {
|
||||
for (Snark snark : _snarks.values()) {
|
||||
if (!snark.isStopped()) {
|
||||
if (count == 0)
|
||||
addMessage(_t("Stopping all torrents and closing the I2P tunnel."));
|
||||
|
@ -87,7 +87,7 @@ public class Storage implements Closeable
|
||||
/** bigger than this will be rejected */
|
||||
public static final int MAX_PIECE_SIZE = 32*1024*1024;
|
||||
/** The maximum number of pieces in a torrent. */
|
||||
public static final int MAX_PIECES = 64*1024;
|
||||
public static final int MAX_PIECES = 32*1024;
|
||||
public static final long MAX_TOTAL_SIZE = MAX_PIECE_SIZE * (long) MAX_PIECES;
|
||||
public static final int PRIORITY_SKIP = -9;
|
||||
public static final int PRIORITY_NORMAL = 0;
|
||||
@ -288,15 +288,9 @@ public class Storage implements Closeable
|
||||
* @throws IOException if too many total files
|
||||
*/
|
||||
private void addFiles(List<File> l, File f) throws IOException {
|
||||
int max = _util.getMaxFilesPerTorrent();
|
||||
if (!f.isDirectory()) {
|
||||
int sz = l.size() + 1;
|
||||
if (sz > max)
|
||||
throw new IOException(_util.getString("Too many files in \"{0}\" ({1})!",
|
||||
(metainfo != null ? metainfo.getName() : _base.toString()), sz) +
|
||||
" - limit is " + max + ", zip them or set " +
|
||||
SnarkManager.PROP_MAX_FILES_PER_TORRENT + '=' + sz + " in " +
|
||||
SnarkManager.CONFIG_FILE + " and restart");
|
||||
if (l.size() >= SnarkManager.MAX_FILES_PER_TORRENT)
|
||||
throw new IOException("Too many files, limit is " + SnarkManager.MAX_FILES_PER_TORRENT + ", zip them?");
|
||||
l.add(f);
|
||||
} else {
|
||||
File[] files = f.listFiles();
|
||||
@ -307,13 +301,6 @@ public class Storage implements Closeable
|
||||
+ "' not a normal file.");
|
||||
return;
|
||||
}
|
||||
int sz = l.size() + files.length;
|
||||
if (sz > max)
|
||||
throw new IOException(_util.getString("Too many files in \"{0}\" ({1})!",
|
||||
(metainfo != null ? metainfo.getName() : _base.toString()), sz) +
|
||||
" - limit is " + max + ", zip them or set " +
|
||||
SnarkManager.PROP_MAX_FILES_PER_TORRENT + '=' + sz + " in " +
|
||||
SnarkManager.CONFIG_FILE + " and restart");
|
||||
for (int i = 0; i < files.length; i++)
|
||||
addFiles(l, files[i]);
|
||||
}
|
||||
@ -913,10 +900,7 @@ public class Storage implements Closeable
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||||
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
||||
// unicode newlines
|
||||
0x2028, 0x2029,
|
||||
// LTR/RTL
|
||||
// https://security.stackexchange.com/questions/158802/how-can-this-executable-have-an-avi-extension
|
||||
0x202a, 0x202b, 0x202c, 0x202d, 0x202e, 0x200e, 0x200f
|
||||
0x2028, 0x2029
|
||||
};
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file
|
||||
|
@ -94,8 +94,7 @@ public class TrackerClient implements Runnable {
|
||||
private static final Hash DSA_ONLY_TRACKER = ConvertToHash.getHash("cfmqlafjfmgkzbt4r3jsfyhgsr5abgxryl6fnz3d3y5a365di5aa.b32.i2p");
|
||||
|
||||
private final I2PSnarkUtil _util;
|
||||
// non-final for reinitialize()
|
||||
private MetaInfo meta;
|
||||
private final MetaInfo meta;
|
||||
private final String infoHash;
|
||||
private final String peerID;
|
||||
private final String additionalTrackerURL;
|
||||
@ -267,22 +266,8 @@ public class TrackerClient implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call after editing torrent
|
||||
* @since 0.9.57
|
||||
*/
|
||||
public synchronized void reinitialize() {
|
||||
if (!_initialized || !stop)
|
||||
return;
|
||||
trackers.clear();
|
||||
backupTrackers.clear();
|
||||
meta = snark.getMetaInfo();
|
||||
setup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do this one time only (not every time it is started).
|
||||
* Unless torrent was edited.
|
||||
* @since 0.9.1
|
||||
*/
|
||||
private void setup() {
|
||||
|
@ -128,7 +128,7 @@ class UDPTrackerClient implements I2PSessionMuxedListener {
|
||||
*
|
||||
* @param ih the Info Hash (torrent)
|
||||
* @param max maximum number of peers to return
|
||||
* @param maxWait the maximum time to wait (ms) must be greater than 0
|
||||
* @param maxWait the maximum time to wait (ms) must be > 0
|
||||
* @param fast if true, don't wait for dest, no retx, ...
|
||||
* @return null on fail or if fast is true
|
||||
*/
|
||||
|
@ -319,13 +319,6 @@ class UpdateRunner implements UpdateTask, CompleteListener {
|
||||
return _smgr.shouldAutoStart();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public BandwidthListener getBandwidthListener() {
|
||||
return _smgr.getBandwidthListener();
|
||||
}
|
||||
|
||||
//////// end CompleteListener methods
|
||||
|
||||
private static String linkify(String url) {
|
||||
|
@ -122,7 +122,7 @@ class WebPeer extends Peer implements EepGet.StatusListener {
|
||||
* @param uploadOnly if we are complete with skipped files, i.e. a partial seed
|
||||
*/
|
||||
@Override
|
||||
public void runConnection(I2PSnarkUtil util, PeerListener listener, BandwidthListener bwl, BitField ignore,
|
||||
public void runConnection(I2PSnarkUtil util, PeerListener listener, BitField ignore,
|
||||
MagnetState mState, boolean uploadOnly) {
|
||||
if (uploadOnly)
|
||||
return;
|
||||
@ -204,8 +204,6 @@ class WebPeer extends Peer implements EepGet.StatusListener {
|
||||
if (i >= maxRequests)
|
||||
break;
|
||||
Request r = outstandingRequests.get(i);
|
||||
if (!shouldRequest(r.len))
|
||||
break;
|
||||
if (r.getPiece() == piece &&
|
||||
lastRequest.off + lastRequest.len == r.off) {
|
||||
requests.add(r);
|
||||
@ -342,7 +340,7 @@ class WebPeer extends Peer implements EepGet.StatusListener {
|
||||
Request req = iter.next();
|
||||
if (dis.available() < req.len)
|
||||
break;
|
||||
req.read(dis, this);
|
||||
req.read(dis);
|
||||
iter.remove();
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Saved chunk " + req + " recvd before failure");
|
||||
@ -365,13 +363,13 @@ class WebPeer extends Peer implements EepGet.StatusListener {
|
||||
_log.debug("Fetch of piece: " + piece + " chunks: " + requests.size() + " offset: " + off + " torrent offset: " + toff + " len: " + tlen + " successful");
|
||||
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(out.toByteArray()));
|
||||
for (Request req : requests) {
|
||||
req.read(dis, this);
|
||||
req.read(dis);
|
||||
}
|
||||
|
||||
PartialPiece pp = last.getPartialPiece();
|
||||
synchronized(pp) {
|
||||
// Last chunk needed for this piece?
|
||||
if (pp.isComplete()) {
|
||||
if (pp.getLength() == pp.getDownloaded()) {
|
||||
if (listener.gotPiece(this, pp)) {
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Got " + piece + ": " + this);
|
||||
@ -521,29 +519,6 @@ class WebPeer extends Peer implements EepGet.StatusListener {
|
||||
return false;
|
||||
}
|
||||
|
||||
// begin BandwidthListener interface overrides
|
||||
// Because super doesn't have a PeerState
|
||||
|
||||
/**
|
||||
* @since 0.9.62
|
||||
*/
|
||||
@Override
|
||||
public void downloaded(int size) {
|
||||
super.downloaded(size);
|
||||
_coordinator.downloaded(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we request this many bytes?
|
||||
* @since 0.9.62
|
||||
*/
|
||||
@Override
|
||||
public boolean shouldRequest(int size) {
|
||||
return _coordinator.shouldRequest(this, size);
|
||||
}
|
||||
|
||||
// end BandwidthListener interface overrides
|
||||
|
||||
// private methods below here implementing parts of PeerState
|
||||
|
||||
private synchronized void addRequest() {
|
||||
@ -573,8 +548,7 @@ class WebPeer extends Peer implements EepGet.StatusListener {
|
||||
Request req = new Request(nextPiece,nextBegin, nextLength);
|
||||
outstandingRequests.add(req);
|
||||
lastRequest = req;
|
||||
if (shouldRequest(maxLength))
|
||||
this.notifyAll();
|
||||
this.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -593,8 +567,7 @@ class WebPeer extends Peer implements EepGet.StatusListener {
|
||||
Request r = pp.getRequest();
|
||||
outstandingRequests.add(r);
|
||||
lastRequest = r;
|
||||
if (shouldRequest(r.len))
|
||||
this.notifyAll();
|
||||
this.notifyAll();
|
||||
return true;
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
@ -650,8 +623,15 @@ class WebPeer extends Peer implements EepGet.StatusListener {
|
||||
List<Request> rv = new ArrayList<Request>(pcs.size());
|
||||
for (Integer p : pcs) {
|
||||
Request req = getLowestOutstandingRequest(p.intValue());
|
||||
if (req != null)
|
||||
if (req != null) {
|
||||
PartialPiece pp = req.getPartialPiece();
|
||||
synchronized(pp) {
|
||||
int dl = pp.getDownloaded();
|
||||
if (req.off != dl)
|
||||
req = new Request(pp, dl);
|
||||
}
|
||||
rv.add(req);
|
||||
}
|
||||
}
|
||||
outstandingRequests.clear();
|
||||
return rv;
|
||||
@ -673,6 +653,8 @@ class WebPeer extends Peer implements EepGet.StatusListener {
|
||||
|
||||
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {
|
||||
lastRcvd = System.currentTimeMillis();
|
||||
downloaded(currentWrite);
|
||||
listener.downloaded(this, currentWrite);
|
||||
}
|
||||
|
||||
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {}
|
||||
|
@ -294,7 +294,7 @@ public class BDecoder
|
||||
|
||||
/**
|
||||
* Returns the next bencoded value on the stream and makes sure it
|
||||
* is a map (dictionary). If it is not a map it will throw
|
||||
* is a map (dictonary). If it is not a map it will throw
|
||||
* InvalidBEncodingException.
|
||||
*/
|
||||
public BEValue bdecodeMap() throws IOException
|
||||
@ -311,7 +311,7 @@ public class BDecoder
|
||||
c = getNextIndicator();
|
||||
while (c != 'e')
|
||||
{
|
||||
// Dictionary keys are always strings.
|
||||
// Dictonary keys are always strings.
|
||||
String key = bdecode().getString();
|
||||
|
||||
// XXX ugly hack
|
||||
|
@ -32,7 +32,7 @@ public class Comment implements Comparable<Comment> {
|
||||
public static final int MAX_NAME_LEN = 32;
|
||||
// same as IRC, more or less
|
||||
private static final int MAX_TEXT_LEN = 512;
|
||||
private static final int BUCKET_SIZE = 4*60*60*1000;
|
||||
private static final int BUCKET_SIZE = 10*60*1000;
|
||||
private static final long TIME_SHRINK = 1000L;
|
||||
private static final int MAX_SKEW = (int) (BUCKET_SIZE / TIME_SHRINK);
|
||||
// 1/1/2005
|
||||
|
@ -100,7 +100,6 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
||||
private final ConcurrentHashMap<NID, Token> _incomingTokens;
|
||||
/** recently unreachable, with lastSeen() as the added-to-blacklist time */
|
||||
private final Set<NID> _blacklist;
|
||||
private SimpleTimer2.TimedEvent _cleaner, _explorer;
|
||||
|
||||
/** hook to inject and receive datagrams */
|
||||
private final I2PSession _session;
|
||||
@ -624,8 +623,6 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
||||
public synchronized void start() {
|
||||
if (_isRunning)
|
||||
return;
|
||||
if (_log.shouldInfo())
|
||||
_log.info("KRPC start", new Exception());
|
||||
_session.addMuxedSessionListener(this, I2PSession.PROTO_DATAGRAM_RAW, _rPort);
|
||||
_session.addMuxedSessionListener(this, I2PSession.PROTO_DATAGRAM, _qPort);
|
||||
_knownNodes.start();
|
||||
@ -633,8 +630,9 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
||||
PersistDHT.loadDHT(this, _dhtFile, _backupDhtFile);
|
||||
// start the explore thread
|
||||
_isRunning = true;
|
||||
_cleaner = new Cleaner();
|
||||
_explorer = new Explorer(5*1000);
|
||||
// no need to keep ref, it will eventually stop
|
||||
new Cleaner();
|
||||
new Explorer(5*1000);
|
||||
_txPkts.set(0);
|
||||
_rxPkts.set(0);
|
||||
_txBytes.set(0);
|
||||
@ -650,10 +648,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
||||
if (!_isRunning)
|
||||
return;
|
||||
_isRunning = false;
|
||||
if (_log.shouldInfo())
|
||||
_log.info("KRPC stop", new Exception());
|
||||
_cleaner.cancel();
|
||||
_explorer.cancel();
|
||||
// FIXME stop the explore thread
|
||||
// unregister port listeners
|
||||
_session.removeListener(I2PSession.PROTO_DATAGRAM, _qPort);
|
||||
_session.removeListener(I2PSession.PROTO_DATAGRAM_RAW, _rPort);
|
||||
@ -688,7 +683,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
||||
public String renderStatusHTML() {
|
||||
long uptime = Math.max(1000, _context.clock().now() - _started);
|
||||
StringBuilder buf = new StringBuilder(256);
|
||||
buf.append("<br><hr class=\"debug\"><br><hr class=\"debug\"><hr><b>TX:</b> ").append(_txPkts.get()).append(" pkts / ")
|
||||
buf.append("<br><hr class=\"debug\"><b>DHT DEBUG</b><br><hr class=\"debug\"><hr><b>TX:</b> ").append(_txPkts.get()).append(" pkts / ")
|
||||
.append(DataHelper.formatSize2(_txBytes.get())).append("B / ")
|
||||
.append(DataHelper.formatSize2Decimal(_txBytes.get() * 1000 / uptime)).append("Bps<br>" +
|
||||
"<b>RX:</b> ").append(_rxPkts.get()).append(" pkts / ")
|
||||
@ -1645,7 +1640,6 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
||||
public void disconnected(I2PSession session) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("KRPC disconnected");
|
||||
stop();
|
||||
}
|
||||
|
||||
public void errorOccurred(I2PSession session, String message, Throwable error) {
|
||||
@ -1766,7 +1760,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
||||
}
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Explore of " + keys.size() + " buckets done, new size: " + _knownNodes.size());
|
||||
_explorer = new Explorer(EXPLORE_TIME);
|
||||
new Explorer(EXPLORE_TIME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,13 +31,12 @@ public class ConfigUIHelper {
|
||||
{ "az", "az", "Azerbaijani", null },
|
||||
{ "cs", "cz", "Čeština", null },
|
||||
{ "zh", "cn", "Chinese 中文", null },
|
||||
{ "zh_TW", "tw", "Chinese 中文", "Taiwan" },
|
||||
//{ "zh_TW", "tw", "Chinese 中文", "Taiwan" },
|
||||
{ "da", "dk", "Dansk", null },
|
||||
{ "de", "de", "Deutsch", null },
|
||||
//{ "et", "ee", "Eesti", null },
|
||||
{ "en", "us", "English", null },
|
||||
{ "es", "es", "Español", null },
|
||||
{ "es_AR", "ar", "Español" ,"Argentina" },
|
||||
{ "fa", "ir", "Persian فارسی", null },
|
||||
{ "fr", "fr", "Français", null },
|
||||
//{ "gl", "lang_gl", "Galego", null },
|
||||
|
@ -8,19 +8,13 @@ import java.util.Properties;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.app.MenuCallback;
|
||||
import net.i2p.app.MenuHandle;
|
||||
import net.i2p.app.MenuService;
|
||||
import net.i2p.apps.systray.UrlLauncher;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.desktopgui.ExternalMain;
|
||||
import net.i2p.jetty.I2PLogger;
|
||||
import net.i2p.jetty.JettyStart;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.SystemVersion;
|
||||
|
||||
import org.klomp.snark.SnarkManager;
|
||||
|
||||
/**
|
||||
* @since moved from ../web and fixed in 0.9.27
|
||||
*/
|
||||
@ -77,19 +71,14 @@ public class RunStandalone {
|
||||
public void start() {
|
||||
try {
|
||||
String url = "http://" + _host + ':' + _port + "/i2psnark/";
|
||||
System.out.println("Starting i2psnark " + SnarkManager.FULL_VERSION + " at " + url);
|
||||
MenuService dtg = startTrayApp();
|
||||
System.out.println("Starting i2psnark at " + url);
|
||||
startTrayApp();
|
||||
_jettyStart.startup();
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException ie) {}
|
||||
String p = _context.getProperty("routerconsole.browser");
|
||||
if (!("/bin/false".equals(p) || "NUL".equals(p))) {
|
||||
UrlLauncher launch = new UrlLauncher(_context, null, new String[] { url } );
|
||||
launch.startup();
|
||||
}
|
||||
if (dtg != null)
|
||||
dtg.addMenu("Shutdown I2PSnark", new StandaloneStopper(dtg));
|
||||
UrlLauncher launch = new UrlLauncher(_context, null, new String[] { url } );
|
||||
launch.startup();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -132,47 +121,16 @@ public class RunStandalone {
|
||||
|
||||
/**
|
||||
* @since 0.9.54 adapted from RouterConsoleRunner
|
||||
* @return null on failure
|
||||
*/
|
||||
private MenuService startTrayApp() {
|
||||
private void startTrayApp() {
|
||||
try {
|
||||
if (isSystrayEnabled(_context)) {
|
||||
System.setProperty("java.awt.headless", "false");
|
||||
ExternalMain dtg = new ExternalMain(_context, _context.clientAppManager(), null);
|
||||
dtg.startup();
|
||||
return dtg;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback when shutdown is clicked in systray
|
||||
* @since 0.9.61
|
||||
*/
|
||||
public static class StandaloneStopper implements MenuCallback {
|
||||
private final MenuService _ms;
|
||||
|
||||
public StandaloneStopper(MenuService ms) { _ms = ms; }
|
||||
|
||||
public void clicked(MenuHandle menu) {
|
||||
_ms.disableMenu(menu);
|
||||
_ms.updateMenu("I2PSnark shutting down", menu);
|
||||
Thread t = new I2PAppThread(new StopperThread(), "Snark Stopper", true);
|
||||
t.start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Threaded shutdown
|
||||
* @since 0.9.61
|
||||
*/
|
||||
public static class StopperThread implements Runnable {
|
||||
public void run() {
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -395,11 +395,11 @@ class BasicServlet extends HttpServlet
|
||||
String rtype = response.getContentType();
|
||||
String ctype = content.getContentType();
|
||||
if (rtype != null) {
|
||||
if (rtype.contains("javascript"))
|
||||
if (rtype.equals("application/javascript"))
|
||||
response.setCharacterEncoding("ISO-8859-1");
|
||||
} else if (ctype != null) {
|
||||
response.setContentType(ctype);
|
||||
if (ctype.contains("javascript"))
|
||||
if (ctype.equals("application/javascript"))
|
||||
response.setCharacterEncoding("ISO-8859-1");
|
||||
}
|
||||
response.setHeader("X-Content-Type-Options", "nosniff");
|
||||
@ -586,17 +586,6 @@ class BasicServlet extends HttpServlet
|
||||
protected static String addPaths(String base, String path) {
|
||||
if (path == null)
|
||||
return base;
|
||||
if (path.equals("/")) {
|
||||
// Java 17 and below:
|
||||
// (new File("foo", "/")).toString() = "foo/"
|
||||
// (new File("foo/", "/")).toString() = "foo/"
|
||||
// Java 21:
|
||||
// (new File("foo", "/")).toString() = "foo"
|
||||
// (new File("foo/", "/")).toString() = "foo"
|
||||
if (base.endsWith("/"))
|
||||
return base;
|
||||
return base + path;
|
||||
}
|
||||
String rv = (new File(base, path)).toString();
|
||||
if (SystemVersion.isWindows())
|
||||
rv = rv.replace("\\", "/");
|
||||
|
@ -3,7 +3,6 @@ package org.klomp.snark.web;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Serializable;
|
||||
@ -38,7 +37,6 @@ import net.i2p.data.Base32;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.servlet.RequestWrapper;
|
||||
import net.i2p.servlet.util.ServletUtil;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.Log;
|
||||
@ -48,7 +46,6 @@ import net.i2p.util.SystemVersion;
|
||||
import net.i2p.util.Translate;
|
||||
import net.i2p.util.UIMessages;
|
||||
|
||||
import org.klomp.snark.BandwidthListener;
|
||||
import org.klomp.snark.I2PSnarkUtil;
|
||||
import org.klomp.snark.MagnetURI;
|
||||
import org.klomp.snark.MetaInfo;
|
||||
@ -60,8 +57,6 @@ import org.klomp.snark.Storage;
|
||||
import org.klomp.snark.Tracker;
|
||||
import org.klomp.snark.TrackerClient;
|
||||
import org.klomp.snark.URIUtil;
|
||||
import org.klomp.snark.bencode.BEValue;
|
||||
import org.klomp.snark.bencode.InvalidBEncodingException;
|
||||
import org.klomp.snark.dht.DHT;
|
||||
import org.klomp.snark.comments.Comment;
|
||||
import org.klomp.snark.comments.CommentSet;
|
||||
@ -217,7 +212,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
req.setCharacterEncoding("UTF-8");
|
||||
|
||||
String pOverride = _manager.util().connected() ? null : "";
|
||||
String peerString = getQueryString(req, pOverride, null, null, "");
|
||||
String peerString = getQueryString(req, pOverride, null, null);
|
||||
|
||||
String cspNonce = Integer.toHexString(_context.random().nextInt());
|
||||
// AJAX for mainsection
|
||||
@ -329,8 +324,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
out.write("<script src=\".resources/js/configui.js?" + CoreVersion.VERSION + "\" type=\"text/javascript\"></script>\n");
|
||||
} else {
|
||||
delay = _manager.getRefreshDelaySeconds();
|
||||
// init for search even if refresh disabled
|
||||
//if (delay > 0) {
|
||||
if (delay > 0) {
|
||||
String jsPfx = _context.isRouterContext() ? "" : ".resources";
|
||||
String downMsg = _context.isRouterContext() ? _t("Router is down") : _t("I2PSnark has stopped");
|
||||
// fallback to metarefresh when javascript is disabled
|
||||
@ -341,16 +335,13 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
"var ajaxDelay = " + (delay * 1000) + ";\n" +
|
||||
"</script>\n" +
|
||||
"<script src=\".resources/js/initajax.js?" + CoreVersion.VERSION + "\" type=\"text/javascript\"></script>\n");
|
||||
//}
|
||||
}
|
||||
out.write("<script nonce=\"" + cspNonce + "\" type=\"text/javascript\">\n" +
|
||||
"var deleteMessage1 = \"" + _t("Are you sure you want to delete the file \\''{0}\\'' (downloaded data will not be deleted) ?") + "\";\n" +
|
||||
"var deleteMessage2 = \"" + _t("Are you sure you want to delete the torrent \\''{0}\\'' and all downloaded data?") + "\";\n" +
|
||||
"</script>\n" +
|
||||
"<script src=\".resources/js/delete.js?" + CoreVersion.VERSION + "\" type=\"text/javascript\"></script>\n" +
|
||||
"<script src=\".resources/js/search.js?" + CoreVersion.VERSION + "\" type=\"text/javascript\"></script>\n" +
|
||||
"<script src=\".resources/js/dnd.js?" + CoreVersion.VERSION + "\" type=\"text/javascript\"></script>\n");
|
||||
"<script src=\".resources/js/delete.js?" + CoreVersion.VERSION + "\" type=\"text/javascript\"></script>\n");
|
||||
}
|
||||
out.write("<script src=\"/js/iframeResizer.contentWindow.js?" + CoreVersion.VERSION + "\" type=\"text/javascript\"></script>\n");
|
||||
out.write(HEADER_A + _themePath + HEADER_B);
|
||||
|
||||
// ...and inject CSS to display panels uncollapsed
|
||||
@ -373,7 +364,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
else
|
||||
out.write(_contextName);
|
||||
if (!_context.isRouterContext()) {
|
||||
out.write(' ' + SnarkManager.FULL_VERSION);
|
||||
out.write(' ' + CoreVersion.VERSION);
|
||||
}
|
||||
out.write("</a>");
|
||||
List<Tracker> sortedTrackers = null;
|
||||
@ -385,30 +376,15 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
continue;
|
||||
if (_manager.util().isKnownOpenTracker(t.announceURL))
|
||||
continue;
|
||||
out.write(" <a href=\"" + t.baseURL + "\" class=\"snarkNav nav_tracker\" target=\"_blank\">" + t.name + "</a>\n");
|
||||
out.write(" <a href=\"" + t.baseURL + "\" class=\"snarkNav nav_tracker\" target=\"_blank\">" + t.name + "</a>");
|
||||
}
|
||||
}
|
||||
}
|
||||
// end snarkNavBar
|
||||
out.write("</div>\n");
|
||||
|
||||
if (!isConfigure) {
|
||||
String search = req.getParameter("nf_s");
|
||||
if (_manager.getTorrents().size() > 1 || (search != null && search.length() > 0)) {
|
||||
out.write("<form class=\"search\" id = \"search\" action=\"" + _contextPath + "\" method=\"GET\">" +
|
||||
"<input type=\"text\" name=\"nf_s\" size=\"20\" class=\"search\" id=\"searchbox\"");
|
||||
if (search != null)
|
||||
out.write(" value=\"" + DataHelper.escapeHTML(search) + '"');
|
||||
out.write(">" +
|
||||
"<a class=\"cancel\" id=\"searchcancel\" href=\"" + _contextPath + "/\"></a>" +
|
||||
"</form>\n");
|
||||
}
|
||||
}
|
||||
|
||||
String newURL = req.getParameter("newURL");
|
||||
if (newURL != null && newURL.trim().length() > 0 && req.getMethod().equals("GET"))
|
||||
_manager.addMessage(_t("Click \"Add torrent\" button to fetch torrent"));
|
||||
out.write("<div id=\"page\" class=\"page\"><div id=\"mainsection\" class=\"mainsection\">");
|
||||
out.write("<div class=\"page\"><div id=\"mainsection\" class=\"mainsection\">");
|
||||
|
||||
writeMessages(out, isConfigure, peerString);
|
||||
|
||||
@ -510,17 +486,6 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
boolean isDegraded = ua != null && ServletUtil.isTextBrowser(ua);
|
||||
boolean noThinsp = isDegraded || (ua != null && ua.startsWith("Opera"));
|
||||
|
||||
// search
|
||||
boolean isSearch = false;
|
||||
String search = req.getParameter("nf_s");
|
||||
if (search != null && search.length() > 0) {
|
||||
List<Snark> matches = search(search, snarks);
|
||||
if (matches != null) {
|
||||
snarks = matches;
|
||||
isSearch = true;
|
||||
}
|
||||
}
|
||||
|
||||
// pages
|
||||
int start = 0;
|
||||
int total = snarks.size();
|
||||
@ -776,8 +741,6 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
out.write(_t("Unreadable") + ": " + DataHelper.escapeHTML(dd.toString()));
|
||||
} else if (!canWrite) {
|
||||
out.write(_t("No write permissions for data directory") + ": " + DataHelper.escapeHTML(dd.toString()));
|
||||
} else if (isSearch) {
|
||||
out.write(_t("No torrents found."));
|
||||
} else {
|
||||
out.write(_t("No torrents loaded."));
|
||||
}
|
||||
@ -838,7 +801,6 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
out.write(' ');
|
||||
out.write(_t("Dht Debug"));
|
||||
out.write("</label><div id=\"dhtDebugInner\">");
|
||||
out.write(_manager.getBandwidthListener().toString());
|
||||
out.write(dht.renderStatusHTML());
|
||||
out.write("</div></div></th>");
|
||||
}
|
||||
@ -853,48 +815,6 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
return start == 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* search torrents for matching terms
|
||||
*
|
||||
* @param search non-null and %-encoded, will be decoded here
|
||||
* @param snarks unmodified, order will be honored
|
||||
* @return null if not a valid search, or matching torrents in same order, possibly empty
|
||||
* @since 0.9.58
|
||||
*/
|
||||
private static List<Snark> search(String search, Collection<Snark> snarks) {
|
||||
try {
|
||||
search = decodePath(search);
|
||||
} catch (IOException ioe) {
|
||||
return null;
|
||||
}
|
||||
List<String> searchList = null;
|
||||
String[] terms = DataHelper.split(search, " ");
|
||||
for (int i = 0; i < terms.length; i++) {
|
||||
String term = terms[i];
|
||||
if (term.length() > 0) {
|
||||
if (searchList == null)
|
||||
searchList = new ArrayList<String>(4);
|
||||
searchList.add(term.toLowerCase(Locale.US));
|
||||
}
|
||||
}
|
||||
if (searchList == null)
|
||||
return null;
|
||||
List<Snark> matches = new ArrayList<Snark>(32);
|
||||
for (Snark snark : snarks) {
|
||||
String lcname = snark.getBaseName().toLowerCase(Locale.US);
|
||||
// search for any term (OR)
|
||||
for (int j = 0; j < searchList.size(); j++) {
|
||||
String term = searchList.get(j);
|
||||
if (lcname.contains(term)) {
|
||||
matches.add(snark);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* hidden inputs for nonce and paramters p, st, and sort
|
||||
*
|
||||
@ -936,19 +856,11 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
if (action != null) {
|
||||
buf.append("<input type=\"hidden\" name=\"action\" value=\"")
|
||||
.append(action).append("\" >\n");
|
||||
} else {
|
||||
// for buttons, keep the search term
|
||||
String sParam = req.getParameter("nf_s");
|
||||
if (sParam != null) {
|
||||
buf.append("<input type=\"hidden\" name=\"nf_s\" value=\"")
|
||||
.append(DataHelper.escapeHTML(sParam)).append("\" >\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build HTML-escaped and stripped query string.
|
||||
* Keeps any existing search param.
|
||||
* Build HTML-escaped and stripped query string
|
||||
*
|
||||
* @param p override or "" for default or null to keep the same as in req
|
||||
* @param st override or "" for default or null to keep the same as in req
|
||||
@ -957,14 +869,6 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
* @since 0.9.16
|
||||
*/
|
||||
private static String getQueryString(HttpServletRequest req, String p, String st, String so) {
|
||||
return getQueryString(req, p, st, so, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param s search param override or "" for default or null to keep the same as in req
|
||||
* @since 0.9.58
|
||||
*/
|
||||
private static String getQueryString(HttpServletRequest req, String p, String st, String so, String s) {
|
||||
StringBuilder buf = new StringBuilder(64);
|
||||
if (p == null) {
|
||||
p = req.getParameter("p");
|
||||
@ -997,18 +901,6 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
buf.append("&st=");
|
||||
buf.append(st);
|
||||
}
|
||||
if (s == null) {
|
||||
s = req.getParameter("nf_s");
|
||||
if (s != null)
|
||||
s = DataHelper.escapeHTML(s);
|
||||
}
|
||||
if (s != null && !s.equals("")) {
|
||||
if (buf.length() <= 0)
|
||||
buf.append("?nf_s=");
|
||||
else
|
||||
buf.append("&nf_s=");
|
||||
buf.append(s);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@ -1113,87 +1005,44 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
// return;
|
||||
//}
|
||||
if ("Add".equals(action)) {
|
||||
File dd = _manager.getDataDir();
|
||||
if (!dd.canWrite()) {
|
||||
_manager.addMessage(_t("No write permissions for data directory") + ": " + dd);
|
||||
return;
|
||||
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));
|
||||
}
|
||||
String contentType = req.getContentType();
|
||||
RequestWrapper reqw = new RequestWrapper(req);
|
||||
String newURL = reqw.getParameter("nofilter_newURL");
|
||||
String newFile = reqw.getFilename("newFile");
|
||||
if (newFile != null && newFile.trim().length() > 0) {
|
||||
if (!newFile.endsWith(".torrent"))
|
||||
newFile += ".torrent";
|
||||
File local = new File(dd, newFile);
|
||||
String newFile2 = Storage.filterName(newFile);
|
||||
File local2;
|
||||
if (!newFile.equals(newFile2)) {
|
||||
local2 = new File(dd, newFile2);
|
||||
} else {
|
||||
local2 = null;
|
||||
}
|
||||
if (local.exists() || (local2 != null && local2.exists())) {
|
||||
try {
|
||||
String canonical = local.getCanonicalPath();
|
||||
String canonical2 = local2 != null ? local2.getCanonicalPath() : null;
|
||||
if (_manager.getTorrent(canonical) != null ||
|
||||
(canonical2 != null && _manager.getTorrent(canonical2) != null))
|
||||
_manager.addMessage(_t("Torrent already running: {0}", canonical));
|
||||
else
|
||||
_manager.addMessage(_t("Torrent already in the queue: {0}", canonical));
|
||||
} catch (IOException ioe) {}
|
||||
} else {
|
||||
File tmp = new File(_manager.util().getTempDir(), "newTorrent-" + _manager.util().getContext().random().nextLong() + ".torrent");
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
try {
|
||||
in = reqw.getInputStream("newFile");
|
||||
out = new SecureFileOutputStream(tmp);
|
||||
DataHelper.copy(in, out);
|
||||
out.close();
|
||||
out = null;
|
||||
in.close();
|
||||
// test that it's a valid torrent file, and get the hash to check for dups
|
||||
in = new FileInputStream(tmp);
|
||||
byte[] fileInfoHash = new byte[20];
|
||||
String name = MetaInfo.getNameAndInfoHash(in, fileInfoHash);
|
||||
try { in.close(); } catch (IOException ioe) {}
|
||||
Snark snark = _manager.getTorrentByInfoHash(fileInfoHash);
|
||||
if (snark != null) {
|
||||
_manager.addMessage(_t("Torrent with this info hash is already running: {0}", snark.getBaseName()));
|
||||
return;
|
||||
}
|
||||
if (local2 != null)
|
||||
local = local2;
|
||||
String canonical = local.getCanonicalPath();
|
||||
// This may take a LONG time to create the storage.
|
||||
boolean ok = _manager.copyAndAddTorrent(tmp, canonical, dd);
|
||||
if (!ok)
|
||||
throw new IOException("Unknown error - check logs");
|
||||
snark = _manager.getTorrentByInfoHash(fileInfoHash);
|
||||
if (snark != null)
|
||||
snark.startTorrent();
|
||||
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
|
||||
throw new IOException("Not found: " + canonical);
|
||||
} catch (IOException ioe) {
|
||||
_manager.addMessageNoEscape(_t("Torrent at {0} was not valid", DataHelper.escapeHTML(newFile)) + ": " + DataHelper.stripHTML(ioe.getMessage()));
|
||||
tmp.delete();
|
||||
local.delete();
|
||||
if (local2 != null)
|
||||
local2.delete();
|
||||
return;
|
||||
} catch (OutOfMemoryError oom) {
|
||||
_manager.addMessageNoEscape(_t("ERROR - Out of memory, cannot create torrent from {0}", DataHelper.escapeHTML(newFile)) + ": " + DataHelper.stripHTML(oom.getMessage()));
|
||||
} finally {
|
||||
if (in != null) try { in.close(); } catch (IOException ioe) {}
|
||||
if (out != null) try { out.close(); } catch (IOException ioe) {}
|
||||
tmp.delete();
|
||||
_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.trim().length() > 0) {
|
||||
} else
|
||||
*****/
|
||||
if (newURL != null) {
|
||||
newURL = newURL.trim();
|
||||
String newDir = reqw.getParameter("nofilter_newDir");
|
||||
String newDir = req.getParameter("nofilter_newDir");
|
||||
File dir = null;
|
||||
if (newDir != null) {
|
||||
newDir = newDir.trim();
|
||||
@ -1221,6 +1070,11 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
}
|
||||
}
|
||||
}
|
||||
File dd = _manager.getDataDir();
|
||||
if (!dd.canWrite()) {
|
||||
_manager.addMessage(_t("No write permissions for data directory") + ": " + dd);
|
||||
return;
|
||||
}
|
||||
if (newURL.startsWith("http://") || newURL.startsWith("https://")) {
|
||||
if (isI2PTracker(newURL)) {
|
||||
FetchAndAdd fetch = new FetchAndAdd(_context, _manager, newURL, dir);
|
||||
@ -1284,7 +1138,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
boolean ok = _manager.copyAndAddTorrent(file, canonical, dd);
|
||||
if (!ok)
|
||||
throw new IOException("Unknown error - check logs");
|
||||
snark = _manager.getTorrentByInfoHash(fileInfoHash);
|
||||
snark = _manager.getTorrentByBaseName(originalName);
|
||||
if (snark != null)
|
||||
snark.startTorrent();
|
||||
else
|
||||
@ -1304,7 +1158,6 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
}
|
||||
} else {
|
||||
// no file or URL specified
|
||||
_manager.addMessage(_t("Enter URL or select torrent file"));
|
||||
}
|
||||
} else if (action.startsWith("Stop_")) {
|
||||
String torrent = action.substring(5);
|
||||
@ -1456,7 +1309,6 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
String i2cpOpts = buildI2CPOpts(req);
|
||||
String upLimit = req.getParameter("upLimit");
|
||||
String upBW = req.getParameter("upBW");
|
||||
String downBW = req.getParameter("downBW");
|
||||
String refreshDel = req.getParameter("refreshDelay");
|
||||
String startupDel = req.getParameter("startupDelay");
|
||||
String pageSize = req.getParameter("pageSize");
|
||||
@ -1472,7 +1324,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
boolean collapsePanels = req.getParameter("collapsePanels") != null;
|
||||
_manager.updateConfig(dataDir, filesPublic, autoStart, smartSort, refreshDel, startupDel, pageSize,
|
||||
seedPct, eepHost, eepPort, i2cpHost, i2cpPort, i2cpOpts,
|
||||
upLimit, upBW, downBW, useOpenTrackers, useDHT, theme,
|
||||
upLimit, upBW, useOpenTrackers, useDHT, theme,
|
||||
lang, ratings, comments, commentsName, collapsePanels);
|
||||
// update servlet
|
||||
try {
|
||||
@ -1485,9 +1337,6 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
} else if ("Create".equals(action)) {
|
||||
String baseData = req.getParameter("nofilter_baseFile");
|
||||
if (baseData != null && baseData.trim().length() > 0) {
|
||||
// drag and drop, no js
|
||||
if (baseData.startsWith("file://"))
|
||||
baseData = baseData.substring(7);
|
||||
File baseFile = new File(baseData.trim());
|
||||
if (!baseFile.isAbsolute())
|
||||
baseFile = new File(_manager.getDataDir(), baseData);
|
||||
@ -1606,36 +1455,8 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
_manager.addMessage(_t("Error creating torrent - you must enter a file or directory"));
|
||||
}
|
||||
} else if ("StopAll".equals(action)) {
|
||||
String search = req.getParameter("nf_s");
|
||||
if (search != null && search.length() > 0) {
|
||||
List<Snark> matches = search(search, _manager.getTorrents());
|
||||
if (matches != null) {
|
||||
for (Snark snark : matches) {
|
||||
_manager.stopTorrent(snark, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
_manager.stopAllTorrents(false);
|
||||
} else if ("StartAll".equals(action)) {
|
||||
String search = req.getParameter("nf_s");
|
||||
if (search != null && search.length() > 0) {
|
||||
List<Snark> matches = search(search, _manager.getTorrents());
|
||||
if (matches != null) {
|
||||
// TODO thread it
|
||||
int count = 0;
|
||||
for (Snark snark : matches) {
|
||||
if (!snark.isStopped())
|
||||
continue;
|
||||
_manager.startTorrent(snark);
|
||||
if ((count++ & 0x0f) == 15) {
|
||||
// try to prevent OOMs
|
||||
try { Thread.sleep(250); } catch (InterruptedException ie) {}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
_manager.startAllTorrents();
|
||||
} else if ("Clear".equals(action)) {
|
||||
String sid = req.getParameter("id");
|
||||
@ -1941,7 +1762,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
":</b> " + curPeers + thinsp(noThinsp) +
|
||||
ngettext("1 peer", "{0} peers", knownPeers);
|
||||
} else if (isRunning && curPeers > 0 && !showPeers) {
|
||||
statusString = toThemeImg("stalled", "", _t("Stalled") + " (" + ngettext("Connected to {0} peer", "Connected to {0} peers", curPeers) + ")") + "</td>" +
|
||||
statusString = toThemeImg("stalled", "", _t("Stalled") + " (" + ngettext("Connected to {0} peer", "Connected to {0} peers", curPeers)) + "</td>" +
|
||||
"<td class=\"snarkTorrentStatus\"><b>" + _t("Stalled") +
|
||||
":</b> <a href=\"" + uri + getQueryString(req, b64, null, null) + '#' + b64Short + "\">" +
|
||||
curPeers + thinsp(noThinsp) +
|
||||
@ -2183,73 +2004,30 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
if (ch.startsWith("WebSeed@")) {
|
||||
out.write(ch);
|
||||
} else {
|
||||
// most clients start -xx, see
|
||||
// BT spec or libtorrent identify_client.cpp
|
||||
// Base64 encode -xx
|
||||
// Anything starting with L is -xx and has an Az version
|
||||
// snark is 9 nulls followed by 3 3 3 (binary), see Snark
|
||||
// PeerID.toString() skips nulls
|
||||
// Base64 encode '\3\3\3' = AwMD
|
||||
boolean addVersion = true;
|
||||
ch = ch.substring(0, 4);
|
||||
String client;
|
||||
if ("AwMD".equals(ch))
|
||||
client = _t("I2PSnark");
|
||||
else if ("LUJJ".equals(ch))
|
||||
client = "BiglyBT";
|
||||
client = "BiglyBT" + getAzVersion(pid.getID());
|
||||
else if ("LUFa".equals(ch))
|
||||
client = "Vuze";
|
||||
client = "Vuze" + getAzVersion(pid.getID());
|
||||
else if ("LVhE".equals(ch))
|
||||
client = "XD";
|
||||
else if (ch.startsWith("LV")) // LVCS 1.0.2?; LVRS 1.0.4
|
||||
client = "Transmission";
|
||||
else if ("LUtU".equals(ch))
|
||||
client = "KTorrent";
|
||||
// libtorrent and downstreams
|
||||
// https://www.libtorrent.org/projects.html
|
||||
else if ("LURF".equals(ch)) // DL
|
||||
client = "Deluge";
|
||||
else if ("LXFC".equals(ch)) // qB
|
||||
client = "qBittorrent";
|
||||
else if ("LUxU".equals(ch)) // LT
|
||||
client = "libtorrent";
|
||||
// ancient below here
|
||||
client = "XD" + getAzVersion(pid.getID());
|
||||
else if ("ZV".equals(ch.substring(2,4)) || "VUZP".equals(ch))
|
||||
client = "Robert" + getRobtVersion(pid.getID());
|
||||
else if (ch.startsWith("LV")) // LVCS 1.0.2?; LVRS 1.0.4
|
||||
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 {
|
||||
// get client + version from handshake
|
||||
client = null;
|
||||
Map<String, BEValue> handshake = peer.getHandshakeMap();
|
||||
if (handshake != null) {
|
||||
BEValue bev = handshake.get("v");
|
||||
if (bev != null) {
|
||||
try {
|
||||
String s = bev.getString();
|
||||
if (s.length() > 0) {
|
||||
if (s.length() > 64)
|
||||
s = s.substring(0, 64);
|
||||
client = DataHelper.escapeHTML(s);
|
||||
addVersion = false;
|
||||
}
|
||||
} catch (InvalidBEncodingException ibee) {}
|
||||
}
|
||||
}
|
||||
if (client == null)
|
||||
client = _t("Unknown") + " (" + ch + ')';
|
||||
}
|
||||
|
||||
if (addVersion) {
|
||||
byte[] id = pid.getID();
|
||||
if (id != null && id[0] == '-')
|
||||
client += getAzVersion(id);
|
||||
}
|
||||
|
||||
else
|
||||
client = _t("Unknown") + " (" + ch + ')';
|
||||
out.write(client + " <tt title=\"");
|
||||
out.write(_t("Destination (identity) of peer"));
|
||||
out.write("\">" + peer.toString().substring(5, 9)+ "</tt>");
|
||||
@ -2513,9 +2291,12 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
newURL = "";
|
||||
else
|
||||
newURL = DataHelper.stripHTML(newURL); // XSS
|
||||
//String newFile = req.getParameter("newFile");
|
||||
//if ( (newFile == null) || (newFile.trim().length() <= 0) ) newFile = "";
|
||||
|
||||
out.write("<div id=\"add\" class=\"snarkNewTorrent\">\n" +
|
||||
"<form action=\"_post\" method=\"POST\" enctype=\"multipart/form-data\" accept-charset=\"UTF-8\">\n");
|
||||
// *not* enctype="multipart/form-data", so that the input type=file sends the filename, not the file
|
||||
"<form action=\"_post\" method=\"POST\">\n");
|
||||
writeHiddenInputs(out, req, "Add");
|
||||
out.write("<div class=\"addtorrentsection\">" +
|
||||
"<input class=\"toggle_input\" id=\"toggle_addtorrent\" type=\"checkbox\"");
|
||||
@ -2531,20 +2312,19 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
|
||||
out.write("<hr>\n<table border=\"0\"><tr><td>");
|
||||
out.write(_t("From URL"));
|
||||
out.write(":<td><input type=\"text\" id=\"nofilter_newURL\" name=\"nofilter_newURL\" size=\"85\" value=\"" + newURL + "\" spellcheck=\"false\"" +
|
||||
out.write(":<td><input type=\"text\" name=\"nofilter_newURL\" size=\"85\" value=\"" + newURL + "\" spellcheck=\"false\"" +
|
||||
" title=\"");
|
||||
out.write(_t("Enter the torrent file download URL (I2P only), magnet link, or info hash"));
|
||||
out.write("\">\n");
|
||||
out.write("<input type=\"submit\" id=\"addButton\" class=\"add\" value=\"");
|
||||
// not supporting from file at the moment, since the file name passed isn't always absolute (so it may not resolve)
|
||||
//out.write("From file: <input type=\"file\" name=\"newFile\" size=\"50\" value=\"" + newFile + "\" /><br>");
|
||||
out.write("<input type=\"submit\" class=\"add\" value=\"");
|
||||
out.write(_t("Add torrent"));
|
||||
out.write("\" name=\"foo\" ><br>\n" +
|
||||
"<tr><td>");
|
||||
out.write(_t("Torrent file"));
|
||||
out.write(":<td><input type=\"file\" name=\"newFile\" id=\"newFile\" accept=\".torrent\"/>\n" +
|
||||
"<tr><td>");
|
||||
|
||||
out.write(_t("Data dir"));
|
||||
out.write(":<td><input type=\"text\" id=\"nofilter_newDir\" name=\"nofilter_newDir\" size=\"85\" value=\"\" spellcheck=\"false\"" +
|
||||
out.write(":<td><input type=\"text\" name=\"nofilter_newDir\" size=\"85\" value=\"\" spellcheck=\"false\"" +
|
||||
" title=\"");
|
||||
out.write(_t("Enter the directory to save the data in (default {0})", _manager.getDataDir().getAbsolutePath()));
|
||||
out.write("\"></td></tr>\n");
|
||||
@ -2570,11 +2350,11 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
//out.write("From file: <input type=\"file\" name=\"newFile\" size=\"50\" value=\"" + newFile + "\" /><br>\n");
|
||||
out.write(_t("Data to seed"));
|
||||
out.write(":<td>"
|
||||
+ "<input type=\"text\" id=\"nofilter_baseFile\" name=\"nofilter_baseFile\" size=\"85\" value=\""
|
||||
+ "<input type=\"text\" name=\"nofilter_baseFile\" size=\"85\" value=\""
|
||||
+ "\" spellcheck=\"false\" title=\"");
|
||||
out.write(_t("File or directory to seed (full path or within the directory {0} )",
|
||||
_manager.getDataDir().getAbsolutePath() + File.separatorChar));
|
||||
out.write("\" > <input type=\"submit\" id=\"createButton\" class=\"create\" value=\"");
|
||||
out.write("\" > <input type=\"submit\" class=\"create\" value=\"");
|
||||
out.write(_t("Create torrent"));
|
||||
out.write("\" name=\"foo\" >" +
|
||||
"<tr><td>\n");
|
||||
@ -2831,7 +2611,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
out.write(":<td><input type=\"text\" name=\"upBW\" class=\"r\" value=\""
|
||||
+ _manager.util().getMaxUpBW() + "\" size=\"4\" maxlength=\"4\""
|
||||
+ " title=\"");
|
||||
out.write(_t("Maximum bandwidth allocated"));
|
||||
out.write(_t("Maximum bandwidth allocated for uploading"));
|
||||
out.write("\"> KBps <td id=\"bwHelp\"><i>");
|
||||
out.write(_t("Half available bandwidth recommended."));
|
||||
if (_context.isRouterContext()) {
|
||||
@ -2841,24 +2621,6 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
out.write(_t("Configure"));
|
||||
out.write("]</a>");
|
||||
}
|
||||
out.write("\n" +
|
||||
|
||||
"<tr><td>");
|
||||
out.write(_t("Down bandwidth limit"));
|
||||
out.write(":<td><input type=\"text\" name=\"downBW\" class=\"r\" value=\""
|
||||
+ (_manager.getBandwidthListener().getDownBWLimit() / 1000) + "\" size=\"4\" maxlength=\"4\""
|
||||
+ " title=\"");
|
||||
out.write(_t("Maximum bandwidth allocated"));
|
||||
out.write("\"> KBps <td id=\"bwHelp\"><i>");
|
||||
out.write(_t("Half available bandwidth recommended."));
|
||||
if (_context.isRouterContext()) {
|
||||
out.write("</i> <a href=\"/config.jsp\" target=\"blank\" title=\"");
|
||||
out.write(_t("View or change router bandwidth"));
|
||||
out.write("\">[");
|
||||
out.write(_t("Configure"));
|
||||
out.write("]</a>");
|
||||
}
|
||||
|
||||
out.write("\n<tr><td><label for=\"useOpenTrackers\">");
|
||||
out.write(_t("Use open trackers also"));
|
||||
out.write(":</label><td colspan=\"2\"><input type=\"checkbox\" class=\"optbox\" name=\"useOpenTrackers\" id=\"useOpenTrackers\" value=\"true\" "
|
||||
@ -3193,7 +2955,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
return escaped;
|
||||
}
|
||||
|
||||
private static final String DOCTYPE = "<!DOCTYPE html>\n";
|
||||
private static final String DOCTYPE = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n";
|
||||
private static final String HEADER_A = "<link id=\"pagestyle\" href=\"";
|
||||
private static final String HEADER_B = "snark.css?" + CoreVersion.VERSION + "\" rel=\"stylesheet\" type=\"text/css\" >";
|
||||
private static final String HEADER_C = "nocollapse.css?" + CoreVersion.VERSION + "\" rel=\"stylesheet\" type=\"text/css\" >";
|
||||
@ -3412,7 +3174,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
buf.append("</span></td></tr>");
|
||||
}
|
||||
List<List<String>> alist = meta.getAnnounceList();
|
||||
Set<String> annlist = new TreeSet<String>();
|
||||
List<String> annlist = new ArrayList<String>();
|
||||
if (alist != null && !alist.isEmpty()) {
|
||||
// strip non-i2p trackers
|
||||
for (List<String> alist2 : alist) {
|
||||
@ -4468,8 +4230,8 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
if (announce != null)
|
||||
annlist.add(announce);
|
||||
if (!annlist.isEmpty()) {
|
||||
buf.append("<tr><td colspan=\"3\"></td><td>").append(_t("Primary")).append("</td><td>")
|
||||
.append(_t("Delete")).append("</td></tr>");
|
||||
buf.append("<tr><td colspan=\"3\"></td><td>").append("Primary").append("</td><td>")
|
||||
.append("Delete").append("</td></tr>");
|
||||
for (String s : annlist) {
|
||||
int hc = s.hashCode();
|
||||
buf.append("<tr><td>");
|
||||
@ -4501,8 +4263,8 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
iter.remove();
|
||||
}
|
||||
if (!newTrackers.isEmpty()) {
|
||||
buf.append("<tr><td colspan=\"3\"></td><td>").append(_t("Primary")).append("</td><td>")
|
||||
.append(_t("Add")).append("</td></tr>");
|
||||
buf.append("<tr><td colspan=\"3\"></td><td>").append("Primary").append("</td><td>")
|
||||
.append("Add").append("</td></tr>");
|
||||
for (Tracker t : newTrackers) {
|
||||
String name = t.name;
|
||||
int hc = t.announceURL.hashCode();
|
||||
@ -4886,7 +4648,7 @@ public class I2PSnarkServlet extends BasicServlet {
|
||||
if (newCreatedBy.equals(""))
|
||||
newCreatedBy = null;
|
||||
MetaInfo newMeta = new MetaInfo(thePrimary, meta.getName(), null, meta.getFiles(), meta.getLengths(),
|
||||
meta.getPieceLength(0), meta.getPieceHashes(), meta.getTotalLength(), meta.getPrivateTrackerStatus(),
|
||||
meta.getPieceLength(0), meta.getPieceHashes(), meta.getTotalLength(), meta.isPrivate(),
|
||||
newAnnList, newCreatedBy, meta.getWebSeedURLs(), newComment);
|
||||
if (!DataHelper.eq(meta.getInfoHash(), newMeta.getInfoHash())) {
|
||||
// shouldn't happen
|
||||
|
@ -35,6 +35,5 @@ raiseopenfilesulimit() {
|
||||
|
||||
raiseopenfilesulimit
|
||||
|
||||
I2P="`dirname $0`"
|
||||
cd "$I2P"
|
||||
java $JAVA_OPTS -jar i2psnark.jar
|
||||
I2P="."
|
||||
java $JAVA_OPTS -jar "$I2P/i2psnark.jar"
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -12,7 +12,6 @@ epub = application/epub+zip
|
||||
flac = audio/flac
|
||||
flv = video/x-flv
|
||||
iso = application/x-iso9660-image
|
||||
js = text/javascript
|
||||
jxl = image/jxl
|
||||
m3u = audio/mpegurl
|
||||
m3u8 = audio/mpegurl
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user