Compare commits

..

161 Commits

Author SHA1 Message Date
zzz
3b9c26fe8a 1.7.0 2022-02-21 09:12:59 -05:00
zzz
961936f8d5 bump for review 2022-02-18 13:58:02 -05:00
zzz
7ea31835c2 more translations from Transifex 2022-02-18 13:44:08 -05:00
zzz
bf1f2e4635 pull translations from Transifex 2022-02-18 13:39:24 -05:00
zzz
198008472a i2psnark standalone: Raise open files ulimit
copied from i2prouter script
2022-02-17 13:58:10 -05:00
91e9d95df7 Merge branch 'docker-host-networking' into 'master'
Make Docker host networking safer

See merge request i2p-hackers/i2p.i2p!54
2022-02-16 15:53:32 +00:00
1b5feda517 generic advice for cloud deployments 2022-02-16 15:51:28 +00:00
29f74ba72a change interfaces 0.0.0.0->127.0.0.1 and update documentation 2022-02-16 11:14:10 +00:00
zzz
d6684403a2 Add new Japanese man pages 2022-02-12 13:47:52 -05:00
zzz
388aa233e0 Add new Slovenian translated resources 2022-02-12 13:30:33 -05:00
idk
ea92b79340 set table-width to fixed on console dark theme, and run the auto-indenter on the console light theme to fix it's inconsistent tabs. Merge the chrome-overrides rules on the console light theme CSS. Changes to light theme are entirely cosmetic, except that they improve the reliability of my CSS linter. 2022-02-11 23:01:51 -05:00
idk
3ba754d723 Merge branch 'master' of github.com:i2p/i2p.i2p 2022-02-11 15:34:41 -05:00
idk
d651d25de6 Merge pull request #26 from zlatinb/github-actions
Use GitHub Actions to publish installer.jar on each push
2022-02-11 15:32:37 -05:00
idk
00ea32938e set .wizardimg css to display: none on the dark theme so the light-theme background images don't show up. Normalize the wildly inconsistent tabs tabs in console.css 2022-02-11 15:27:50 -05:00
37002822b3 install.jar fix name 2022-02-11 19:50:40 +00:00
50d56ccbe8 gettext 2022-02-11 19:46:27 +00:00
48cb6f79ef Use GitHub Actions to publish installer.jar on each push 2022-02-11 19:38:04 +00:00
idk
a325e63426 use updateType instead of key for error message in ConsoleUpdateManager with custom UPP 2022-02-10 12:42:50 -05:00
zzz
309e306337 javadoc fixes 2022-02-10 09:02:39 -05:00
zzz
2ba56a5e17 Bump build time 2022-02-10 08:39:46 -05:00
zzz
c949ad5205 Update Manager: Add an UpdateType for the API version 2022-02-10 08:37:52 -05:00
zzz
5621b4bf97 GeoIP 2022-02 2022-02-10 08:28:19 -05:00
idk
dbfe8d24a8 log not-found key should an UPP error occur 2022-02-09 21:33:32 -05:00
zzz
548c0994a7 poupdate-source 2022-02-09 14:25:09 -05:00
zzz
d0ca1d38ca NTCP: Fixes for SSU disabled
Update RI reachability after first inbound connection
Allow local address in test mode
2022-02-09 06:39:18 -05:00
idk
96560e8590 Increase size of unicode links on proxy.css 2022-02-07 00:26:18 -05:00
zzz
19712cfd95 SSU: Fix race NPE in debug logging 2022-02-06 09:51:46 -05:00
idk
3dcc954341 Put description of jump link function on newline in proxy.css 2022-02-04 17:26:27 -05:00
zzz
568b5e303f Tunnels: Avoid buggy routers
SSU: Don't bid on connection to buggy routers
2022-02-03 10:36:03 -05:00
idk
73d90ed5c4 Don't add os-arch to pluginname if it's already correct 2022-02-03 01:51:33 -05:00
idk
b2fe36b0d3 Revise ShellService.name to match ShellService directory if the directory includes -SystemVersion.getOS or -SystemVersion.getArch 2022-02-02 17:37:02 -05:00
idk
632a1578a2 Check executable status of shellservice plugins in start. If the ShellService plugin name doesn't correspond to a directory, check plugin name+-$OS-$ARCH and name+$OS. 2022-02-02 15:18:25 -05:00
idk
e28f4be46b Merge branch 'plugin-config-redux' into 'master'
Adds the ability to use `$OS`  and `$ARCH`  variables in clients.config and plugins.config(updateURL.* only)

Closes #340

See merge request i2p-hackers/i2p.i2p!52
2022-02-02 18:57:30 +00:00
idk
73e34b3941 Adds the ability to use $OS and $ARCH variables in clients.config and plugins.config(updateURL.* only) 2022-02-02 18:57:30 +00:00
b4e2366458 Merge branch 'filefilter-fix' into 'master'
Fix for FileFilterDefinitionElement.  Issue #349

See merge request i2p-hackers/i2p.i2p!50
2022-01-31 13:22:44 +00:00
1389e89f6d Merge branch 'junit-deprecations' into 'master'
fix junit deprecations, issue #339

See merge request i2p-hackers/i2p.i2p!51
2022-01-31 13:11:17 +00:00
c3abe7b3d4 Do not use forEach 2022-01-31 13:10:26 +00:00
042c1e88aa fix junit deprecations, issue #339 2022-01-31 11:39:57 +00:00
899ce0f959 Fix for FileFilterDefinitionElement. Issue #349 2022-01-31 04:38:48 +00:00
zzz
5dd8139aad Reseed, DoH: Fixes for IPv6-only 2022-01-30 11:25:36 -05:00
zzz
13ee324d36 NTCP2: Clock skew handling improvements
as discussed in #ls2 meeting
- Bob replies with Session Created even if skewed,
  so that Alice finds out what the skew is
- Alice handles Session Created timestamp and drops if skewed,
  bans Bob, and updates clock if NTP failed
- If Alice does reply with SessionConfirmed, Bob will send a
  destroy with a skew error code
- Don't change skew error code if netdb store failed
- Fix skew adjustment for RTT by Bob
- Call setLastBadSkew() in the right places
- Fix ntcp.invalidInboundSkew and ntcp.invalidOutboundSkew stats
2022-01-26 07:28:43 -05:00
zzz
afa7278080 NTCP: Ban IP if RI signature fails 2022-01-25 12:22:57 -05:00
zzz
b6be2d7e65 bump -9 2022-01-25 09:42:33 -05:00
zzz
78ba3d1f68 Console: CSS tweak for messages 2022-01-25 09:41:12 -05:00
zzz
d930f0a64a Console: Set encoding for CSS 2022-01-25 09:40:02 -05:00
zzz
c1dc3c8275 Data: Remove dup check for negative tunnel ID 2022-01-25 09:37:26 -05:00
zzz
8bf87da4b1 Transport: BW limiter log and javadoc improvements
Portion of gitlab MR !49
2022-01-25 09:35:33 -05:00
zzz
8812e822f9 Util: CDPQ stat description tweak 2022-01-25 09:29:43 -05:00
zzz
f17cd24dc8 UDP: Pass message priority through to the packets
Change UDP-Sender queue from CoDel to CoDelPriority
No change to CoDel params

UDP msg priorities:
High priority: ack-only, session request/created/confirmed, relay request, hole punch, injected
Low priority: ping, destroy, peer test, relay intro/response
2022-01-25 09:27:49 -05:00
zzz
b9f53069bb Tunnels: Reimplement, re-enable using tunnel builds as a tunnel test,
but without ooming
disabled in 2009 because of ooms
2022-01-25 09:10:00 -05:00
zzz
21f5f7c148 Tunnels: Enable tunnel testing by default
disabled since 2011
2022-01-25 09:03:14 -05:00
idk
3057103875 tweak light proxy.css on non-mobile screens 2022-01-23 11:02:47 -05:00
idk
2752015b6e Simplify, add better logging, correctly mark state change in ShellService 2022-01-22 21:26:59 -05:00
idk
f2e0aacbf0 use Arrays.toString to convert trimmed process args to application args in ShellService. 2022-01-22 14:56:04 -05:00
idk
3e8f8a2bd3 add null check to isProcessRunning() in new ShellService 2022-01-22 00:12:37 -05:00
zzz
77e30e246d Util: Fix leak of SimpleTimer2 shutdown task 2022-01-21 09:09:32 -05:00
idk
5e7a00ede4 Merge branch 'fix-docker-configs-support' into 'master'
Allow chown to fail so files can be managed via docker configs and secrets

See merge request i2p-hackers/i2p.i2p!48
2022-01-16 16:45:56 +00:00
ba55ec09ed Allow chown to fail so files can be managed via docker configs and secrets 2022-01-16 16:45:56 +00:00
zzz
0b058c0ffd i2psnark: Add UDPTrackerClient
WIP - not hooked in, untested - target 1.8.0 / 0.9.54
Requires significant changes to TrackerClient
Adapted from mtn branch i2p.i2p.zzz.udpsnark (2014)
Ref: Proposal 160
2022-01-16 08:58:03 -05:00
idk
61422d9f7f Merge branch 'docker_update' into 'master'
Upgrade base image to latest version of Alpine

See merge request i2p-hackers/i2p.i2p!47
2022-01-15 20:32:48 +00:00
zzz
b63a2e41be i2psnark: html fix 2022-01-15 11:52:13 -05:00
zzz
606961c788 Console: Add ban counts to headers 2022-01-15 06:59:52 -05:00
9573c6ed0f Upgrade base image to latest version of Alpine 2022-01-14 20:17:52 +00:00
idk
70bb63e8ab Make the buttons on the save host form look like the links on the jump host form 2022-01-10 17:16:30 -05:00
idk
b96255a65b Merge branch 'master' of i2pgit.org:i2p-hackers/i2p.i2p 2022-01-10 14:44:45 -05:00
idk
e15dae5c5f Turn jump button-links back into regular-looking hyperlinks when resolution indicates we are not on a mobile device 2022-01-10 14:28:40 -05:00
zzz
695cf8796d javadoc: Add API version 2022-01-10 09:07:07 -05:00
zzz
175f043819 javadoc: Add message flow chart 2022-01-10 08:57:01 -05:00
zzz
662ea995c1 javadoc note 2022-01-07 10:48:48 -05:00
zzz
b8670e1e5b hosts.txt update 2022-01-07 05:53:50 -05:00
zzz
7f4441078d Router: Prevent deadlock at startup
in the transports through PLRIJ via FNDF.publish()
2022-01-06 07:18:42 -05:00
zzz
150248d8d7 Plugins: Fix webapp classpath setting when the webapp name does not match the plugin name 2022-01-05 16:50:33 -05:00
zzz
aaa1da4c66 Plugins: console-icon path is relative to consoleLinkURL if specified,
otherwise relative to plugin name, as before
2022-01-05 15:08:35 -05:00
zzz
8167f5184d hosts.txt update 2022-01-05 06:25:01 -05:00
zzz
034a5acd37 i2pcontrol: Send translated tunnel status string 2022-01-04 13:09:34 -05:00
idk
7249f21602 redirect output and error from process builder to files within the plugin directory 2022-01-03 14:26:27 -05:00
idk
d1192f74f2 Remove platform-specific workarounds from Java 8+ version of ShellService 2022-01-03 14:18:16 -05:00
zzz
13f910be70 i2ptunnel: Add hooks to get the session from the contoller 2022-01-02 11:23:23 -05:00
zzz
2d42541b79 i2pcontrol: Handle more router states mapping to i2pcontrol states
Linkify start/stop webapp on password page
2022-01-02 11:13:15 -05:00
zzz
131da9bdb9 javadoc fixes 2021-12-30 09:59:26 -05:00
zzz
bc97e955e2 bump -7 2021-12-28 12:24:37 -05:00
zzz
faa1bf117a i2ptunnel: Add IRC filter support for IRCv3 message tags
Required for irc.ilita.i2p
2021-12-28 12:07:07 -05:00
zzz
aa386f3bdc bump -6 2021-12-28 10:02:27 -05:00
zzz
f1170b948f NetDB: StoreJob reliability improvements
- Always use a lease as the reply tunnel when publishing LS through a client tunnel
  This ensures we're not using about-to-expire tunnels for the reply,
  and ensures the ff is able pick an alternate
- Don't count skipped peers as attempted in FloodfillVerify
- Pass failed and skipped peers to FloodfillVerify job to be skipped there also
- Pass failed and skipped peers from FloodfillVerify job to the next StoreJob on failure
- Consolidate common reply token generation code in StoreJob
- Ensure tunnel diversity in StoreJob retries by only
  using tunnels closest to the target for the first request.
  This increases reliability by not reusing the same tunnels for all retries.
- Refactor StoreState to rework inefficient methods and unused data
- Clean up commented-out code in StoreState
- Log tweaks
2021-12-28 09:57:42 -05:00
zzz
59ab40779c NetDB: RepublishLeaseSetJob
Don't requeue on failure if there is a newer LS, KNDF will have already done that.
Log tweaks and cleanups
2021-12-28 09:44:39 -05:00
zzz
85b9862b64 NetDB: Ensure tunnel diversity in ISJ retries
by only using tunnels closest to the target for the first request.
This increases reliability by not reusing the same tunnels for all retries.
2021-12-28 09:24:35 -05:00
zzz
132d76a06b NetDB: SearchJob minor cleanup, only call getHash() once 2021-12-28 09:15:48 -05:00
zzz
c4b4b2d4b2 NetDB: Increase lookup throttle time
This reduces the max lookup rate
2021-12-28 09:12:29 -05:00
zzz
db6914f555 NetDB: Use same dbResponseTime rate in ff peer selector as in KNDF.getPeerTimeout()
10 minute rate is too short
Change to getAvgOrLifetimeAvg()
Reduce max time
2021-12-28 09:02:40 -05:00
zzz
bef729463d NetDB: Fix usage of dbResponseTime stat
Actually update the stat for stores in dbStoreSent();
we are generally storing to different ffs than lookups, so we need the
stat for stores as well, since we use it as the timeout in StoreJob.

Change from 1-day to 1-hour stat.
Switch to avgOrLifetimeAvg() so the rate is always valid.
Reduce max time used for timeout.
This allows more peers to be tried before total timeout
Previously, the per-peer timeout was almost always the max.
Make sendStore() package private.
Javadocs and cleanups.
2021-12-28 08:56:47 -05:00
zzz
d0e72aca66 Console: Partial string case-insensitive match for netdb family search 2021-12-28 08:55:29 -05:00
zzz
46ee8be9c6 i2psnark standalone: Add version number to header 2021-12-27 12:40:33 -05:00
zzz
cc3d2cf67b bump -5 2021-12-27 09:00:11 -05:00
zzz
57c997730f Console: Fix display of ip lookup param with netmask in netdb search 2021-12-27 08:55:49 -05:00
zzz
0826f431ef i2psnark standalone: Fixes for router startup and shutdown
so that torrents stop when the router stops and restart when the router restarts.

- Use BWLimits from the DirMonitor as a periodic test that the router is there
- DirMonitor does not attempt to autostart torrents if BWLimits test fails
- DirMonitor does autostart existing torrents when BWLimits test passes again
- Register disconnect listener with socket manger and stop all torrents on disconnect
- Use stopTorrent(true) on router errors to prevent changing the persisted torrent running status
- Change autostart default to true for standalone

Possibly more todo for corner cases or other start/stop/fail scenarios.
2021-12-27 08:52:56 -05:00
zzz
c63cb378e8 I2CP: Send DestroySession message when destroying session
in client-side AppContext SimpleSession, to prevent router-side
error message when closing socket, e.g. for BW limits check
2021-12-27 08:32:04 -05:00
zzz
242dc92397 Banlist: Increase ban time again for routers without netID
it's not a i2pd bug at startup that fixes itself.
2021-12-27 08:27:11 -05:00
zzz
26f34d6985 Debian: Update URL in watch file 2021-12-23 15:28:07 -05:00
idk
e002d3f558 Move ShellService into net.i2p.router.web 2021-12-23 15:10:24 -05:00
zzz
3d5dd639e3 i2psnark standalone: Use previously translated I2CP connect error 2021-12-23 13:49:18 -05:00
zzz
2bfedfbc74 i2psnark standalone: Translate I2CP connect error 2021-12-23 13:06:58 -05:00
zzz
70131c6b25 i2psnark standalone: Pass ctx to logger 2021-12-23 12:02:19 -05:00
zzz
e946040ddd i2psnark standalone: Redirect jetty logging to i2p log 2021-12-23 11:54:51 -05:00
zzz
bab37e57fe i2psnark: Add note for translators 2021-12-23 11:23:00 -05:00
zzz
70e06de846 i2psnark: Translate theme names, translated sort 2021-12-23 11:01:05 -05:00
zzz
11f60a7192 i2psnark standalone: Set launch-i2psnark +x 2021-12-23 09:47:48 -05:00
zzz
6282c365bb i2psnark standalone: Update readme 2021-12-23 09:12:57 -05:00
zzz
621ea49621 i2psnark standalone: Add da, el, and fa to language menu 2021-12-23 08:16:32 -05:00
zzz
e51738d180 i2psnark standalone: Add jbigi.jar
as requested by R4SAS
2021-12-21 06:51:06 -05:00
zzz
811442f9cb Transport: Async NTCP writes (MR !43)
- Write directly from writer threads, except for during establishment and when write doesn't complete; throw those to the pumper as usual
- New NTCPCon writelock, readlock, and statlock (formerly all on NTCPCon.this) to prevent deadlocks
- NTCPCon chan and key now volatile, remove synch to prevent deadlocks
- All interestOps changes now lock on the key via setInterest() and clearInterest() since changes may now happen in multiple threads
- Set _paddingConfig at initialization to avoid NPE

Greatly reduces pumper loops and CPU

As proposed by jogger
Reviewed by zlatinb
Ref: http://zzz.i2p/topics/3192
2021-12-21 06:37:10 -05:00
zzz
464a39b939 MaskedIPSet: More efficient string generation
and don't IAE on 8 byte negative value
2021-12-19 10:53:50 -05:00
zzz
1a05083ed0 Tunnels: Double mask value for IPv6
rather than using a fixed value of 6
so IPv6 default is now 4
2021-12-19 08:38:13 -05:00
zzz
937b6120ff i2psnark standalone: Add notes about changing browser and port 2021-12-18 07:52:30 -05:00
zzz
2a451cdb97 bump -3 2021-12-18 06:34:21 -05:00
zzz
ccba4a197d Tunnels: Do not allow failed tunnels to be rebuilt 2021-12-18 06:33:36 -05:00
zzz
feaff690a3 Debian build doc update 2021-12-18 06:28:19 -05:00
zzz
098ef9a0ff Tunnels: remove log in test timeout job 2021-12-18 06:27:18 -05:00
zzz
f317d29dd5 javadoc fix 2021-12-18 06:25:04 -05:00
zzz
f17b568f19 Tunnels: Remove old NTCP cost=2 check in MaskedIPSet 2021-12-18 06:22:54 -05:00
zzz
5029516087 i2ptunnel: Use defined SOCKS constants 2021-12-18 06:21:25 -05:00
zzz
69699638ae i2psnark: Add avif mime type 2021-12-18 06:19:49 -05:00
zzz
e6c76fa5ae Console: CSS tweak for update status box 2021-12-18 06:18:49 -05:00
zzz
b8435f5e9e Tunnels: Cleanup settings for IP restriction
Check bounds at initialization
Remove unused setIPRestriction()
2021-12-18 06:17:41 -05:00
zzz
5995b0b7a7 Tunnels: Restore support for IP restriction in client tunnels (MR !45)
Removed in May 2011 when we added fast tier slices
Also add support in exploratory tunnels
Create MaskedIPSet in peer selectors, pass to ProfileOrganizer.selectXXX() for each call.
Not required for one-hop tunnels.
Disable for test networks (i2np.allowLocal)
Reported by 'vulnerability_reports' http://zzz.i2p/topics/3215
2021-12-18 06:14:09 -05:00
zzz
80237a57bd Reseed: Renew SSL cert 2021-12-13 07:01:41 -05:00
idk
c4cfe420a6 disable any chance of JNDI lookups in log4j.properties file by setting %m{nolookups}. I don't think we're actually vulnerable to CVE-2021-44228 if I'm understanding correctly, by default it doesn't seem like we actually use log4j for much of anything and we don't do much logging of arbitrarily crafted remote inputs, but also it seems like this JNDI lookups thing is way more trouble than it could possibly be worth to us. Maybe it's a good idea to make sure it's turned off by default. 2021-12-10 21:01:37 -05:00
zzz
14c5d54f0e Reseed: Server list update 2021-12-10 07:58:08 -05:00
zzz
b1a4a8517e i2ptunnel: Refactor UDPTunnel, Streamr, and SOCKS UDP for I2CP ports
- Add fromPort and toPort to Sink interface (breaking API change)
- Change cache maps from Destination to I2PSocketAddress to include port
- Accept host:port for destination in Streamr Client, use port
  as toPort in pinger
- Change to muxed listener in I2PSource, only listen for
  specified protocols
- Eliminate thread and queue in I2PSource, process messages inline
  in the listener
- Add support for handling both repliable and raw datagrams in
  a single I2PSource instance
- Remove verify option from I2PSource and I2PTunnelUDPServerBase,
  always verify repliable datagrams
- Add getPort() method to UDPSource
- Add a constructor to UDPSink to pass in an existing DatagramSocket
- Change I2PTunnelUDPClientBase to receive both repliable and raw
- Change SOCKSUDPTunnel reply handling strategy to key on I2CP toPort;
  remove ReplyTracker; the tunnel would not have worked before, because
  it expected raw replies only but MultiSink required a destination
  to look up where to forward the reply.
- Mark SOCKSUDPTunnel as preliminary; note lack of support
  for raw replies; untested
- Change Streamr Client Pinger to support fromPort
- Change Streamr Server to remember fromPort in subscriptions
  and use it as toPort in data stream
- Move fields to top of classes for sanity
- Cleanups and log tweaks
2021-12-08 13:05:27 -05:00
zzz
22ff40bc84 Build: Add missing @Override annotations (dep-ann lint) 2021-12-07 15:33:41 -05:00
zzz
b5d7dffb08 Debian: Add explicit dependency on libservlet3.1-java (Debian #997213)
libjetty9-java used to depend on libservlet3.1-java
but now in sid it doesn't.
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=997213
2021-12-07 14:14:32 -05:00
zzz
a59cad0066 Router: Tweak shutdown messages
Change one from CRIT to WARN
Translate one of them
Attempt to translate class name in notifications
2021-12-05 07:21:57 -05:00
zzz
cbb6a6db65 DTG: Add menu items to control notifications
Fix check for successful configuration save
2021-12-05 06:38:28 -05:00
zzz
730b9790d9 Console: Remove job queue link on /configservice 2021-12-04 16:54:12 -05:00
zzz
ebf6ca5b34 Console: Case-insensitive sort of jobs on /jobs 2021-12-04 16:03:53 -05:00
zzz
0422134a86 SusiMail: Notify new messages on DTG
experimental
2021-12-04 12:47:47 -05:00
zzz
1a77352fa7 i2psnark: Notify completed downloads on DTG
experimental
2021-12-04 11:59:39 -05:00
zzz
cc971eb34f Build: Fix minimum Java version in installer config 2021-12-04 10:56:45 -05:00
zzz
fa0e59435e DTG: Change icon from white to black on Windows by default
Will be set to the opposite of the console theme.
2021-12-04 10:48:11 -05:00
zzz
962cc31f31 DTG: Show all CRIT messages on DTG.
Experimental, may add a separate config or disable later.
Show I2P starting message in DTG
2021-12-04 09:50:08 -05:00
zzz
87362fd68b i2psnark: Edit torrent page cleanup - remove unneeded info 2021-12-04 08:02:37 -05:00
zzz
51f6bef5dc i2psnark: Respect newlines in torrent comments 2021-12-04 07:38:24 -05:00
idk
a1ea48e2b6 Fix the very first ShellService bug, the long pid should be parsed from the pidString from the wrapper output, or it won't be available 2021-12-03 22:44:46 -05:00
zzz
e9aa3a55cc Add file missing from previous checkin to fix build 2021-12-03 16:51:51 -05:00
zzz
d03c690724 Tunnels: Immediately fail outbound tunnels when
we can't connect to the first hop
by attaching an onSendFailJob in OutboundSender.
Check if failed in isValidTunnel()
2021-12-03 12:51:01 -05:00
zzz
2a900a8c5b i2psnark: Add torrent edit page
Additional UI cleanup to follow
2021-12-03 06:26:14 -05:00
zzz
de995761db Tunnels: Change tunnel test failure count to AtomicInteger 2021-12-03 06:15:37 -05:00
zzz
cfbdf8385d Tunnels: Count consecutive build timeouts per-pool
Use exploratory paired tunnel after too many timeouts
2021-12-03 06:10:21 -05:00
zzz
83b959c4a1 Tunnels: Remove 2nd arg on TestJob failure stats 2021-12-03 05:51:56 -05:00
zzz
e66ec208a8 Tunnels: Refactor build completion handling
- Add result code to BuildExecutor.buildComplete() and TunnelPool.buildComplete()
- Remove BuildExecutor.buildSuccessful(), move to buildComplete()
- Move ExpireJob creation to buildComplete()
- TunnelPool.buildComplete() now calls addTunnel()
- Eliminate some now() calls
2021-12-03 05:48:27 -05:00
zzz
cf22186182 Router: Shorter ban time for localhost addresses 2021-12-01 15:51:44 -05:00
zzz
890a8927a5 DTG: Add notification service to display popup messages
unused for now
2021-12-01 08:37:51 -05:00
zzz
dd439bc9be Transport: Add NTCPConnection.getRemoteIP()
to match SSU PeerState method
2021-11-30 11:24:24 -05:00
zzz
537a8bf19b Console: Linkify router hashes on Sybil analysis 2021-11-30 11:14:51 -05:00
zzz
bd0c696b84 CLI: Allow empty blocklist when signing news feed 2021-11-30 11:11:30 -05:00
zzz
5c56884d7f bump -1 2021-11-30 10:51:33 -05:00
zzz
b53707074f DTG: Add classpath to jar, add early check for support when called by CLI
for ease of command-line testing
2021-11-30 10:26:52 -05:00
zzz
6cb8d2eeb7 i2ptunnel: Increase default priority for IRC and standard tunnels 2021-11-30 10:23:14 -05:00
zzz
3895cd1068 Console: NetDB search form improvements 2021-11-30 09:53:44 -05:00
zzz
5b2fbc4ec4 Build: Add bumpBuildTime target 2021-11-30 09:35:06 -05:00
zzz
87654e2f4f Build: Remove BOB from installer, updater, and clients.config
Source remains for now and may still be built with ant buildBOB.
Existing non-package installs will continue to work.
2021-11-30 09:31:06 -05:00
zzz
9c29f8c8ff Debian files for 1.6.1
fix a lintian warning about compare-versions
update launchpad doc for git
2021-11-30 08:53:49 -05:00
296 changed files with 37419 additions and 29429 deletions

34
.github/workflows/ant.yml vendored Normal file
View File

@ -0,0 +1,34 @@
# Mostly copied from https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-ant
# zlatinb
name: Java CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: GetText
run: sudo apt install gettext
- uses: actions/checkout@v2
- name: Set up JDK 8
uses: actions/setup-java@v2
with:
java-version: '8'
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: build with Ant
run: ant distclean pkg
- name: Upload installer.jar
uses: actions/upload-artifact@v2
with:
name: I2P-install.jar-${{ github.sha }}
path: install.jar

View File

@ -256,6 +256,7 @@ trans.pt_BR = apps/routerconsole/locale-countries/messages_pt_BR.po
trans.ro = apps/routerconsole/locale-countries/messages_ro.po
trans.ru_RU = apps/routerconsole/locale-countries/messages_ru.po
trans.sk = apps/routerconsole/locale-countries/messages_sk.po
trans.sl = apps/routerconsole/locale-countries/messages_sl.po
trans.sq = apps/routerconsole/locale-countries/messages_sq.po
trans.sr = apps/routerconsole/locale-countries/messages_sr.po
trans.sv_SE = apps/routerconsole/locale-countries/messages_sv.po
@ -364,6 +365,7 @@ trans.pt_BR = apps/desktopgui/locale/messages_pt_BR.po
trans.ro = apps/desktopgui/locale/messages_ro.po
trans.ru_RU = apps/desktopgui/locale/messages_ru.po
trans.sk = apps/desktopgui/locale/messages_sk.po
trans.sl = apps/desktopgui/locale/messages_sl.po
trans.sr = apps/desktopgui/locale/messages_sr.po
trans.sv_SE = apps/desktopgui/locale/messages_sv.po
trans.sq = apps/desktopgui/locale/messages_sq.po
@ -442,6 +444,7 @@ trans.pt_BR = debian/po/pt_BR.po
trans.ro = debian/po/ro.po
trans.ru_RU = debian/po/ru.po
trans.sk = debian/po/sk.po
trans.sl = debian/po/sl.po
trans.sq = debian/po/sq.po
trans.sv_SE = debian/po/sv.po
trans.tk = debian/po/tk.po
@ -578,6 +581,7 @@ trans.fr = installer/resources/locale-man/man_fr.po
trans.hu = installer/resources/locale-man/man_hu.po
trans.id = installer/resources/locale-man/man_id.po
trans.it = installer/resources/locale-man/man_it.po
trans.ja = installer/resources/locale-man/man_ja.po
trans.ko = installer/resources/locale-man/man_ko.po
trans.nl = installer/resources/locale-man/man_nl.po
trans.pl = installer/resources/locale-man/man_pl.po
@ -642,6 +646,7 @@ trans.pl = apps/routerconsole/resources/docs/readme_pl.html
trans.pt = apps/routerconsole/resources/docs/readme_pt.html
trans.ro = apps/routerconsole/resources/docs/readme_ro.html
trans.ru_RU = apps/routerconsole/resources/docs/readme_ru.html
trans.sl = apps/routerconsole/resources/docs/readme_sl.html
trans.tr_TR = apps/routerconsole/resources/docs/readme_tr.html
trans.uk_UA = apps/routerconsole/resources/docs/readme_uk.html
trans.zh_CN = apps/routerconsole/resources/docs/readme_zh.html

View File

@ -1,5 +1,25 @@
# I2P in Docker
### Very quick start
If you just want to give I2P a quick try or are using it on a home network, follow these steps:
1. Create two directories `i2pconfig` and `i2ptorrents`
2. Copy the following text and save it in a file `docker-compose.yml`
```
version: "3.5"
services:
i2p:
image: geti2p/i2p
network_mode: host
volumes:
- ./i2pconfig:/i2p/.i2p
- ./i2ptorrents:/i2psnark
```
3. Execute `docker-compose up`
4. Start a browser and go to `http://127.0.0.1:7657` to complete the setup wizard.
Note that this quick-start approach is not recommended for production deployments on remote servers. Please read the rest of this document for more information.
### 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:
```
@ -17,21 +37,26 @@ By the default the image limits the memory available to the Java heap to 512MB.
#### Ports
There are several ports which are exposed by the image. You can choose which ones to publish depending on your specific needs.
|Port|Description|TCP/UDP|
|---|---|---|
|4444|HTTP Proxy|TCP|
|4445|HTTPS Proxy|TCP|
|6668|IRC Proxy|TCP|
|7654|I2CP Protocol|TCP|
|7656|SAM Bridge TCP|TCP|
|7657|Router console|TCP|
|7658|I2P Site|TCP|
|7659|SMTP Proxy|TCP|
|7660|POP Proxy|TCP|
|12345|I2NP Protocol|TCP and UDP|
|Port|Interface|Description|TCP/UDP|
|---|---|---|---|
|4444|127.0.0.1|HTTP Proxy|TCP|
|4445|127.0.0.1|HTTPS Proxy|TCP|
|6668|127.0.0.1|IRC Proxy|TCP|
|7654|127.0.0.1|I2CP Protocol|TCP|
|7656|127.0.0.1|SAM Bridge TCP|TCP|
|7657|127.0.0.1|Router console|TCP|
|7658|127.0.0.1|I2P Site|TCP|
|7659|127.0.0.1|SMTP Proxy|TCP|
|7660|127.0.0.1|POP Proxy|TCP|
|7652|LAN interface|UPnP|TCP|
|7653|LAN interface|UPnP|UDP|
|12345|0.0.0.0|I2NP Protocol|TCP and UDP|
You probably want at least the Router Console (7657) and the HTTP Proxy (4444). If you want I2P to be able to receive incoming connections from the internet, and hence not think it's firewalled, publish the I2NP Protocol port (12345) - but make sure you publish to a different random port, otherwise others may be able to guess you're running I2P in a Docker image.
#### Networking
A best-practices guide for cloud deployments is beyond the scope of this document, but in general you should try to minimize the number of published ports, while exposing only the `I2NP` ports to the internet. That means that the services in the list above which are bound to `127.0.0.1` (which include the router console) will need to be accessed via other methods like ssh tunneling or be manually configured to bind to a different interface.
#### 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.
```

View File

@ -1,4 +1,4 @@
FROM jlesage/baseimage:alpine-3.10-glibc as builder
FROM jlesage/baseimage:alpine-3.15-glibc as builder
ENV APP_HOME="/i2p"
@ -10,7 +10,7 @@ RUN add-pkg --virtual build-base gettext tar bzip2 apache-ant openjdk8 \
&& rm -rf pkg-temp/osid pkg-temp/lib/wrapper pkg-temp/lib/wrapper.* \
&& del-pkg build-base gettext tar bzip2 apache-ant openjdk8
FROM jlesage/baseimage:alpine-3.10-glibc
FROM jlesage/baseimage:alpine-3.15-glibc
ENV APP_HOME="/i2p"
RUN add-pkg openjdk8-jre

View File

@ -64,6 +64,9 @@ your `~/.gradle/gradle.properties`:
systemProp.socksProxyHost=localhost
systemProp.socksProxyPort=9150
### Development builds
Automatic CI builds are available at the [continuous integration](https://github.com/i2p/i2p.i2p/actions/workflows/ant.yml) page.
### Docker
For more information how to run I2P in Docker, see [Docker.md](Docker.md)
## Contact info

View File

@ -10,6 +10,7 @@
<property name="javac.version" value="1.8" />
<property name="javac.release" value="8" />
<property name="require.gettext" value="true" />
<property name="manifest.classpath.name" value="Class-Path" />
<condition property="no.bundle">
<isfalse value="${require.gettext}" />
@ -86,6 +87,7 @@
<jar basedir="${build}" excludes="messages-src/**" destfile="${dist}/${jar}">
<manifest>
<attribute name="Main-Class" value="net.i2p.desktopgui.Main"/>
<attribute name="${manifest.classpath.name}" value="i2p.jar router.jar" />
<attribute name="Implementation-Version" value="${full.version}" />
<attribute name="Built-By" value="${build.built-by}" />
<attribute name="Build-Date" value="${build.timestamp}" />

View File

@ -10,9 +10,9 @@ msgid ""
msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
"PO-Revision-Date: 2017-09-20 20:31+0000\n"
"Last-Translator: Vitaly Zdorovenko <stenliterziev@gmail.com>\n"
"POT-Creation-Date: 2022-02-09 19:13+0000\n"
"PO-Revision-Date: 2022-02-09 19:23+0000\n"
"Last-Translator: zzzi2p\n"
"Language-Team: Bulgarian (http://www.transifex.com/otf/I2P/language/bg/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -27,69 +27,81 @@ msgstr "Стартиране на 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 е стартиран!"
#: 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:55
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
msgid "Launch I2P Browser"
msgstr "Стартиране на I2P Браузер"
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
msgid "Configure I2P 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:87
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
msgid "Enable notifications"
msgstr ""
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
#: 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:131
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
msgid "Restart I2P"
msgstr "Рестартиране на I2P"
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
msgid "Stop I2P"
msgstr "Спиране на I2P"
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
#: 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:143
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
#: 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:157
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
#: 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:363
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
#, java-format
msgid "Shutdown in {0}"
msgstr "Изключване в {0}"
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
msgid "Shutdown imminent"
msgstr ""
#. status translations are in the console bundle
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
#: src/net/i2p/desktopgui/InternalTrayManager.java:444
msgid "Network"
msgstr ""
msgstr "Мрежа"
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
#: src/net/i2p/desktopgui/TrayManager.java:63
#: src/net/i2p/desktopgui/TrayManager.java:73
msgid "I2P: Right-click for menu"
msgstr ""

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: I2P desktopgui\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-08-11 15:33+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"
@ -25,69 +25,81 @@ 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:54
#: src/net/i2p/desktopgui/InternalTrayManager.java:206
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
msgid "Launch I2P Browser"
msgstr ""
#: src/net/i2p/desktopgui/InternalTrayManager.java:75
#: src/net/i2p/desktopgui/InternalTrayManager.java:227
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
msgid "Configure I2P System Tray"
msgstr ""
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
msgid "Disable"
#: src/net/i2p/desktopgui/InternalTrayManager.java:87
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
msgid "Enable notifications"
msgstr ""
#: src/net/i2p/desktopgui/InternalTrayManager.java:92
#: src/net/i2p/desktopgui/InternalTrayManager.java:244
#: 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:131
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
msgid "Restart I2P"
msgstr ""
#: src/net/i2p/desktopgui/InternalTrayManager.java:109
#: src/net/i2p/desktopgui/InternalTrayManager.java:261
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
msgid "Stop I2P"
msgstr ""
#: src/net/i2p/desktopgui/InternalTrayManager.java:125
#: src/net/i2p/desktopgui/InternalTrayManager.java:277
#: 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:142
#: src/net/i2p/desktopgui/InternalTrayManager.java:294
#: 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:156
#: src/net/i2p/desktopgui/InternalTrayManager.java:308
#: 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:362
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
#, java-format
msgid "Shutdown in {0}"
msgstr ""
#: src/net/i2p/desktopgui/InternalTrayManager.java:364
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
msgid "Shutdown imminent"
msgstr ""
#. status translations are in the console bundle
#: src/net/i2p/desktopgui/InternalTrayManager.java:369
#: 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:63
#: src/net/i2p/desktopgui/TrayManager.java:73
msgid "I2P: Right-click for menu"
msgstr ""

View File

@ -4,15 +4,16 @@
# To contribute translations, see http://www.i2p2.de/newdevelopers
#
# Translators:
# タカハシ <indexial@outlook.jp>, 2013
# daingewuvzeevisiddfddd, 2022
# タカハシ, 2013
# Masayuki Hatta <mhatta@mhatta.org>, 2018
msgid ""
msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
"PO-Revision-Date: 2018-08-17 22:08+0000\n"
"Last-Translator: Masayuki Hatta <mhatta@mhatta.org>\n"
"POT-Creation-Date: 2022-02-09 19:13+0000\n"
"PO-Revision-Date: 2022-02-13 03:11+0000\n"
"Last-Translator: daingewuvzeevisiddfddd\n"
"Language-Team: Japanese (http://www.transifex.com/otf/I2P/language/ja/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -27,69 +28,81 @@ msgstr "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 を起動中!"
#: 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:55
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
msgid "Launch I2P Browser"
msgstr "I2P ブラウザを起動"
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
msgid "Configure I2P System Tray"
msgstr "I2P システムトレイを設定"
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
msgid "Disable"
msgstr "無効"
#: src/net/i2p/desktopgui/InternalTrayManager.java:87
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
msgid "Enable notifications"
msgstr "通知を有効化"
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
#: 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:131
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
msgid "Restart I2P"
msgstr "I2P を再起動"
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
msgid "Stop I2P"
msgstr "I2P を停止"
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
#: src/net/i2p/desktopgui/InternalTrayManager.java:164
#: src/net/i2p/desktopgui/InternalTrayManager.java:348
msgid "Restart I2P Immediately"
msgstr "すぐに I2P を再起動"
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
#: src/net/i2p/desktopgui/InternalTrayManager.java:181
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
msgid "Stop I2P Immediately"
msgstr "すぐに I2P を停止"
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
#: src/net/i2p/desktopgui/InternalTrayManager.java:195
#: src/net/i2p/desktopgui/InternalTrayManager.java:379
msgid "Cancel I2P Shutdown"
msgstr "I2P のシャットダウンを中止"
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
#, java-format
msgid "Shutdown in {0}"
msgstr "{0} でシャットダウン"
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
msgid "Shutdown imminent"
msgstr "即時シャットダウン"
#. status translations are in the console bundle
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
#: 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:63
#: src/net/i2p/desktopgui/TrayManager.java:73
msgid "I2P: Right-click for menu"
msgstr "I2P: 右クリックでメニュー"

View File

@ -0,0 +1,106 @@
# I2P
# Copyright (C) 2009 The I2P Project
# This file is distributed under the same license as the desktopgui package.
# To contribute translations, see http://www.i2p2.de/newdevelopers
#
# Translators:
# Žan Šadl-Ferš, 2021
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: 2022-02-09 19:23+0000\n"
"Last-Translator: zzzi2p\n"
"Language-Team: Slovenian (http://www.transifex.com/otf/I2P/language/sl/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: sl\n"
"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n"
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
msgid "Start I2P"
msgstr "Zaženi 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 se zaganja!"
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
msgid "Starting"
msgstr "Zaganja"
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
msgid "Launch I2P Browser"
msgstr "Zaženi I2P brskalnik"
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
msgid "Configure I2P System Tray"
msgstr "Konfiguriraj I2P opravilno vrstico"
#: 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:131
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
msgid "Restart I2P"
msgstr "Ponovno zaženi I2P"
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
msgid "Stop I2P"
msgstr "Ustavi I2P"
#: src/net/i2p/desktopgui/InternalTrayManager.java:164
#: src/net/i2p/desktopgui/InternalTrayManager.java:348
msgid "Restart I2P Immediately"
msgstr "Nemudoma ponovno zaženi I2P"
#: src/net/i2p/desktopgui/InternalTrayManager.java:181
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
msgid "Stop I2P Immediately"
msgstr "Nemudoma ustavi I2P"
#: src/net/i2p/desktopgui/InternalTrayManager.java:195
#: src/net/i2p/desktopgui/InternalTrayManager.java:379
msgid "Cancel I2P Shutdown"
msgstr "Prekliči zaustavitev od I2P"
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
#, java-format
msgid "Shutdown in {0}"
msgstr "Zaustavi v {0}"
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
msgid "Shutdown imminent"
msgstr "Zaustavitev je neizbežna"
#. status translations are in the console bundle
#: src/net/i2p/desktopgui/InternalTrayManager.java:444
msgid "Network"
msgstr "Omrežje"
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
#: src/net/i2p/desktopgui/TrayManager.java:73
msgid "I2P: Right-click for menu"
msgstr "I2P: Pritisnite na desno tipko miške za meni"

View File

@ -4,15 +4,16 @@
# To contribute translations, see http://www.i2p2.de/newdevelopers
#
# Translators:
# Besnik <besnik@programeshqip.org>, 2016,2019
# Besnik Bleta <besnik@programeshqip.org>, 2022
# Besnik Bleta <besnik@programeshqip.org>, 2016,2019
# Shpetim <shpetim@privacysolutions.no>, 2014
msgid ""
msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
"PO-Revision-Date: 2019-01-10 14:28+0000\n"
"Last-Translator: Besnik <besnik@programeshqip.org>\n"
"POT-Creation-Date: 2022-02-09 19:13+0000\n"
"PO-Revision-Date: 2022-02-10 10:34+0000\n"
"Last-Translator: Besnik Bleta <besnik@programeshqip.org>\n"
"Language-Team: Albanian (http://www.transifex.com/otf/I2P/language/sq/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -27,69 +28,81 @@ msgstr "Nise I2P-në"
#: 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 po niset!"
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
msgid "Starting"
msgstr "Po niset"
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
msgid "Launch I2P Browser"
msgstr "Nis Shfletuesin I2P"
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
msgid "Configure I2P System Tray"
msgstr "Formësoni Panel Sistemi I2P"
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
msgid "Disable"
msgstr "Çaktivizoje"
#: src/net/i2p/desktopgui/InternalTrayManager.java:87
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
msgid "Enable notifications"
msgstr "Aktivizoni njoftimet"
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
#: src/net/i2p/desktopgui/InternalTrayManager.java:101
#: src/net/i2p/desktopgui/InternalTrayManager.java:285
msgid "Disable notifications"
msgstr "Çaktivizoni njoftimet"
#: src/net/i2p/desktopgui/InternalTrayManager.java:115
#: src/net/i2p/desktopgui/InternalTrayManager.java:299
msgid "Disable system tray"
msgstr "Çaktivizo panel sistemi"
#: src/net/i2p/desktopgui/InternalTrayManager.java:131
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
msgid "Restart I2P"
msgstr "Rinise I2P-në"
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
msgid "Stop I2P"
msgstr "Ndale I2P-në"
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
#: src/net/i2p/desktopgui/InternalTrayManager.java:164
#: src/net/i2p/desktopgui/InternalTrayManager.java:348
msgid "Restart I2P Immediately"
msgstr "Rinise I2P-në Menjëherë"
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
#: src/net/i2p/desktopgui/InternalTrayManager.java:181
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
msgid "Stop I2P Immediately"
msgstr "Ndale I2P-në Menjëherë"
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
#: src/net/i2p/desktopgui/InternalTrayManager.java:195
#: src/net/i2p/desktopgui/InternalTrayManager.java:379
msgid "Cancel I2P Shutdown"
msgstr "Anuloje Mbylljen e I2P-së"
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
#, java-format
msgid "Shutdown in {0}"
msgstr "Mbylle për {0}"
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
msgid "Shutdown imminent"
msgstr "Mbyllje shumë shpejt"
#. status translations are in the console bundle
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
#: src/net/i2p/desktopgui/InternalTrayManager.java:444
msgid "Network"
msgstr "Rrjet"
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
#: src/net/i2p/desktopgui/TrayManager.java:63
#: src/net/i2p/desktopgui/TrayManager.java:73
msgid "I2P: Right-click for menu"
msgstr "I2P: Djathtasklikoni për menu"

View File

@ -4,20 +4,20 @@
# To contribute translations, see http://www.i2p2.de/newdevelopers
#
# Translators:
# Kaya Zeren <kayazeren@gmail.com>, 2013,2016
# Kaya Zeren <kayazeren@gmail.com>, 2013,2016,2022
msgid ""
msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
"PO-Revision-Date: 2017-06-30 21:32+0000\n"
"POT-Creation-Date: 2022-02-09 19:13+0000\n"
"PO-Revision-Date: 2022-02-10 04:40+0000\n"
"Last-Translator: Kaya Zeren <kayazeren@gmail.com>\n"
"Language-Team: Turkish (Turkey) (http://www.transifex.com/otf/I2P/language/tr_TR/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: tr_TR\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
@ -26,69 +26,81 @@ msgstr "I2P başlasın"
#: 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 başlatılıyor!"
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
msgid "Starting"
msgstr "Başlatılıyor"
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
msgid "Launch I2P Browser"
msgstr "I2P Tarayıcısını ın"
msgstr "I2P tarayıcısını "
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
msgid "Configure I2P System Tray"
msgstr "I2P Sistem Tepsisi Ayarları"
msgstr "I2P sistem tepsisi ayarları"
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
msgid "Disable"
msgstr "Devre Dışı"
#: src/net/i2p/desktopgui/InternalTrayManager.java:87
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
msgid "Enable notifications"
msgstr "Bildirimleri etkinleştir"
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
#: src/net/i2p/desktopgui/InternalTrayManager.java:101
#: src/net/i2p/desktopgui/InternalTrayManager.java:285
msgid "Disable notifications"
msgstr "Bildirimleri devre dışı bırak"
#: src/net/i2p/desktopgui/InternalTrayManager.java:115
#: src/net/i2p/desktopgui/InternalTrayManager.java:299
msgid "Disable system tray"
msgstr "Sistem tepsisini devre dışı bırak"
#: src/net/i2p/desktopgui/InternalTrayManager.java:131
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
msgid "Restart I2P"
msgstr "I2P Yeniden Başlasın"
msgstr "I2P yeniden başlasın"
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
msgid "Stop I2P"
msgstr "I2P Durdurulsun"
msgstr "I2P durdurulsun"
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
#: src/net/i2p/desktopgui/InternalTrayManager.java:164
#: src/net/i2p/desktopgui/InternalTrayManager.java:348
msgid "Restart I2P Immediately"
msgstr "I2P Hemen Yeniden Başlatılsın"
msgstr "I2P hemen yeniden başlatılsın"
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
#: src/net/i2p/desktopgui/InternalTrayManager.java:181
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
msgid "Stop I2P Immediately"
msgstr "I2P Hemen Durdurulsun"
msgstr "I2P hemen durdurulsun"
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
#: src/net/i2p/desktopgui/InternalTrayManager.java:195
#: src/net/i2p/desktopgui/InternalTrayManager.java:379
msgid "Cancel I2P Shutdown"
msgstr "I2P Kapatmayı İptal Et"
msgstr "I2P kapatmayı iptal et"
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
#, java-format
msgid "Shutdown in {0}"
msgstr "{0} içinde kapat"
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
msgid "Shutdown imminent"
msgstr "Kapatılmak üzere"
#. status translations are in the console bundle
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
#: src/net/i2p/desktopgui/InternalTrayManager.java:444
msgid "Network"
msgstr "Ağ"
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
#: src/net/i2p/desktopgui/TrayManager.java:63
#: src/net/i2p/desktopgui/TrayManager.java:73
msgid "I2P: Right-click for menu"
msgstr "I2P: Menüde sağ tık"

View File

@ -5,15 +5,15 @@
#
# Translators:
# ducki2p <ducki2p@gmail.com>, 2011
# Scott Rhodes <starring169@gmail.com>, 2021
# Scott Rhodes <starring169@gmail.com>, 2021-2022
# walking <walking@i2pmail.org>, 2011
# YFdyh000 <yfdyh000@gmail.com>, 2016
msgid ""
msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
"PO-Revision-Date: 2021-03-07 07:58+0000\n"
"POT-Creation-Date: 2022-02-09 19:13+0000\n"
"PO-Revision-Date: 2022-02-16 16:05+0000\n"
"Last-Translator: Scott Rhodes <starring169@gmail.com>\n"
"Language-Team: Chinese (China) (http://www.transifex.com/otf/I2P/language/zh_CN/)\n"
"MIME-Version: 1.0\n"
@ -29,69 +29,81 @@ msgstr "启动 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 正在启动!"
#: 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:55
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
msgid "Launch I2P Browser"
msgstr "启动 I2P 浏览器"
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
msgid "Configure I2P System Tray"
msgstr "配置 I2P 系统托盘"
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
msgid "Disable"
msgstr "禁用"
#: src/net/i2p/desktopgui/InternalTrayManager.java:87
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
msgid "Enable notifications"
msgstr "启用通知"
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
#: 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:131
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
msgid "Restart I2P"
msgstr "重启 I2P"
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
msgid "Stop I2P"
msgstr "停止 I2P"
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
#: src/net/i2p/desktopgui/InternalTrayManager.java:164
#: src/net/i2p/desktopgui/InternalTrayManager.java:348
msgid "Restart I2P Immediately"
msgstr "立即重启 I2P"
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
#: src/net/i2p/desktopgui/InternalTrayManager.java:181
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
msgid "Stop I2P Immediately"
msgstr "立即停止 I2P"
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
#: src/net/i2p/desktopgui/InternalTrayManager.java:195
#: src/net/i2p/desktopgui/InternalTrayManager.java:379
msgid "Cancel I2P Shutdown"
msgstr "取消 I2P 关闭"
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
#, java-format
msgid "Shutdown in {0}"
msgstr "{0} 后关闭"
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
msgid "Shutdown imminent"
msgstr "立即关闭"
#. status translations are in the console bundle
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
#: 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:63
#: src/net/i2p/desktopgui/TrayManager.java:73
msgid "I2P: Right-click for menu"
msgstr "I2P右击获得菜单"

View File

@ -1,5 +1,6 @@
package net.i2p.desktopgui;
import java.awt.AWTException;
import java.awt.Desktop;
import java.awt.Desktop.Action;
import java.awt.MenuItem;
@ -30,9 +31,11 @@ class InternalTrayManager extends TrayManager {
private final RouterContext _context;
private final Log log;
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);
@ -44,6 +47,14 @@ class InternalTrayManager extends TrayManager {
log = ctx.logManager().getLog(InternalTrayManager.class);
}
/**
* @since 0.9.53
*/
public void startManager() throws AWTException {
super.startManager();
displayMessage(Log.INFO, _t("Starting"), _t("I2P is starting!"), null);
}
public synchronized PopupMenu getMainMenu() {
PopupMenu popup = new PopupMenu();
@ -73,7 +84,35 @@ class InternalTrayManager extends TrayManager {
}
PopupMenu desktopguiConfigurationLauncher = new PopupMenu(_t("Configure I2P System Tray"));
MenuItem configSubmenu = new MenuItem(_t("Disable"));
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() {
@Override
public void actionPerformed(ActionEvent arg0) {
@ -173,6 +212,8 @@ class InternalTrayManager extends TrayManager {
popup.add(browserLauncher);
popup.addSeparator();
}
desktopguiConfigurationLauncher.add(notificationItem2);
desktopguiConfigurationLauncher.add(notificationItem1);
desktopguiConfigurationLauncher.add(configSubmenu);
popup.add(desktopguiConfigurationLauncher);
popup.addSeparator();
@ -187,6 +228,8 @@ class InternalTrayManager extends TrayManager {
_statusItem = statusItem;
_browserItem = browserLauncher;
_configItem = desktopguiConfigurationLauncher;
_notificationItem1 = notificationItem1;
_notificationItem2 = notificationItem2;
_restartItem = restartItem;
_stopItem = stopItem;
_restartHardItem = restartItem2;
@ -225,7 +268,35 @@ class InternalTrayManager extends TrayManager {
}
JMenu desktopguiConfigurationLauncher = new JMenu(_t("Configure I2P System Tray"));
JMenuItem configSubmenu = new JMenuItem(_t("Disable"));
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() {
@Override
public void actionPerformed(ActionEvent arg0) {
@ -325,6 +396,8 @@ class InternalTrayManager extends TrayManager {
popup.add(browserLauncher);
popup.addSeparator();
}
desktopguiConfigurationLauncher.add(notificationItem2);
desktopguiConfigurationLauncher.add(notificationItem1);
desktopguiConfigurationLauncher.add(configSubmenu);
popup.add(desktopguiConfigurationLauncher);
popup.addSeparator();
@ -339,6 +412,8 @@ class InternalTrayManager extends TrayManager {
_jstatusItem = statusItem;
_jbrowserItem = browserLauncher;
_jconfigItem = desktopguiConfigurationLauncher;
_jnotificationItem1 = notificationItem1;
_jnotificationItem2 = notificationItem2;
_jrestartItem = restartItem;
_jstopItem = stopItem;
_jrestartHardItem = restartItem2;
@ -390,6 +465,10 @@ class InternalTrayManager extends TrayManager {
_stopHardItem.setEnabled(!imminent);
if (_cancelItem != null)
_cancelItem.setEnabled(x && !imminent);
if (_notificationItem1 != null)
_notificationItem1.setEnabled(_showNotifications);
if (_notificationItem2 != null)
_notificationItem2.setEnabled(!_showNotifications);
if (_jstatusItem != null)
_jstatusItem.setText(status);
@ -407,6 +486,10 @@ class InternalTrayManager extends TrayManager {
_jstopHardItem.setVisible(!imminent);
if (_jcancelItem != null)
_jcancelItem.setVisible(x && !imminent);
if (_jnotificationItem1 != null)
_jnotificationItem1.setVisible(_showNotifications);
if (_jnotificationItem2 != null)
_jnotificationItem2.setVisible(!_showNotifications);
}
/**
@ -415,18 +498,24 @@ class InternalTrayManager extends TrayManager {
private void configureDesktopgui(boolean enable) {
String property = Main.PROP_ENABLE;
String value = Boolean.toString(enable);
try {
_context.router().saveConfig(property, value);
if (!enable) {
// TODO popup that explains how to re-enable in console
_main.shutdown(null);
}
} catch (Exception ex) {
log.error("Error saving config", ex);
if (!_context.router().saveConfig(property, value))
log.error("Error saving config");
if (!enable) {
// TODO popup that explains how to re-enable in console
_main.shutdown(null);
}
}
/**
* @since 0.9.53
*/
private void configureNotifications(boolean enable) {
_showNotifications = enable;
String value = Boolean.toString(enable);
if (!_context.router().saveConfig(PROP_NOTIFICATIONS, value))
log.error("Error saving config");
}
/**
* Build the console URL with info from the port mapper,
* and launch the browser at it.

View File

@ -5,6 +5,7 @@ package net.i2p.desktopgui;
*/
import java.awt.Image;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.io.File;
import java.lang.reflect.Method;
@ -16,6 +17,7 @@ import net.i2p.I2PAppContext;
import net.i2p.app.ClientAppManager;
import net.i2p.app.ClientAppState;
import static net.i2p.app.ClientAppState.*;
import net.i2p.app.NotificationService;
import net.i2p.desktopgui.router.RouterManager;
import net.i2p.router.RouterContext;
import net.i2p.router.app.RouterApp;
@ -27,7 +29,7 @@ import net.i2p.util.I2PProperties.I2PPropertyCallback;
/**
* The main class of the application.
*/
public class Main implements RouterApp {
public class Main implements RouterApp, NotificationService {
// non-null
private final I2PAppContext _appContext;
@ -95,6 +97,11 @@ public class Main implements RouterApp {
}
public static void main(String[] args) {
// early check so we can bail out when started via CLI
if (!SystemTray.isSupported()) {
System.err.println("SystemTray not supported");
return;
}
Main main = new Main();
main.beginStartup(args);
}
@ -198,6 +205,46 @@ public class Main implements RouterApp {
t.start();
}
/////// NotificationService methods
/**
* Send a notification to the user.
*
* @param source unsupported
* @param category unsupported
* @param priority unsupported
* @param title for the popup, translated
* @param message translated
* @param path unsupported
* @return 0, or -1 on failure
*/
public int notify(String source, String category, int priority, String title, String message, String path) {
TrayManager tm = _trayManager;
if (tm == null)
return -1;
return tm.displayMessage(priority, title, message, path);
}
/**
* Cancel a notification if possible.
* Unsupported.
*
* @return false always
*/
public boolean cancel(int id) {
return false;
}
/**
* Update the text of a notification if possible.
* Unsupported.
*
* @return false always
*/
public boolean update(int id, String title, String message, String path) {
return false;
}
/////// ClientApp methods
/** @since 0.9.26 */

View File

@ -8,21 +8,27 @@ import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import java.net.URL;
import javax.swing.JFrame;
import javax.swing.JPopupMenu;
import javax.swing.SwingWorker;
import javax.swing.event.MenuKeyEvent;
import javax.swing.event.MenuKeyListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import net.i2p.I2PAppContext;
import net.i2p.apps.systray.UrlLauncher;
import net.i2p.desktopgui.i18n.DesktopguiTranslator;
import net.i2p.util.Log;
import net.i2p.util.SystemVersion;
/**
@ -37,11 +43,14 @@ abstract class TrayManager {
protected SystemTray tray;
///Our tray icon, or null if unsupported
protected TrayIcon trayIcon;
protected volatile boolean _showNotifications;
private static final String PNG_DIR = "/desktopgui/resources/images/";
private static final String MAC_ICON = "itoopie_black_24.png";
private static final String WIN_ICON = "itoopie_white_24.png";
private static final String WIN_ICON_LIGHT = "itoopie_white_24.png";
private static final String WIN_ICON_DARK = "itoopie_black_24.png";
private static final String LIN_ICON = "logo.png";
protected static final String PROP_NOTIFICATIONS = "desktopgui.showNotifications";
/**
* Instantiate tray manager.
@ -58,6 +67,7 @@ abstract class TrayManager {
public synchronized void startManager() throws AWTException {
if (!SystemTray.isSupported())
throw new AWTException("SystemTray not supported");
_showNotifications = _appContext.getBooleanPropertyDefaultTrue(PROP_NOTIFICATIONS);
tray = SystemTray.getSystemTray();
// Windows typically has tooltips; Linux (at least Ubuntu) doesn't
String tooltip = SystemVersion.isWindows() ? _t("I2P: Right-click for menu") : null;
@ -191,12 +201,20 @@ abstract class TrayManager {
*/
private Image getTrayImage() throws AWTException {
String img;
if (SystemVersion.isWindows())
img = WIN_ICON;
else if (SystemVersion.isMac())
if (SystemVersion.isWindows()) {
// too hard to get the theme out of the registry,
// use our console theme as a best guess
// so we have a contrasting icon
String theme = _appContext.getProperty("routerconsole.theme", "light");
if (theme.equals("dark"))
img = WIN_ICON_LIGHT;
else
img = WIN_ICON_DARK;
} else if (SystemVersion.isMac()) {
img = MAC_ICON;
else
} else {
img = LIN_ICON;
}
URL url = getClass().getResource(PNG_DIR + img);
if (url == null)
throw new AWTException("cannot load tray image " + img);
@ -204,6 +222,74 @@ abstract class TrayManager {
return image;
}
/**
* Send a notification to the user.
*
* @param title for the popup, translated
* @param message translated
* @param path unsupported
* @return 0, or -1 on failure
*/
public int displayMessage(int priority, String title, String message, String path) {
if (!_showNotifications)
return -1;
final TrayIcon ti = trayIcon;
if (ti == null)
return -1;
TrayIcon.MessageType type;
if (priority <= Log.DEBUG)
type = TrayIcon.MessageType.NONE;
else if (priority <= Log.INFO)
type = TrayIcon.MessageType.INFO;
else if (priority <= Log.WARN)
type = TrayIcon.MessageType.WARNING;
else
type = TrayIcon.MessageType.ERROR;
ti.displayMessage(title, message, type);
/*
* There's apparently no way to bind a particular message to an action
that comes back. We can't keep a queue because we don't get
an action back when the message is removed via timeout or user x-out.
On OSX, new messages dismiss previous ones.
On LXDE (and Gnome?), new messages go under previous ones. Timeout is only 10 seconds.
Message timeout is platform-dependent.
So the order of events is unknowable.
This only works if there is only one message ever.
if (path != null && path.length() > 0) {
if (path.charAt(0) == '/');
path = path.substring(1);
final String url = _appContext.portMapper().getConsoleURL() + path;
ti.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
ti.removeActionListener(this);
new SwingWorker<Object, Object>() {
@Override
protected Object doInBackground() throws Exception {
System.out.println("DIB " + arg0);
UrlLauncher launcher = new UrlLauncher(_appContext, null, null);
try {
launcher.openUrl(url);
System.out.println("DIB success " + url);
} catch (IOException e1) {
System.out.println("DIB fail " + url);
}
return null;
}
@Override
protected void done() {
System.out.println("done " + arg0);
}
}.execute();
}
});
}
*/
return 0;
}
protected String _t(String s) {
return DesktopguiTranslator._t(_appContext, s);
}

View File

@ -156,11 +156,11 @@ public class JSONRPC2Servlet extends HttpServlet {
} else {
out.println("<p>Current API password:<input name=\"password\" type=\"password\">");
}
out.println("<p>New API password (twice):<input name=\"password2\" type=\"password\">" +
"<input name=\"password3\" type=\"password\">" +
out.println("<p>New API password (twice): <input name=\"password2\" type=\"password\"> " +
"<input name=\"password3\" type=\"password\"> " +
"<input name=\"save\" type=\"submit\" value=\"Change API Password\">" +
"<p>If you forget the API password, stop i2pcontrol, delete the file <tt>" + _conf.getConfFile() +
"</tt>, and restart i2pcontrol.");
"<p>If you forget the API password, <a href=\"/configwebapps\">stop jsonrpc</a>, delete the file <tt>" + _conf.getConfFile() +
"</tt>, and <a href=\"/configwebapps\">restart jsonrpc</a>.");
out.println("</form>");
} else {
out.println("<p><a href=\"password\">Change API Password</a>");

View File

@ -96,7 +96,7 @@ public class RouterInfoHandler implements RequestHandler {
}
if (inParams.containsKey("i2p.router.status")) {
outParams.put("i2p.router.status", _context.throttle().getTunnelStatus());
outParams.put("i2p.router.status", _context.throttle().getLocalizedTunnelStatus());
}
if (inParams.containsKey("i2p.router.net.status")) {
@ -179,25 +179,44 @@ public class RouterInfoHandler implements RequestHandler {
int status = _context.commSystem().getStatus().getCode();
switch (status) {
case CommSystemFacade.STATUS_OK:
RouterAddress ra = _context.router().getRouterInfo().getTargetAddress("NTCP");
case CommSystemFacade.STATUS_OK:
case CommSystemFacade.STATUS_IPV4_OK_IPV6_UNKNOWN:
case CommSystemFacade.STATUS_IPV4_OK_IPV6_FIREWALLED:
case CommSystemFacade.STATUS_IPV4_FIREWALLED_IPV6_OK:
case CommSystemFacade.STATUS_IPV4_DISABLED_IPV6_OK:
RouterAddress ra = _context.router().getRouterInfo().getTargetAddress("NTCP2");
if (ra == null || TransportUtil.isPubliclyRoutable(ra.getIP(), true))
return NETWORK_STATUS.OK;
return NETWORK_STATUS.ERROR_PRIVATE_TCP_ADDRESS;
case CommSystemFacade.STATUS_DIFFERENT:
case CommSystemFacade.STATUS_DIFFERENT:
case CommSystemFacade.STATUS_IPV4_SNAT_IPV6_OK:
case CommSystemFacade.STATUS_IPV4_SNAT_IPV6_UNKNOWN:
return NETWORK_STATUS.ERROR_SYMMETRIC_NAT;
case CommSystemFacade.STATUS_REJECT_UNSOLICITED:
if (_context.router().getRouterInfo().getTargetAddress("NTCP") != null)
case CommSystemFacade.STATUS_REJECT_UNSOLICITED:
case CommSystemFacade.STATUS_IPV4_FIREWALLED_IPV6_UNKNOWN:
case CommSystemFacade.STATUS_IPV4_DISABLED_IPV6_FIREWALLED:
if (_context.router().getRouterInfo().getTargetAddress("NTCP2") != null)
return NETWORK_STATUS.WARN_FIREWALLED_WITH_INBOUND_TCP;
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;
return NETWORK_STATUS.FIREWALLED;
case CommSystemFacade.STATUS_HOSED:
case CommSystemFacade.STATUS_HOSED:
return NETWORK_STATUS.ERROR_UDP_PORT_IN_USE;
case CommSystemFacade.STATUS_UNKNOWN: // fallthrough
default:
case CommSystemFacade.STATUS_DISCONNECTED:
return NETWORK_STATUS.ERROR_NO_ACTIVE_PEERS_CHECK_CONNECTION_AND_FIREWALL;
case CommSystemFacade.STATUS_UNKNOWN: // fallthrough
case CommSystemFacade.STATUS_IPV4_UNKNOWN_IPV6_OK:
case CommSystemFacade.STATUS_IPV4_UNKNOWN_IPV6_FIREWALLED:
case CommSystemFacade.STATUS_IPV4_DISABLED_IPV6_UNKNOWN:
default:
ra = _context.router().getRouterInfo().getTargetAddress("SSU");
if (ra == null && _context.router().getUptime() > 5 * 60 * 1000) {
if (_context.commSystem().countActivePeers() <= 0)

View File

@ -2,3 +2,7 @@
# This is for app context configuration of standalone i2psnark.
# Almost all configuration settings are in i2psnark.config.d/i2psnark.config
#
# disable browser launch on startup
#routerconsole.browser=/bin/false
# change browser
#routerconsole.browser=firefox

View File

@ -197,9 +197,16 @@
</target>
<target name="standalone" depends="standalone_prep">
<!-- doesn't support file permissions
<zip destfile="i2psnark-standalone.zip">
<zipfileset dir="./dist/" prefix="i2psnark/" />
<zipfileset dir="./i2psnark/" />
</zip>
-->
<exec executable="zip" failifexecutionfails="true" failonerror="true" >
<arg value="-r" />
<arg value="i2psnark-standalone.zip" />
<arg value="i2psnark" />
</exec>
</target>
<!-- make a fat jar for standalone -->
@ -228,6 +235,7 @@
<zipfileset src="../../ministreaming/java/build/mstreaming.jar" />
<zipfileset src="../../streaming/java/build/streaming.jar" />
<zipfileset src="../../systray/java/build/systray.jar" />
<zipfileset src="../../../build/jbigi.jar" />
<!-- Countries translations. The i2psnark translations are in the war but it's easier to put these here -->
<!-- 300KB just to translate "Brazil", but why not... -->
<!--
@ -306,33 +314,34 @@
</target>
<target name="standalone_prep" depends="standalone_jar, standalone_war">
<delete dir="./dist" />
<mkdir dir="./dist" />
<copy file="../launch-i2psnark" todir="./dist/" />
<copy file="../launch-i2psnark.bat" todir="./dist/" />
<mkdir dir="./dist/contexts" />
<copy file="../standalone-context.xml" tofile="./dist/contexts/context.xml" />
<mkdir dir="./dist/docroot" />
<copy file="../standalone-index.html" tofile="./dist/docroot/index.html" />
<mkdir dir="./dist/webapps" />
<copy file="../i2psnark.war" tofile="./dist/webapps/i2psnark.war" />
<copy file="../jetty-i2psnark.xml" tofile="./dist/jetty-i2psnark.xml" />
<copy file="../i2psnark-appctx.config" tofile="./dist/i2psnark-appctx.config" />
<copy file="./build/i2psnark-standalone.jar" tofile="./dist/i2psnark.jar" />
<copy file="../readme-standalone.txt" tofile="./dist/readme.txt" />
<delete dir="./i2psnark" />
<mkdir dir="./i2psnark" />
<copy file="../launch-i2psnark" todir="./i2psnark/" />
<chmod type="file" file="./i2psnark/launch-i2psnark" perm="+x" />
<copy file="../launch-i2psnark.bat" todir="./i2psnark/" />
<mkdir dir="./i2psnark/contexts" />
<copy file="../standalone-context.xml" tofile="./i2psnark/contexts/context.xml" />
<mkdir dir="./i2psnark/docroot" />
<copy file="../standalone-index.html" tofile="./i2psnark/docroot/index.html" />
<mkdir dir="./i2psnark/webapps" />
<copy file="../i2psnark.war" tofile="./i2psnark/webapps/i2psnark.war" />
<copy file="../jetty-i2psnark.xml" tofile="./i2psnark/jetty-i2psnark.xml" />
<copy file="../i2psnark-appctx.config" tofile="./i2psnark/i2psnark-appctx.config" />
<copy file="./build/i2psnark-standalone.jar" tofile="./i2psnark/i2psnark.jar" />
<copy file="../readme-standalone.txt" tofile="./i2psnark/readme.txt" />
<!-- temp so announces work -->
<copy file="../../../installer/resources/hosts.txt" tofile="./dist/hosts.txt" />
<copy todir="./dist/licenses" >
<copy file="../../../installer/resources/hosts.txt" tofile="./i2psnark/hosts.txt" />
<copy todir="./i2psnark/licenses" >
<fileset dir="../../../licenses" includes="LICENSE-GPLv2.txt, ABOUT-Jetty.html" />
</copy>
<mkdir dir="./dist/logs" />
<mkdir dir="./i2psnark/logs" />
</target>
<target name="clean">
<delete dir="./build" />
<delete file="../i2psnark.war" />
<delete file="./i2psnark-standalone.zip" />
<delete dir="./dist" />
<delete dir="./i2psnark" />
</target>
<target name="cleandep" depends="clean">
</target>

View File

@ -23,6 +23,7 @@ import net.i2p.client.streaming.I2PServerSocket;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.client.streaming.I2PSocketEepGet;
import net.i2p.client.streaming.I2PSocketManager;
import net.i2p.client.streaming.I2PSocketManager.DisconnectListener;
import net.i2p.client.streaming.I2PSocketManagerFactory;
import net.i2p.client.streaming.I2PSocketOptions;
import net.i2p.data.Base32;
@ -47,7 +48,7 @@ import org.klomp.snark.dht.KRPC;
* so we can run multiple instances of single Snarks
* (but not multiple SnarkManagers, it is still static)
*/
public class I2PSnarkUtil {
public class I2PSnarkUtil implements DisconnectListener {
private final I2PAppContext _context;
private final Log _log;
private final String _baseName;
@ -75,6 +76,7 @@ public class I2PSnarkUtil {
private List<String> _openTrackers;
private DHT _dht;
private long _startedTime;
private final DisconnectListener _discon;
private static final int EEPGET_CONNECT_TIMEOUT = 45*1000;
private static final int EEPGET_CONNECT_TIMEOUT_SHORT = 5*1000;
@ -91,17 +93,18 @@ public class I2PSnarkUtil {
public I2PSnarkUtil(I2PAppContext ctx) {
this(ctx, "i2psnark");
this(ctx, "i2psnark", null);
}
/**
* @param baseName generally "i2psnark"
* @since Jetty 7
*/
public I2PSnarkUtil(I2PAppContext ctx, String baseName) {
public I2PSnarkUtil(I2PAppContext ctx, String baseName, DisconnectListener discon) {
_context = ctx;
_log = _context.logManager().getLog(Snark.class);
_baseName = baseName;
_discon = discon;
_opts = new HashMap<String, String>();
//setProxy("127.0.0.1", 4444);
setI2CPConfig("127.0.0.1", I2PClient.DEFAULT_LISTEN_PORT, null);
@ -324,8 +327,11 @@ public class I2PSnarkUtil {
if (opts.getProperty(I2PClient.PROP_GZIP) == null)
opts.setProperty(I2PClient.PROP_GZIP, "false");
_manager = I2PSocketManagerFactory.createManager(_i2cpHost, _i2cpPort, opts);
if (_manager != null)
if (_manager != null) {
_startedTime = _context.clock().now();
if (_discon != null)
_manager.addDisconnectListener(this);
}
_connecting = false;
}
if (_shouldUseDHT && _manager != null && _dht == null)
@ -333,6 +339,19 @@ public class I2PSnarkUtil {
return (_manager != null);
}
/**
* DisconnectListener interface
* @since 0.9.53
*/
public void sessionDisconnected() {
synchronized(this) {
_manager = null;
_connecting = false;
}
if (_discon != null)
_discon.sessionDisconnected();
}
/**
* @return null if disabled or not started
* @since 0.8.4

View File

@ -82,8 +82,9 @@ public class MetaInfo
* @param created_by may be null
* @param url_list may be null
* @param comment may be null
* @since public since 0.9.53, was package private
*/
MetaInfo(String announce, String name, String name_utf8, List<List<String>> files, List<Long> lengths,
public MetaInfo(String announce, String name, String name_utf8, List<List<String>> files, List<Long> lengths,
int piece_length, byte[] piece_hashes, long length, boolean privateTorrent,
List<List<String>> announce_list, String created_by, List<String> url_list, String comment)
{
@ -442,9 +443,12 @@ public class MetaInfo
}
/**
* Returns the piece hashes. Only used by storage so package local.
* Returns the piece hashes.
*
* @return not a copy, do not modify
* @since public since 0.9.53, was package private
*/
byte[] getPieceHashes()
public byte[] getPieceHashes()
{
return piece_hashes;
}

View File

@ -590,8 +590,12 @@ public class Snark
private void x_startTorrent() {
boolean ok = _util.connect();
if (!ok)
fatalRouter("Unable to connect to I2P", null);
if (!ok) {
if (_util.getContext().isRouterContext())
fatalRouter(_util.getString("Unable to connect to I2P"), null);
else
fatalRouter(_util.getString("Error connecting to I2P - check your I2CP settings!") + ' ' + _util.getI2CPHost() + ':' + _util.getI2CPPort(), null);
}
if (coordinator == null) {
I2PServerSocket serversocket = _util.getServerSocket();
if (serversocket == null)
@ -1255,7 +1259,7 @@ public class Snark
*/
private void fatalRouter(String s, Throwable t) throws RouterException {
_log.error(s, t);
stopTorrent();
stopTorrent(true);
if (completeListener != null)
completeListener.fatal(this, s);
throw new RouterException(s, t);
@ -1321,6 +1325,15 @@ public class Snark
}
}
/**
* Call after editing torrent.
* Caller must ensure infohash, files, etc. did not change.
*
* @since 0.9.53
*/
public void replaceMetaInfo(MetaInfo metainfo) {
meta = metainfo;
}
///////////// Begin StorageListener methods

View File

@ -29,7 +29,9 @@ import net.i2p.I2PAppContext;
import net.i2p.app.ClientApp;
import net.i2p.app.ClientAppManager;
import net.i2p.app.ClientAppState;
import net.i2p.app.NotificationService;
import net.i2p.client.I2PClient;
import net.i2p.client.streaming.I2PSocketManager.DisconnectListener;
import net.i2p.crypto.SHA1Hash;
import net.i2p.crypto.SigType;
import net.i2p.data.Base64;
@ -57,7 +59,7 @@ import org.klomp.snark.dht.KRPC;
/**
* Manage multiple snarks
*/
public class SnarkManager implements CompleteListener, ClientApp {
public class SnarkManager implements CompleteListener, ClientApp, DisconnectListener {
/**
* Map of (canonical) filename of the .torrent file to Snark instance.
@ -130,7 +132,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
public static final String PROP_FILES_PUBLIC = "i2psnark.filesPublic";
public static final String PROP_OLD_AUTO_START = "i2snark.autoStart"; // oops
public static final String PROP_AUTO_START = "i2psnark.autoStart"; // convert in migration to new config file
public static final String DEFAULT_AUTO_START = "false";
private final boolean DEFAULT_AUTO_START;
//public static final String PROP_LINK_PREFIX = "i2psnark.linkPrefix";
//public static final String DEFAULT_LINK_PREFIX = "file:///";
public static final String PROP_STARTUP_DELAY = "i2psnark.startupDelay";
@ -140,7 +142,8 @@ public class SnarkManager implements CompleteListener, ClientApp {
public static final String RC_PROP_UNIVERSAL_THEMING = "routerconsole.universal.theme";
public static final String PROP_THEME = "i2psnark.theme";
public static final String DEFAULT_THEME = "ubergine";
private static final String[] THEMES = new String[] { "dark", "light", "ubergine", "vanilla" };
// Translators: Translate "ubergine" as "aubergine" or "eggplant" or "purple"
private static final String[] THEMES = new String[] { _x("ubergine"), _x("dark"), _x("light"), _x("vanilla") };
/** From CSSHelper */
private static final String PROP_DISABLE_OLD = "routerconsole.disableOldThemes";
private static final boolean DEFAULT_DISABLE_OLD = true;
@ -267,7 +270,8 @@ public class SnarkManager implements CompleteListener, ClientApp {
_contextName = ctxName;
_log = _context.logManager().getLog(SnarkManager.class);
_messages = new UIMessages(MAX_MESSAGES);
_util = new I2PSnarkUtil(_context, ctxName);
_util = new I2PSnarkUtil(_context, ctxName, this);
DEFAULT_AUTO_START = !ctx.isRouterContext();
String cfile = ctxName + CONFIG_FILE_SUFFIX;
File configFile = new File(cfile);
if (!configFile.isAbsolute())
@ -342,6 +346,18 @@ public class SnarkManager implements CompleteListener, ClientApp {
}
}
/**
* DisconnectListener interface
* @since 0.9.53
*/
public void sessionDisconnected() {
if (!_context.isRouterContext()) {
addMessage(_t("Unable to connect to I2P"));
stopAllTorrents(true);
_stopping = false;
}
}
/*
* Called by the webapp at Jetty shutdown.
* Stops all torrents. Does not close the tunnel, so the announces have a chance.
@ -463,7 +479,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
}
public boolean shouldAutoStart() {
return Boolean.parseBoolean(_config.getProperty(PROP_AUTO_START, DEFAULT_AUTO_START));
return Boolean.parseBoolean(_config.getProperty(PROP_AUTO_START, Boolean.toString(DEFAULT_AUTO_START)));
}
/**
@ -814,7 +830,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
if (!_config.containsKey(PROP_DIR))
_config.setProperty(PROP_DIR, _contextName);
if (!_config.containsKey(PROP_AUTO_START))
_config.setProperty(PROP_AUTO_START, DEFAULT_AUTO_START);
_config.setProperty(PROP_AUTO_START, Boolean.toString(DEFAULT_AUTO_START));
if (!_config.containsKey(PROP_REFRESH_DELAY))
_config.setProperty(PROP_REFRESH_DELAY, Integer.toString(DEFAULT_REFRESH_DELAY_SECS));
if (!_config.containsKey(PROP_STARTUP_DELAY))
@ -847,7 +863,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
/**
* Get current theme.
* @return String -- the current theme
* @return String -- the current theme, untranslated
*/
public String getTheme() {
String theme;
@ -912,20 +928,29 @@ public class SnarkManager implements CompleteListener, ClientApp {
/**
* Get all themes
* @return String[] -- Array of all the themes found, non-null, unsorted
* @return Array of all the themes found, non-null, unsorted, untranslated. Not a copy, do not modify.
*/
public static String[] getThemes() {
return THEMES;
}
/** call from DirMonitor since loadConfig() is called before router I2CP is up */
private void getBWLimit() {
if (!_config.containsKey(PROP_UPBW_MAX)) {
/**
* Call from DirMonitor since loadConfig() is called before router I2CP is up.
* We also use this as a test that the router is there for standalone.
*
* @return true if we got a response from the router
*/
private boolean getBWLimit() {
boolean shouldSet = !_config.containsKey(PROP_UPBW_MAX);
if (shouldSet || !_context.isRouterContext()) {
int[] limits = BWLimits.getBWLimits(_util.getI2CPHost(), _util.getI2CPPort());
if (limits != null && limits[1] > 0)
if (limits == null)
return false;
if (shouldSet && limits[1] > 0)
_util.setMaxUpBW(limits[1]);
}
return true;
}
private void updateConfig() {
@ -1576,7 +1601,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
}
if (dataDir == null)
dataDir = getDataDir();
Snark torrent = null;
Snark torrent;
synchronized (_snarks) {
torrent = _snarks.get(filename);
}
@ -1696,7 +1721,10 @@ public class SnarkManager implements CompleteListener, ClientApp {
addMessage(_t("Connecting to I2P"));
boolean ok = _util.connect();
if (!ok) {
addMessage(_t("Error connecting to I2P - check your I2CP settings!"));
if (_context.isRouterContext())
addMessage(_t("Unable to connect to I2P"));
else
addMessage(_t("Error connecting to I2P - check your I2CP settings!") + ' ' + _util.getI2CPHost() + ':' + _util.getI2CPPort());
// this would rename the torrent to .BAD
//return false;
}
@ -2492,6 +2520,13 @@ public class SnarkManager implements CompleteListener, ClientApp {
addMessage(_t("Torrent removed: \"{0}\"", torrent.getBaseName()));
}
/**
* This calls monitorTorrents() once a minute.
* It also gets the bandwidth limits and loads magnets on first run.
* For standalone, it also handles checking that the external router is there,
* and restarting torrents once the router appears.
*
*/
private class DirMonitor implements Runnable {
public void run() {
// don't bother delaying if auto start is false
@ -2506,17 +2541,65 @@ public class SnarkManager implements CompleteListener, ClientApp {
// here because we need to delay until I2CP is up
// although the user will see the default until then
getBWLimit();
boolean routerOK = false;
boolean doMagnets = true;
while (_running) {
File dir = getDataDir();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Directory Monitor loop over " + dir.getAbsolutePath());
if (routerOK &&
(_context.isRouterContext() || _util.connected() || _util.isConnecting())) {
autostart = shouldAutoStart();
} else {
// Test if the router is there
// For standalone, this will probe the router every 60 seconds if not connected
boolean oldOK = routerOK;
routerOK = getBWLimit();
if (routerOK) {
autostart = shouldAutoStart();
if (autostart && !oldOK && !doMagnets && !_snarks.isEmpty()) {
// Start previously added torrents
for (Snark snark : _snarks.values()) {
Properties config = getConfig(snark);
String prop = config.getProperty(PROP_META_RUNNING);
if (prop == null || Boolean.parseBoolean(prop)) {
if (!_util.connected()) {
addMessage(_t("Connecting to I2P"));
// getBWLimit() was successful so this should work
boolean ok = _util.connect();
if (!ok) {
if (_context.isRouterContext())
addMessage(_t("Unable to connect to I2P"));
else
addMessage(_t("Error connecting to I2P - check your I2CP settings!") + ' ' + _util.getI2CPHost() + ':' + _util.getI2CPPort());
routerOK = false;
autostart = false;
break;
}
}
addMessageNoEscape(_t("Starting up torrent {0}", linkify(snark)));
try {
snark.startTorrent();
} catch (Snark.RouterException re) {
// Snark.fatal() will log and call fatal() here for user message before throwing
break;
} catch (RuntimeException re) {
// Snark.fatal() will log and call fatal() here for user message before throwing
}
}
}
if (routerOK)
addMessage(_t("Up bandwidth limit is {0} KBps", _util.getMaxUpBW()));
}
} else {
autostart = false;
}
}
boolean ok;
try {
// Don't let this interfere with .torrent files being added or deleted
synchronized (_snarks) {
ok = monitorTorrents(dir);
ok = monitorTorrents(dir, autostart);
}
} catch (RuntimeException e) {
_log.error("Error in the DirectoryMonitor", e);
@ -2530,7 +2613,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
} catch (RuntimeException e) {
_log.error("Error in the DirectoryMonitor", e);
}
if (!_snarks.isEmpty())
if (routerOK && !_snarks.isEmpty())
addMessage(_t("Up bandwidth limit is {0} KBps", _util.getMaxUpBW()));
// To fix bug where files were left behind,
// but also good for when user removes snarks when i2p is not running
@ -2539,6 +2622,12 @@ public class SnarkManager implements CompleteListener, ClientApp {
// time i2psnark starts. See ticket #1658.
if (ok)
cleanupTorrentStatus();
if (!routerOK) {
if (_context.isRouterContext())
addMessage(_t("Unable to connect to I2P"));
else
addMessage(_t("Error connecting to I2P - check your I2CP settings!") + ' ' + _util.getI2CPHost() + ':' + _util.getI2CPPort());
}
}
try { Thread.sleep(60*1000); } catch (InterruptedException ie) {}
}
@ -2555,8 +2644,18 @@ public class SnarkManager implements CompleteListener, ClientApp {
Storage storage = snark.getStorage();
if (meta == null || storage == null)
return;
if (snark.getDownloaded() > 0)
if (snark.getDownloaded() > 0) {
addMessageNoEscape(_t("Download finished: {0}", linkify(snark)));
ClientAppManager cmgr = _context.clientAppManager();
if (cmgr != null) {
NotificationService ns = (NotificationService) cmgr.getRegisteredApp("desktopgui");
if (ns != null) {
ns.notify("I2PSnark", null, Log.INFO, _t("I2PSnark"),
_t("Download finished: {0}", snark.getName()),
"/i2psnark/" + linkify(snark));
}
}
}
updateStatus(snark);
}
@ -2704,9 +2803,10 @@ public class SnarkManager implements CompleteListener, ClientApp {
/**
* caller must synchronize on _snarks
*
* @param shouldStart should we autostart the torrents
* @return success, false if an error adding any torrent.
*/
private boolean monitorTorrents(File dir) {
private boolean monitorTorrents(File dir, boolean shouldStart) {
boolean rv = true;
File files[] = dir.listFiles(new FileSuffixFilter(".torrent"));
List<String> foundNames = new ArrayList<String>(0);
@ -2726,7 +2826,6 @@ public class SnarkManager implements CompleteListener, ClientApp {
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("DirMon found: " + DataHelper.toString(foundNames) + " existing: " + DataHelper.toString(existingNames));
// lets find new ones first...
boolean shouldStart = shouldAutoStart();
for (String name : foundNames) {
if (existingNames.contains(name)) {
// already known. noop
@ -2791,6 +2890,14 @@ public class SnarkManager implements CompleteListener, ClientApp {
return _util.getString(s, o, o2);
}
/**
* mark for translation, does not translate
* @since 0.9.53
*/
private static String _x(String s) {
return s;
}
/**
* Unsorted map of name to Tracker object
* Modifiable, not a copy

View File

@ -0,0 +1,753 @@
package org.klomp.snark;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import net.i2p.I2PAppContext;
import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionException;
import net.i2p.client.I2PSessionMuxedListener;
import net.i2p.client.SendMessageOptions;
import net.i2p.client.datagram.I2PDatagramDissector;
import net.i2p.client.datagram.I2PDatagramMaker;
import net.i2p.client.datagram.I2PInvalidDatagramException;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
import net.i2p.util.Log;
import net.i2p.util.SimpleTimer2;
/**
* One of these for all trackers and info hashes.
* Ref: BEP 15, proposal 160
*
* The main difference from BEP 15 is that the announce response
* contains a 32-byte hash instead of a 4-byte IP and a 2-byte port.
*
* This implements only "fast mode".
* We send only repliable datagrams, and
* receive only raw datagrams, as follows:
*
*<pre>
* client tracker type
* ------ ------- ----
* announce --&gt; repliable
* &lt;-- ann resp raw
*</pre>
*
* @since 0.9.53, enabled in 0.9.54
*/
class UDPTrackerClient implements I2PSessionMuxedListener {
private final I2PAppContext _context;
private final Log _log;
/** hook to inject and receive datagrams */
private final I2PSession _session;
private final I2PSnarkUtil _util;
private final Hash _myHash;
/** unsigned dgrams */
private final int _rPort;
/** dest and port to tracker data */
private final ConcurrentHashMap<HostPort, Tracker> _trackers;
/** our TID to tracker */
private final Map<Integer, ReplyWaiter> _sentQueries;
private boolean _isRunning;
public static final int EVENT_NONE = 0;
public static final int EVENT_COMPLETED = 1;
public static final int EVENT_STARTED = 2;
public static final int EVENT_STOPPED = 3;
private static final int ACTION_CONNECT = 0;
private static final int ACTION_ANNOUNCE = 1;
private static final int ACTION_SCRAPE = 2;
private static final int ACTION_ERROR = 3;
private static final int SEND_CRYPTO_TAGS = 8;
private static final int LOW_CRYPTO_TAGS = 4;
private static final long DEFAULT_TIMEOUT = 15*1000;
private static final long DEFAULT_QUERY_TIMEOUT = 60*1000;
private static final long CLEAN_TIME = 163*1000;
/** in seconds */
private static final int DEFAULT_INTERVAL = 60*60;
private static final int MIN_INTERVAL = 15*60;
private static final int MAX_INTERVAL = 8*60*60;
private enum WaitState { INIT, SUCCESS, TIMEOUT, FAIL }
/**
*
*/
public UDPTrackerClient(I2PAppContext ctx, I2PSession session, I2PSnarkUtil util) {
_context = ctx;
_session = session;
_util = util;
_log = ctx.logManager().getLog(UDPTrackerClient.class);
_rPort = TrackerClient.PORT - 1;
_myHash = session.getMyDestination().calculateHash();
_trackers = new ConcurrentHashMap<HostPort, Tracker>(8);
_sentQueries = new ConcurrentHashMap<Integer, ReplyWaiter>(32);
}
/**
* Can't be restarted after stopping?
*/
public synchronized void start() {
if (_isRunning)
return;
_session.addMuxedSessionListener(this, I2PSession.PROTO_DATAGRAM_RAW, _rPort);
_isRunning = true;
}
/**
* Stop everything.
*/
public synchronized void stop() {
if (!_isRunning)
return;
_isRunning = false;
_session.removeListener(I2PSession.PROTO_DATAGRAM_RAW, _rPort);
_trackers.clear();
for (ReplyWaiter w : _sentQueries.values()) {
w.cancel();
}
_sentQueries.clear();
}
/**
* Announce and get peers for a torrent.
* Blocking!
* Caller should run in a thread.
*
* @param ih the Info Hash (torrent)
* @param max maximum number of peers to return
* @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
*/
public TrackerResponse announce(byte[] ih, byte[] peerID, int max, long maxWait,
String toHost, int toPort,
long downloaded, long left, long uploaded,
int event, boolean fast) {
long now = _context.clock().now();
long end = now + maxWait;
if (toPort < 0)
throw new IllegalArgumentException();
Tracker tr = getTracker(toHost, toPort);
if (tr.getDest(fast) == null) {
if (_log.shouldInfo())
_log.info("cannot resolve " + tr);
return null;
}
long toWait = end - now;
if (!fast)
toWait = toWait * 3 / 4;
if (toWait < 1000) {
if (_log.shouldInfo())
_log.info("out of time after resolving: " + tr);
return null;
}
if (fast) {
toWait = 0;
} else {
toWait = end - now;
if (toWait < 1000) {
if (_log.shouldInfo())
_log.info("out of time after getting conn: " + tr);
return null;
}
}
ReplyWaiter w = sendAnnounce(tr, 0, ih, peerID,
downloaded, left, uploaded, event, max, toWait);
if (fast)
return null;
if (w == null) {
if (_log.shouldInfo())
_log.info("initial announce failed: " + tr);
return null;
}
boolean success = waitAndRetransmit(w, end);
_sentQueries.remove(w.getID());
if (success)
return w.getReplyObject();
if (_log.shouldInfo())
_log.info("announce failed after retx: " + tr);
return null;
}
//////// private below here
/**
* @return non-null
*/
private Tracker getTracker(String host, int port) {
Tracker ndp = new Tracker(host, port);
Tracker odp = _trackers.putIfAbsent(ndp, ndp);
if (odp != null)
ndp = odp;
return ndp;
}
///// Sending.....
/**
* Send one time with a new tid
* @param toWait if <= 0 does not register
* @return null on failure or if toWait <= 0
*/
private ReplyWaiter sendAnnounce(Tracker tr, long connID,
byte[] ih, byte[] id,
long downloaded, long left, long uploaded,
int event, int numWant, long toWait) {
int tid = _context.random().nextInt();
byte[] payload = sendAnnounce(tr, tid, connID, ih, id, downloaded, left, uploaded, event, numWant);
if (payload != null) {
if (toWait > 0) {
ReplyWaiter rv = new ReplyWaiter(tid, tr, payload, toWait);
_sentQueries.put(Integer.valueOf(tid), rv);
if (_log.shouldInfo())
_log.info("Sent: " + rv + " timeout: " + toWait);
return rv;
}
if (_log.shouldInfo())
_log.info("Sent annc " + event + " to " + tr + " no wait");
}
return null;
}
/**
* Send one time with given tid
* @return the payload or null on failure
*/
private byte[] sendAnnounce(Tracker tr, int tid, long connID,
byte[] ih, byte[] id,
long downloaded, long left, long uploaded,
int event, int numWant) {
byte[] payload = new byte[98];
DataHelper.toLong8(payload, 0, connID);
DataHelper.toLong(payload, 8, 4, ACTION_ANNOUNCE);
DataHelper.toLong(payload, 12, 4, tid);
System.arraycopy(ih, 0, payload, 16, 20);
System.arraycopy(id, 0, payload, 36, 20);
DataHelper.toLong(payload, 56, 8, downloaded);
DataHelper.toLong(payload, 64, 8, left);
DataHelper.toLong(payload, 72, 8, uploaded);
DataHelper.toLong(payload, 80, 4, event);
DataHelper.toLong(payload, 92, 4, numWant);
DataHelper.toLong(payload, 96, 2, TrackerClient.PORT);
boolean rv = sendMessage(tr.getDest(true), tr.getPort(), payload, true);
return rv ? payload : null;
}
/**
* wait after initial send, resend if necessary
*/
private boolean waitAndRetransmit(ReplyWaiter w, long untilTime) {
synchronized(w) {
while(true) {
try {
long toWait = untilTime - _context.clock().now();
if (toWait <= 0)
return false;
w.wait(toWait);
} catch (InterruptedException ie) {
return false;
}
switch (w.getState()) {
case INIT:
continue;
case SUCCESS:
return true;
case FAIL:
return false;
case TIMEOUT:
if (_log.shouldInfo())
_log.info("Timeout: " + w);
long toWait = untilTime - _context.clock().now();
if (toWait <= 1000)
return false;
boolean ok = resend(w, Math.min(toWait, w.getSentTo().getTimeout()));
if (!ok)
return false;
continue;
}
}
}
}
/**
* Resend the stored payload
* @return success
*/
private boolean resend(ReplyWaiter w, long toWait) {
Tracker tr = w.getSentTo();
int port = tr.getPort();
if (_log.shouldInfo())
_log.info("Resending: " + w + " timeout: " + toWait);
boolean rv = sendMessage(tr.getDest(true), port, w.getPayload(), true);
if (rv) {
_sentQueries.put(Integer.valueOf(w.getID()), w);
w.schedule(toWait);
}
return rv;
}
/**
* Lowest-level send message call.
* @param dest may be null, returns false
* @param repliable true for conn request, false for announce
* @return success
*/
private boolean sendMessage(Destination dest, int toPort, byte[] payload, boolean repliable) {
if (!_isRunning) {
if (_log.shouldInfo())
_log.info("send failed, not running");
return false;
}
if (dest == null) {
if (_log.shouldInfo())
_log.info("send failed, no dest");
return false;
}
if (dest.calculateHash().equals(_myHash))
throw new IllegalArgumentException("don't send to ourselves");
if (repliable) {
I2PDatagramMaker dgMaker = new I2PDatagramMaker(_session);
payload = dgMaker.makeI2PDatagram(payload);
if (payload == null) {
if (_log.shouldWarn())
_log.warn("DGM fail");
return false;
}
}
SendMessageOptions opts = new SendMessageOptions();
opts.setDate(_context.clock().now() + 60*1000);
opts.setTagsToSend(SEND_CRYPTO_TAGS);
opts.setTagThreshold(LOW_CRYPTO_TAGS);
if (!repliable)
opts.setSendLeaseSet(false);
try {
boolean success = _session.sendMessage(dest, payload, 0, payload.length,
repliable ? I2PSession.PROTO_DATAGRAM : I2PSession.PROTO_DATAGRAM_RAW,
_rPort, toPort, opts);
if (success) {
// ...
} else {
if (_log.shouldWarn())
_log.warn("sendMessage fail");
}
return success;
} catch (I2PSessionException ise) {
if (_log.shouldWarn())
_log.warn("sendMessage fail", ise);
return false;
}
}
///// Reception.....
/**
* @param from dest or null if it didn't come in on signed port
*/
private void receiveMessage(Destination from, int fromPort, byte[] payload) {
if (payload.length < 8) {
if (_log.shouldInfo())
_log.info("Got short message: " + payload.length + " bytes");
return;
}
int action = (int) DataHelper.fromLong(payload, 0, 4);
int tid = (int) DataHelper.fromLong(payload, 4, 4);
ReplyWaiter waiter = _sentQueries.remove(Integer.valueOf(tid));
if (waiter == null) {
if (_log.shouldInfo())
_log.info("Rcvd msg with no one waiting: " + tid);
return;
}
if (action == ACTION_ANNOUNCE) {
receiveAnnounce(waiter, payload);
} else if (action == ACTION_ERROR) {
receiveError(waiter, payload);
} else {
// includes ACTION_CONNECT
if (_log.shouldInfo())
_log.info("Rcvd msg with unknown action: " + action + " for: " + waiter);
waiter.gotReply(false);
Tracker tr = waiter.getSentTo();
tr.gotError();
}
}
private void receiveAnnounce(ReplyWaiter waiter, byte[] payload) {
Tracker tr = waiter.getSentTo();
if (payload.length >= 22) {
int interval = Math.min(MAX_INTERVAL, Math.max(MIN_INTERVAL,
(int) DataHelper.fromLong(payload, 8, 4)));
int leeches = (int) DataHelper.fromLong(payload, 12, 4);
int seeds = (int) DataHelper.fromLong(payload, 16, 4);
int peers = (int) DataHelper.fromLong(payload, 20, 2);
if (22 + (peers * Hash.HASH_LENGTH) > payload.length) {
if (_log.shouldWarn())
_log.warn("Short reply");
waiter.gotReply(false);
tr.gotError();
return;
}
if (_log.shouldInfo())
_log.info("Rcvd " + peers + " peers from " + tr);
Set<Hash> hashes;
if (peers > 0) {
hashes = new HashSet<Hash>(peers);
for (int off = 20; off < payload.length; off += Hash.HASH_LENGTH) {
hashes.add(Hash.create(payload, off));
}
} else {
hashes = Collections.emptySet();
}
TrackerResponse resp = new TrackerResponse(interval, seeds, leeches, hashes);
waiter.gotResponse(resp);
tr.setInterval(interval);
} else {
waiter.gotReply(false);
tr.gotError();
}
}
private void receiveError(ReplyWaiter waiter, byte[] payload) {
String msg;
if (payload.length > 8) {
msg = DataHelper.getUTF8(payload, 8, payload.length - 8);
} else {
msg = "";
}
TrackerResponse resp = new TrackerResponse(msg);
waiter.gotResponse(resp);
Tracker tr = waiter.getSentTo();
tr.gotError();
}
// I2PSessionMuxedListener interface ----------------
/**
* Instruct the client that the given session has received a message
*
* Will be called only if you register via addMuxedSessionListener().
* Will be called only for the proto(s) and toPort(s) you register for.
*
* @param session session to notify
* @param msgId message number available
* @param size size of the message - why it's a long and not an int is a mystery
* @param proto 1-254 or 0 for unspecified
* @param fromPort 1-65535 or 0 for unspecified
* @param toPort 1-65535 or 0 for unspecified
*/
public void messageAvailable(I2PSession session, int msgId, long size, int proto, int fromPort, int toPort) {
// TODO throttle
try {
byte[] payload = session.receiveMessage(msgId);
if (payload == null)
return;
if (toPort == _rPort) {
// raw
receiveMessage(null, fromPort, payload);
} else {
if (_log.shouldWarn())
_log.warn("msg on bad port");
}
} catch (I2PSessionException e) {
if (_log.shouldWarn())
_log.warn("bad msg");
}
}
/** for non-muxed */
public void messageAvailable(I2PSession session, int msgId, long size) {}
public void reportAbuse(I2PSession session, int severity) {}
public void disconnected(I2PSession session) {
if (_log.shouldWarn())
_log.warn("UDPTC disconnected");
}
public void errorOccurred(I2PSession session, String message, Throwable error) {
if (_log.shouldWarn())
_log.warn("UDPTC got error msg: ", error);
}
public static class TrackerResponse {
private final int interval, complete, incomplete;
private final String error;
private final Set<Hash> peers;
/** success */
public TrackerResponse(int interval, int seeds, int leeches, Set<Hash> peers) {
this.interval = interval;
complete = seeds;
incomplete = leeches;
this.peers = peers;
error = null;
}
/** failure */
public TrackerResponse(String errorMsg) {
interval = DEFAULT_INTERVAL;
complete = 0;
incomplete = 0;
peers = null;
error = errorMsg;
}
public Set<Hash> getPeers() {
return peers;
}
public int getPeerCount() {
int pc = peers == null ? 0 : peers.size();
return Math.max(pc, complete + incomplete - 1);
}
public int getSeedCount() {
return complete;
}
public int getLeechCount() {
return incomplete;
}
public String getFailureReason() {
return error;
}
/** in seconds */
public int getInterval() {
return interval;
}
}
private static class HostPort {
protected final String host;
protected final int port;
/**
* @param port the announce port
*/
public HostPort(String host, int port) {
this.host = host;
this.port = port;
}
/**
* @return the announce port
*/
public int getPort() {
return port;
}
@Override
public int hashCode() {
return host.hashCode() ^ port;
}
@Override
public boolean equals(Object o) {
if (o == null || !(o instanceof HostPort))
return false;
HostPort dp = (HostPort) o;
return port == dp.port && host.equals(dp.host);
}
@Override
public String toString() {
return "UDP Tracker " + host + ':' + port;
}
}
private class Tracker extends HostPort {
private final Object destLock = new Object();
private Destination dest;
private long expires;
private long lastHeardFrom;
private long lastFailed;
private int consecFails;
private int interval = DEFAULT_INTERVAL;
private static final long DELAY = 15*1000;
public Tracker(String host, int port) {
super(host, port);
}
/**
* @param fast if true, do not lookup
* @return dest or null
*/
public Destination getDest(boolean fast) {
synchronized(destLock) {
if (dest == null && !fast)
dest = _util.getDestination(host);
return dest;
}
}
/** does not change state */
public synchronized void replyTimeout() {
consecFails++;
lastFailed = _context.clock().now();
}
public synchronized int getInterval() {
return interval;
}
/** sets heardFrom; calls notify */
public synchronized void setInterval(int interval) {
long now = _context.clock().now();
lastHeardFrom = now;
consecFails = 0;
this.interval = interval;
this.notifyAll();
}
/** sets heardFrom; calls notify */
public synchronized void gotError() {
long now = _context.clock().now();
lastHeardFrom = now;
consecFails = 0;
this.notifyAll();
}
/** doubled for each consecutive failure */
public synchronized long getTimeout() {
return DEFAULT_TIMEOUT << Math.min(consecFails, 3);
}
@Override
public String toString() {
return "UDP Tracker " + host + ':' + port + " hasDest? " + (dest != null);
}
}
/**
* Callback for replies
*/
private class ReplyWaiter extends SimpleTimer2.TimedEvent {
private final int tid;
private final Tracker sentTo;
private final byte[] data;
private TrackerResponse replyObject;
private WaitState state = WaitState.INIT;
/**
* Either wait on this object with a timeout, or use non-null Runnables.
* Any sent data to be remembered may be stored by setSentObject().
* Reply object may be in getReplyObject().
*/
public ReplyWaiter(int tid, Tracker tracker, byte[] payload, long toWait) {
super(SimpleTimer2.getInstance(), toWait);
this.tid = tid;
sentTo = tracker;
data = payload;
}
public int getID() {
return tid;
}
public Tracker getSentTo() {
return sentTo;
}
public byte[] getPayload() {
return data;
}
/**
* @return may be null depending on what happened. Cast to expected type.
*/
public synchronized TrackerResponse getReplyObject() {
return replyObject;
}
/**
* If true, we got a reply, and getReplyObject() may contain something.
*/
public synchronized WaitState getState() {
return state;
}
/**
* Will notify this.
* Also removes from _sentQueries and calls heardFrom().
* Sets state to SUCCESS or FAIL.
*/
public synchronized void gotReply(boolean success) {
cancel();
_sentQueries.remove(Integer.valueOf(tid));
setState(success ? WaitState.SUCCESS : WaitState.FAIL);
}
/**
* Will notify this and run onReply.
* Also removes from _sentQueries and calls heardFrom().
*/
private synchronized void setState(WaitState state) {
this.state = state;
this.notifyAll();
}
/**
* Will notify this.
* Also removes from _sentQueries and calls heardFrom().
* Sets state to SUCCESS.
*/
public synchronized void gotResponse(TrackerResponse resp) {
replyObject = resp;
gotReply(true);
}
/**
* Sets state to INIT.
*/
@Override
public synchronized void schedule(long toWait) {
state = WaitState.INIT;
super.schedule(toWait);
}
/** timer callback on timeout */
public synchronized void timeReached() {
// don't trump success or failure
if (state != WaitState.INIT)
return;
//if (action == ACTION_CONNECT)
// sentTo.connFailed();
//else
sentTo.replyTimeout();
setState(WaitState.TIMEOUT);
if (_log.shouldWarn())
_log.warn("timeout waiting for reply from " + sentTo);
}
@Override
public String toString() {
return "Waiting for ID: " + tid + " to: " + sentTo + " state: " + state;
}
}
}

View File

@ -32,14 +32,15 @@ public class ConfigUIHelper {
{ "cs", "cz", "Čeština", null },
{ "zh", "cn", "Chinese 中文", null },
//{ "zh_TW", "tw", "Chinese 中文", "Taiwan" },
//{ "da", "dk", "Dansk", null },
{ "da", "dk", "Dansk", null },
{ "de", "de", "Deutsch", null },
//{ "et", "ee", "Eesti", null },
{ "en", "us", "English", null },
{ "es", "es", "Español", null },
{ "fa", "ir", "Persian فارسی", null },
{ "fr", "fr", "Français", null },
//{ "gl", "lang_gl", "Galego", null },
//{ "el", "gr", "Greek Ελληνικά", null },
{ "el", "gr", "Greek Ελληνικά", null },
{ "in", "id", "bahasa Indonesia", null },
{ "it", "it", "Italiano", null },
{ "ja", "jp", "Japanese 日本語", null },

View File

@ -4,9 +4,12 @@ import java.io.File;
import java.io.IOException;
import java.util.Properties;
import org.eclipse.jetty.util.log.Log;
import net.i2p.I2PAppContext;
import net.i2p.apps.systray.UrlLauncher;
import net.i2p.data.DataHelper;
import net.i2p.jetty.I2PLogger;
import net.i2p.jetty.JettyStart;
/**
@ -29,6 +32,13 @@ public class RunStandalone {
} catch (IOException ioe) {}
}
_context = new I2PAppContext(p);
// Do this after we have a context
// To take effect, must be set before any Jetty classes are loaded
try {
Log.setLog(new I2PLogger(_context));
} catch (Throwable t) {
System.err.println("INFO: I2P Jetty logging class not found, logging to stdout");
}
File base = _context.getBaseDir();
File xml = new File(base, "jetty-i2psnark.xml");
_jettyStart = new JettyStart(_context, null, new String[] { xml.getAbsolutePath() } );

View File

@ -3,12 +3,14 @@ package org.klomp.snark.web;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.Collator;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
@ -22,6 +24,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
@ -35,8 +38,10 @@ import net.i2p.data.Base64;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.servlet.util.ServletUtil;
import net.i2p.util.FileUtil;
import net.i2p.util.Log;
import net.i2p.util.SecureFile;
import net.i2p.util.SecureFileOutputStream;
import net.i2p.util.SystemVersion;
import net.i2p.util.Translate;
import net.i2p.util.UIMessages;
@ -251,11 +256,12 @@ public class I2PSnarkServlet extends BasicServlet {
}
} else {
String base = addPaths(req.getRequestURI(), "/");
boolean showEdit = req.getParameter("showEdit") != null;
String listing = getListHTML(resource, base, true, method.equals("POST") ? req.getParameterMap() : null,
req.getParameter("sort"));
req.getParameter("sort"), showEdit);
if (method.equals("POST")) {
// P-R-G
sendRedirect(req, resp, "");
sendRedirect(req, resp, showEdit ? "?showEdit" : "");
} else if (listing != null) {
setHTMLHeaders(resp, cspNonce, true);
resp.getWriter().write(listing);
@ -343,25 +349,24 @@ public class I2PSnarkServlet extends BasicServlet {
out.write("</head>\n" +
"<body>" +
"<center>");
List<Tracker> sortedTrackers = null;
if (isConfigure) {
out.write("<div class=\"snarknavbar\"><a href=\"" + _contextPath + "/\" title=\"");
out.write(_t("Torrents"));
out.write("\" class=\"snarkNav nav_main\">");
if (_contextName.equals(DEFAULT_NAME))
out.write(_t("I2PSnark"));
else
out.write(_contextName);
out.write("</a>");
} else {
out.write("<div class=\"snarknavbar\"><a href=\"" + _contextPath + '/' + peerString + "\" title=\"");
out.write(_t("Refresh page"));
out.write("\" class=\"snarkNav nav_main\">");
if (_contextName.equals(DEFAULT_NAME))
out.write(_t("I2PSnark"));
else
out.write(_contextName);
out.write("</a>\n");
}
out.write("\" class=\"snarkNav nav_main\">");
if (_contextName.equals(DEFAULT_NAME))
out.write(_t("I2PSnark"));
else
out.write(_contextName);
if (!_context.isRouterContext()) {
out.write(' ' + CoreVersion.VERSION);
}
out.write("</a>");
List<Tracker> sortedTrackers = null;
if (!isConfigure) {
sortedTrackers = _manager.getSortedTrackers();
if (_context.isRouterContext() && _manager.hasModifiedTrackers()) {
for (Tracker t : sortedTrackers) {
@ -2511,12 +2516,18 @@ public class I2PSnarkServlet extends BasicServlet {
out.write("<select name='theme'>");
String theme = _manager.getTheme();
String[] themes = _manager.getThemes();
Arrays.sort(themes);
// translated sort
Map<String, String> tmap = new TreeMap<String, String>(Collator.getInstance());
for (int i = 0; i < themes.length; i++) {
if(themes[i].equals(theme))
out.write("\n<OPTION value=\"" + themes[i] + "\" SELECTED>" + themes[i]);
tmap.put(_t(themes[i]), themes[i]);
}
for (Map.Entry<String, String> e : tmap.entrySet()) {
String tr = e.getKey();
String opt = e.getValue();
if(opt.equals(theme))
out.write("\n<option value=\"" + opt + "\" SELECTED>" + tr + "</option>");
else
out.write("\n<OPTION value=\"" + themes[i] + "\">" + themes[i]);
out.write("\n<option value=\"" + opt + "\">" + tr + "</option>");
}
out.write("</select>\n");
}
@ -2984,8 +2995,8 @@ public class I2PSnarkServlet extends BasicServlet {
* @return String of HTML or null if postParams != null
* @since 0.7.14
*/
private String getListHTML(File xxxr, String base, boolean parent, Map<String, String[]> postParams, String sortParam)
throws IOException
private String getListHTML(File xxxr, String base, boolean parent, Map<String, String[]> postParams,
String sortParam, boolean showEdit) throws IOException
{
String decodedBase = decodePath(base);
String title = decodedBase;
@ -3027,6 +3038,10 @@ public class I2PSnarkServlet extends BasicServlet {
_manager.startTorrent(snark);
} else if (postParams.get("recheck") != null) {
_manager.recheckTorrent(snark);
} else if (postParams.get("editTorrent") != null) {
saveTorrentEdit(snark, postParams);
} else if (postParams.get("showEdit") != null) {
// P-R-G only
} else {
_manager.addMessage("Unknown command");
}
@ -3055,7 +3070,7 @@ public class I2PSnarkServlet extends BasicServlet {
r = new File("");
}
boolean showStopStart = snark != null;
boolean showStopStart = snark != null && !showEdit;
Storage storage = snark != null ? snark.getStorage() : null;
boolean showPriority = storage != null && !storage.complete() &&
r.isDirectory();
@ -3093,7 +3108,7 @@ public class I2PSnarkServlet extends BasicServlet {
final boolean includeForm = showStopStart || showPriority || er || ec;
if (includeForm) {
buf.append("<form action=\"").append(base).append("\" method=\"POST\">\n" +
"<input type=\"hidden\" name=\"nonce\" value=\"").append(_nonce).append("\" >\n");
"<input type=\"hidden\" name=\"nonce\" value=\"").append(_nonce).append("\">\n");
if (sortParam != null) {
buf.append("<input type=\"hidden\" name=\"sort\" value=\"")
.append(DataHelper.stripHTML(sortParam)).append("\" >\n");
@ -3103,7 +3118,7 @@ public class I2PSnarkServlet extends BasicServlet {
// first table - torrent info
buf.append("<table class=\"snarkTorrentInfo\">\n" +
"<tr><th></th><th><b>")
.append(_t("Torrent"))
.append(showEdit ? _t("Edit Torrent") : _t("Torrent"))
.append("</b></th><th>")
.append(DataHelper.escapeHTML(snark.getBaseName()))
.append("</th></tr>\n");
@ -3117,7 +3132,7 @@ public class I2PSnarkServlet extends BasicServlet {
.append("</b></td><td><a href=\"").append(_contextPath).append('/').append(baseName).append("\">")
.append(DataHelper.escapeHTML(fullPath))
.append("</a></td></tr>\n");
if (storage != null) {
if (storage != null && !showEdit) {
buf.append("<tr><td>");
toThemeImg(buf, "file");
buf.append("</td><td><b>")
@ -3127,17 +3142,19 @@ public class I2PSnarkServlet extends BasicServlet {
.append("</td></tr>\n");
}
String hex = I2PSnarkUtil.toHex(snark.getInfoHash());
buf.append("<tr><td>");
toThemeImg(buf, "details");
buf.append("</td><td><b>")
.append(_t("Info hash"))
.append("</b></td><td><span id=\"infohash\">")
.append(hex.toUpperCase(Locale.US))
.append("</span></td></tr>\n");
if (!showEdit) {
buf.append("<tr><td>");
toThemeImg(buf, "details");
buf.append("</td><td><b>")
.append(_t("Info hash"))
.append("</b></td><td><span id=\"infohash\">")
.append(hex.toUpperCase(Locale.US))
.append("</span></td></tr>\n");
}
String announce = null;
MetaInfo meta = snark.getMetaInfo();
if (meta != null) {
if (meta != null && !showEdit) {
announce = meta.getAnnounce();
if (announce == null)
announce = snark.getTrackerURL();
@ -3218,7 +3235,7 @@ public class I2PSnarkServlet extends BasicServlet {
toThemeImg(buf, "details");
buf.append("</td><td><b>")
.append(_t("Comment")).append("</b></td><td>")
.append(DataHelper.stripHTML(com))
.append(DataHelper.escapeHTML(com).replace("\r\n", "<br>").replace("\n", "<br>"))
.append("</td></tr>\n");
}
long dat = meta.getCreationDate();
@ -3239,7 +3256,7 @@ public class I2PSnarkServlet extends BasicServlet {
toThemeImg(buf, "details");
buf.append("</td><td><b>")
.append(_t("Created By")).append("</b></td><td>")
.append(DataHelper.stripHTML(cby))
.append(DataHelper.escapeHTML(cby))
.append("</td></tr>\n");
}
long[] dates = _manager.getSavedAddedAndCompleted(snark);
@ -3275,6 +3292,7 @@ public class I2PSnarkServlet extends BasicServlet {
}
}
if (!showEdit) { // don't bother to reindent
if (meta == null || !meta.isPrivate()) {
buf.append("<tr><td><a href=\"")
.append(MagnetURI.MAGNET_FULL).append(hex);
@ -3377,6 +3395,7 @@ public class I2PSnarkServlet extends BasicServlet {
.append(":</b> ")
.append(formatSize(snark.getPieceLength(0)))
.append("</span></td></tr>\n");
} // !showEdit
// buttons
if (showStopStart) {
@ -3390,7 +3409,7 @@ public class I2PSnarkServlet extends BasicServlet {
buf.append("<b>").append(_t("Starting")).append("&hellip;</b>");
} else if (snark.isAllocating()) {
buf.append("<b>").append(_t("Allocating")).append("&hellip;</b>");
} else {
} else if (isTopLevel && !showEdit) {
boolean isRunning = !snark.isStopped();
buf.append("<input type=\"submit\" value=\"");
if (isRunning)
@ -3398,14 +3417,23 @@ public class I2PSnarkServlet extends BasicServlet {
else
buf.append(_t("Start")).append("\" name=\"start\" class=\"starttorrent\">\n");
buf.append("<input type=\"submit\" name=\"recheck\" value=\"").append(_t("Force Recheck"));
if (isRunning)
if (isRunning) {
buf.append("\" class=\"disabled\" disabled=\"disabled\" title=\"")
.append(_t("Stop the torrent in order to check file integrity"))
.append("\">\n");
else
.append(_t("Torrent must be stopped"));
} else {
buf.append("\" class=\"reload\" title=\"")
.append(_t("Check integrity of the downloaded files"))
.append("\">\n");
.append(_t("Check integrity of the downloaded files"));
}
buf.append("\">\n" +
"<input type=\"submit\" name=\"showEdit\" value=\"").append(_t("Edit Torrent"));
if (isRunning) {
buf.append("\" class=\"disabled\" disabled=\"disabled\" title=\"")
.append(_t("Torrent must be stopped"));
} else {
buf.append("\" class=\"reload\" title=\"")
.append(_t("Add or remove trackers"));
}
buf.append("\">\n");
}
boolean showInOrder = storage != null && !storage.complete() &&
meta != null;
@ -3439,6 +3467,13 @@ public class I2PSnarkServlet extends BasicServlet {
}
buf.append("</table>\n");
if (snark != null && isTopLevel && showEdit) {
// Edit torrent. Show edit section only.
displayTorrentEdit(snark, base, buf);
buf.append("</form></div></div></center></body></html>");
return buf.toString();
}
if (snark != null && !r.exists()) {
// fixup TODO
buf.append("<table class=\"resourceError\" id=\"DoesNotExist\"><tr><th colspan=\"2\">")
@ -3481,7 +3516,7 @@ public class I2PSnarkServlet extends BasicServlet {
displayComments(snark, er, ec, esc, buf);
if (includeForm)
buf.append("</form>");
buf.append("</div></div></body></html>");
buf.append("</div></div></center></body></html>");
return buf.toString();
}
@ -3778,7 +3813,7 @@ public class I2PSnarkServlet extends BasicServlet {
// for stop/start/check
if (includeForm)
buf.append("</form>");
buf.append("</div></div></body></html>");
buf.append("</div></div></center></body></html>");
return buf.toString();
}
@ -4150,6 +4185,136 @@ public class I2PSnarkServlet extends BasicServlet {
buf.append("</div>");
}
/**
* @param snark non-null
* @since 0.9.53
*/
private void displayTorrentEdit(Snark snark, String base, StringBuilder buf) {
MetaInfo meta = snark.getMetaInfo();
if (meta == null)
return;
buf.append("<div id=\"snarkCommentSection\"><table class=\"snarkTorrentInfo\">\n");
//.append("<tr><th colspan=\"5\">")
//.append(_t("Edit Torrent"))
//.append("</th>")
//.append("</tr>");
boolean isRunning = !snark.isStopped();
if (isRunning) {
// shouldn't happen
buf.append("<tr><td colspan=\"5\">")
.append(_t("Torrent must be stopped"))
.append("</td></tr></table></div></form>");
return;
}
String announce = meta.getAnnounce();
if (announce == null)
announce = snark.getTrackerURL();
if (announce != null) {
// strip non-i2p trackers
if (!isI2PTracker(announce))
announce = null;
}
List<List<String>> alist = meta.getAnnounceList();
Set<String> annlist = new TreeSet<String>();
if (alist != null && !alist.isEmpty()) {
// strip non-i2p trackers
for (List<String> alist2 : alist) {
for (String s : alist2) {
if (isI2PTracker(s))
annlist.add(s);
}
}
}
if (announce != null)
annlist.add(announce);
if (!annlist.isEmpty()) {
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>");
toThemeImg(buf, "details");
buf.append("</td><td><b>")
.append(_t("Tracker")).append("</b></td><td>");
s = DataHelper.stripHTML(s);
buf.append("<span class=\"info_tracker\">");
buf.append(getShortTrackerLink(s, snark.getInfoHash()));
buf.append("</span> ");
//buf.append(s);
buf.append("</td><td>");
buf.append("<input type=\"radio\" class=\"optbox\" name=\"primary\" ");
if (s.equals(announce))
buf.append("checked=\"checked\" ");
buf.append("value=\"").append(hc);
buf.append("\"></td><td>");
buf.append("<input type=\"checkbox\" class=\"optbox\" name=\"trdelete.")
.append(hc).append("\" title=\"").append(_t("Mark for deletion")).append("\">");
buf.append("</td></tr>\n");
}
}
List<Tracker> newTrackers = _manager.getSortedTrackers();
for (Iterator<Tracker> iter = newTrackers.iterator(); iter.hasNext(); ) {
Tracker t = iter.next();
String announceURL = t.announceURL.replace("&#61;", "=");
if (announceURL.equals(announce) || annlist.contains(announceURL))
iter.remove();
}
if (!newTrackers.isEmpty()) {
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();
String announceURL = t.announceURL.replace("&#61;", "=");
buf.append("<tr><td>");
toThemeImg(buf, "details");
buf.append("</td><td><b>")
.append(_t("Add Tracker")).append("</b></td><td>");
buf.append(name);
buf.append("</td><td><input type=\"radio\" class=\"optbox\" name=\"primary\" value=\"");
buf.append(hc);
buf.append("\"></td><td>");
buf.append("<input type=\"checkbox\" class=\"optbox\" id=\"").append(name).append("\" name=\"tradd.")
.append(hc).append("\" title=\"").append(_t("Add tracker")).append("\"> ")
.append("</td><td></td></tr>\n");
}
}
String com = meta.getComment();
if (com == null) {
com = "";
} else if (com.length() > 0) {
com = DataHelper.escapeHTML(com);
}
buf.append("<tr><td>");
toThemeImg(buf, "details");
buf.append("</td><td><b>")
.append(_t("Comment")).append("</b></td>");
buf.append("<td colspan=\"2\" id=\"addCommentText\"><textarea name=\"nofilter_newTorrentComment\" cols=\"88\" rows=\"4\">")
.append(com).append("</textarea></td><td></td>");
buf.append("</tr>\n");
String cb = meta.getCreatedBy();
if (cb == null) {
cb = "";
} else if (cb.length() > 0) {
cb = DataHelper.escapeHTML(cb);
}
buf.append("<tr><td>");
toThemeImg(buf, "details");
buf.append("</td><td><b>")
.append(_t("Created By")).append("</b></td>");
buf.append("<td id=\"editTorrentCreatedBy\"><input type=\"text\" name=\"nofilter_newTorrentCreatedBy\" cols=\"44\" rows=\"1\" value=\"")
.append(cb).append("\"></td></tr>");
buf.append("<tr id=\"torrentInfoControl\"><td colspan=\"5\">");
buf.append("<input type=\"submit\" name=\"editTorrent\" value=\"");
buf.append(_t("Save Changes"));
buf.append("\" class=\"accept\"></td></tr>\n");
buf.append("</table></div>");
}
/**
* @param so null ok
* @return query string or ""
@ -4370,6 +4535,147 @@ public class I2PSnarkServlet extends BasicServlet {
_manager.setSavedCommentsEnabled(snark, yes);
}
/**
* @since 0.9.53
*/
private void saveTorrentEdit(Snark snark, Map<String, String[]> postParams) {
if (!snark.isStopped()) {
// shouldn't happen
_manager.addMessage(_t("Torrent must be stopped"));
return;
}
List<Integer> toAdd = new ArrayList<Integer>();
List<Integer> toDel = new ArrayList<Integer>();
Integer primary = null;
String newComment = "";
String newCreatedBy = "";
for (Map.Entry<String, String[]> entry : postParams.entrySet()) {
String key = entry.getKey();
String val = entry.getValue()[0]; // jetty arrays
if (key.startsWith("tradd.")) {
try {
toAdd.add(Integer.parseInt(key.substring(6)));
} catch (NumberFormatException nfe) {}
} else if (key.startsWith("trdelete.")) {
try {
toDel.add(Integer.parseInt(key.substring(9)));
} catch (NumberFormatException nfe) {}
} else if (key.equals("primary")) {
try {
primary = Integer.parseInt(val);
} catch (NumberFormatException nfe) {}
} else if (key.equals("nofilter_newTorrentComment")) {
newComment = val.trim();
} else if (key.equals("nofilter_newTorrentCreatedBy")) {
newCreatedBy = val.trim();
}
}
MetaInfo meta = snark.getMetaInfo();
if (meta == null) {
// shouldn't happen
_manager.addMessage("Can't edit magnet");
return;
}
String oldPrimary = meta.getAnnounce();
String oldComment = meta.getComment();
if (oldComment == null)
oldComment = "";
String oldCreatedBy = meta.getCreatedBy();
if (oldCreatedBy == null)
oldCreatedBy = "";
if (toAdd.isEmpty() && toDel.isEmpty() &&
(primary == null || primary.equals(oldPrimary)) &&
oldComment.equals(newComment) &&
oldCreatedBy.equals(newCreatedBy)) {
_manager.addMessage("No changes to torrent, not saved");
return;
}
List<List<String>> alist = meta.getAnnounceList();
Set<String> annlist = new TreeSet<String>();
if (alist != null && !alist.isEmpty()) {
// strip non-i2p trackers
for (List<String> alist2 : alist) {
for (String s : alist2) {
if (isI2PTracker(s))
annlist.add(s);
}
}
}
if (oldPrimary != null)
annlist.add(oldPrimary);
List<Tracker> newTrackers = _manager.getSortedTrackers();
for (Integer i : toDel) {
int hc = i.intValue();
for (Iterator<String> iter = annlist.iterator(); iter.hasNext(); ) {
String s = iter.next();
if (s.hashCode() == hc)
iter.remove();
}
}
for (Integer i : toAdd) {
int hc = i.intValue();
for (Tracker t : newTrackers) {
if (t.announceURL.hashCode() == hc) {
annlist.add(t.announceURL);
break;
}
}
}
String thePrimary = oldPrimary;
if (primary != null) {
int hc = primary.intValue();
for (String s : annlist) {
if (s.hashCode() == hc) {
thePrimary = s;
break;
}
}
}
List<List<String>> newAnnList;
if (annlist.isEmpty()) {
newAnnList = null;
thePrimary = null;
} else {
List<String> aalist = new ArrayList<String>(annlist);
newAnnList = Collections.singletonList(aalist);
if (!aalist.contains(thePrimary))
thePrimary = aalist.get(0);
}
if (newComment.equals(""))
newComment = null;
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.isPrivate(),
newAnnList, newCreatedBy, meta.getWebSeedURLs(), newComment);
if (!DataHelper.eq(meta.getInfoHash(), newMeta.getInfoHash())) {
// shouldn't happen
_manager.addMessage("Torrent edit failed, infohash mismatch");
return;
}
File f = new File(_manager.util().getTempDir(), "edit-" + _manager.util().getContext().random().nextLong() + ".torrent");
OutputStream out = null;
try {
out = new SecureFileOutputStream(f);
out.write(newMeta.getTorrentData());
out.close();
boolean ok = FileUtil.rename(f, new File(snark.getName()));
if (!ok) {
_manager.addMessage("Save edit changes failed");
return;
}
} catch (IOException ioe) {
try { if (out != null) out.close(); } catch (IOException ioe2) {}
_manager.addMessage("Save edit changes failed: " + ioe);
return;
} finally {
f.delete();
}
snark.replaceMetaInfo(newMeta);
_manager.addMessage("Torrent changes saved");
}
/** @since 0.9.32 */
private static boolean noCollapsePanels(HttpServletRequest req) {
// check for user agents that can't toggle the collapsible panels...

View File

@ -4,5 +4,33 @@
# The file jetty-i2psnark.xml must be present in the current directory.
# i2psnark will be accessed at http://127.0.0.1:8002/
#
# Raise the soft open files soft ulimit to this value, if able
OPEN_FILES_ULIMIT=2048
raiseopenfilesulimit() {
OPEN_FILES_SOFT=`ulimit -S -n` 2> /dev/null || return
if [ "$OPEN_FILES_SOFT" != "unlimited" ]
then
if [ "$OPEN_FILES_ULIMIT" -gt "$OPEN_FILES_SOFT" ]
then
OPEN_FILES_HARD=`ulimit -H -n` 2> /dev/null || return
if [ "$OPEN_FILES_HARD" != "unlimited" ]
then
if [ "$OPEN_FILES_ULIMIT" -gt "$OPEN_FILES_HARD" ]
then
OPEN_FILES_ULIMIT="$OPEN_FILES_HARD"
fi
fi
if [ "$OPEN_FILES_ULIMIT" -gt "$OPEN_FILES_SOFT" ]
then
ulimit -S -n "$OPEN_FILES_ULIMIT" > /dev/null 2>&1
fi
fi
fi
}
raiseopenfilesulimit
I2P="."
java -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

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

View File

@ -2,6 +2,7 @@
3gpp = video/3gpp
7z = application/x-7z-compressed
ape = audio/x-monkeys-audio
avif = image/avif
bz2 = application/x-bzip2
cue = application/x-cue
dff = audio/x-dsd

View File

@ -4,6 +4,10 @@ java -jar i2psnark.jar
I2PSnark web ui will be at http://127.0.0.1:8002/i2psnark/
To change or disable browser launch at startup, edit i2psnark-appctx.config.
To change the port, edit jetty-i2psnark.xml.
I2PSnark is GPL'ed software, based on Snark (http://www.klomp.org/) to run on top of I2P
(https://geti2p.net/) within a webserver (such as the bundled Jetty from
https://www.eclipse.org/jetty/). For more information about I2PSnark, get in touch
@ -19,7 +23,7 @@ To add RPC support:
to the webapps/ directory in your standalone install.
2b) If you do not have the i2psnark-rpc plugin installed, get the i2p.plugins.i2psnark-rpc
branch out of monotone, build with 'ant war', and copy the file src/build/transmission.war.jar
branch out of git, build with 'ant war', and copy the file src/build/transmission.war.jar
to the file webapps/transmission.war in your standalone install.
3) Start i2psnark standalone as usual. The transmission web interface will be at

View File

@ -354,8 +354,9 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
/**
* @return A copy, unmodifiable, non-null
* @since public since 0.9.53 for advanced plugin usage, was package private
*/
List<I2PSession> getSessions() {
public List<I2PSession> getSessions() {
if (_sessions.isEmpty())
return Collections.emptyList();
return new ArrayList<I2PSession>(_sessions);

View File

@ -148,6 +148,9 @@ public class TunnelController implements Logging {
private static final String OPT_ENCTYPE = PFX_OPTION + "i2cp.leaseSetEncType";
/** @since 0.9.53 */
private static final String OPT_PRIORITY = PFX_OPTION + "outbound.priority";
/** all of these @since 0.9.14 */
public static final String TYPE_CONNECT = "connectclient";
public static final String TYPE_HTTP_BIDIR_SERVER = "httpbidirserver";
@ -231,6 +234,15 @@ public class TunnelController implements Logging {
_state = keyOK && getStartOnLoad() ? TunnelState.START_ON_LOAD : TunnelState.STOPPED;
}
/**
* The I2PTunnel
*
* @since 0.9.53 for advanced plugin usage
*/
public I2PTunnel getTunnel() {
return _tunnel;
}
/**
* @return success
*/
@ -902,6 +914,12 @@ public class TunnelController implements Logging {
if (!_config.containsKey(OPT_SIG_TYPE))
_config.setProperty(OPT_SIG_TYPE, PREFERRED_SIGTYPE.name());
}
if (type.equals(TYPE_IRC_CLIENT) || type.equals(TYPE_STD_CLIENT) ||
type.equals(TYPE_IRC_SERVER) || type.equals(TYPE_STD_SERVER) ||
type.equals(TYPE_SOCKS_IRC)) {
if (!_config.containsKey(OPT_PRIORITY))
_config.setProperty(OPT_PRIORITY, "10");
}
if (!isClient(type)) {
_tunnel.filterDefinition = _config.getProperty(PROP_FILTER);

View File

@ -1,5 +1,6 @@
package net.i2p.i2ptunnel.access;
import java.util.HashMap;
import java.util.Map;
import java.io.File;
@ -18,6 +19,7 @@ import net.i2p.data.Hash;
class FileFilterDefinitionElement extends FilterDefinitionElement {
private final File file;
private final Map<Hash, DestTracker> lastLoaded = new HashMap<>();
private volatile long lastLoading;
/**
@ -31,18 +33,36 @@ class FileFilterDefinitionElement extends FilterDefinitionElement {
@Override
public void update(Map<Hash, DestTracker> map) throws IOException {
if (!(file.exists() && file.isFile() && file.lastModified() > lastLoading))
if (!(file.exists() && file.isFile()))
return;
if (file.lastModified() <= lastLoading) {
synchronized (lastLoaded) {
for (Map.Entry<Hash, DestTracker> entry : lastLoaded.entrySet()) {
if (!map.containsKey(entry.getKey()))
map.put(entry.getKey(),entry.getValue());
}
}
return;
}
lastLoading = System.currentTimeMillis();
BufferedReader reader = null;
synchronized (lastLoaded) {
lastLoaded.clear();
}
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(file));
reader = new BufferedReader(new FileReader(file));
String b32;
while((b32 = reader.readLine()) != null) {
Hash hash = fromBase32(b32);
if (map.containsKey(hash))
continue;
map.put(hash, new DestTracker(hash, threshold));
DestTracker newTracker = new DestTracker(hash, threshold);
map.put(hash, newTracker);
synchronized (lastLoaded) {
lastLoaded.put(hash, newTracker);
}
}
} catch (InvalidDefinitionException bad32) {
throw new IOException("invalid access list entry", bad32);

View File

@ -59,13 +59,17 @@ abstract class IRCFilter {
*/
public static String inboundFilter(String s, StringBuffer expectedPong, DCCHelper helper) {
String field[] = DataHelper.split(s, " ", 4);
String field[] = DataHelper.split(s, " ", 5);
String command;
int idx=0;
try {
if (field[0].charAt(0) == ':')
// https://www.unrealircd.org/docs/Message_tags
// https://ircv3.net/specs/extensions/message-tags.html
if (field[0].charAt(0) == '@')
idx++;
if (field[idx].charAt(0) == ':')
idx++;
command = field[idx++].toUpperCase(Locale.US);
} catch (IndexOutOfBoundsException ioobe) {
@ -279,7 +283,7 @@ abstract class IRCFilter {
*/
public static String outboundFilter(String s, StringBuffer expectedPong, DCCHelper helper) {
String field[] = DataHelper.split(s, " ",3);
String field[] = DataHelper.split(s, " ", 4);
if(field[0].length()==0)
return null; // W T F?
@ -288,7 +292,12 @@ abstract class IRCFilter {
if(field[0].charAt(0)==':')
return null; // ???
String command = field[0].toUpperCase(Locale.US);
int idx = 0;
// https://www.unrealircd.org/docs/Message_tags
// https://ircv3.net/specs/extensions/message-tags.html
if (field[0].charAt(0) == '@')
idx++;
String command = field[idx++].toUpperCase(Locale.US);
if ("PING".equals(command)) {
// Most clients just send a PING and are happy with any old PONG. Others,
@ -304,17 +313,17 @@ abstract class IRCFilter {
String rv = null;
expectedPong.setLength(0);
if (field.length == 1) { // PING
if (field.length == idx) { // PING
rv = "PING";
// If we aren't rewriting the PING don't rewrite the PONG
// expectedPong.append("PONG 127.0.0.1");
} else if (field.length == 2) { // PING nonce
rv = "PING " + field[1];
} else if (field.length == idx + 1) { // PING nonce
rv = "PING " + field[idx];
// If we aren't rewriting the PING don't rewrite the PONG
// expectedPong.append("PONG ").append(field[1]);
} else if (field.length == 3) { // PING nonce serverLocation
rv = "PING " + field[1];
expectedPong.append("PONG ").append(field[2]).append(" :").append(field[1]); // PONG serverLocation nonce
} else if (field.length == idx + 2) { // PING nonce serverLocation
rv = "PING " + field[idx];
expectedPong.append("PONG ").append(field[idx + 1]).append(" :").append(field[idx]); // PONG serverLocation nonce
} else {
//if (_log.shouldLog(Log.ERROR))
// _log.error("IRC client sent a PING we don't understand, filtering it (\"" + s + "\")");
@ -335,20 +344,20 @@ abstract class IRCFilter {
// in addition to the CTCP version
if("NOTICE".equals(command))
{
if (field.length < 3)
if (field.length < idx + 2)
return s; // invalid, allow server response
String msg = field[2];
String msg = field[idx + 1];
if(msg.startsWith(":DCC "))
return filterDCCOut(field[0] + ' ' + field[1] + " :DCC ", msg.substring(5), helper);
return filterDCCOut(field[idx - 1] + ' ' + field[idx] + " :DCC ", msg.substring(5), helper);
// fall through
}
// Allow PRIVMSG, but block CTCP (except ACTION).
if("PRIVMSG".equals(command) || "NOTICE".equals(command))
{
if (field.length < 3)
if (field.length < idx + 2)
return s; // invalid, allow server response
String msg = field[2];
String msg = field[idx + 1];
if(msg.indexOf(0x01) >= 0) // CTCP marker ^A can be anywhere, not just immediately after the ':'
{
@ -369,7 +378,7 @@ abstract class IRCFilter {
return s;
}
if (msg.startsWith("DCC "))
return filterDCCOut(field[0] + ' ' + field[1] + " :\001DCC ", msg.substring(4), helper);
return filterDCCOut(field[idx - 1] + ' ' + field[idx] + " :\001DCC ", msg.substring(4), helper);
// XDCC looks safe, ip/port happens over regular DCC
// http://en.wikipedia.org/wiki/XDCC
if (msg.toUpperCase(Locale.US).startsWith("XDCC ") && helper != null && helper.isEnabled())
@ -382,19 +391,19 @@ abstract class IRCFilter {
}
if("USER".equals(command)) {
if (field.length < 3)
if (field.length < idx + 2)
return s; // invalid, allow server response
int idx = field[2].lastIndexOf(':');
if(idx<0)
int cidx = field[idx + 1].lastIndexOf(':');
if (cidx < 0)
return "USER user hostname localhost :realname";
String realname = field[2].substring(idx+1);
String ret = "USER "+field[1]+" hostname localhost :"+realname;
String realname = field[idx + 1].substring(cidx + 1);
String ret = "USER " + field[idx] + " hostname localhost :" + realname;
return ret;
}
if ("PART".equals(command)) {
// hide client message
return "PART " + field[1] + " :leaving";
return "PART " + field[idx] + " :leaving";
}
if ("QUIT".equals(command)) {

View File

@ -8,12 +8,17 @@ import net.i2p.i2ptunnel.udp.*;
import net.i2p.util.Log;
/**
* Sends to one of many Sinks
* Sends to one of many Sinks based on the toPort
*
* @author zzz modded from streamr/MultiSource
*/
public class MultiSink<S extends Sink> implements Source, Sink {
private final Map<Integer, S> cache;
public MultiSink(Map<Destination, S> cache) {
/**
* @param cache map of toPort to Sink
*/
public MultiSink(Map<Integer, S> cache) {
this.cache = cache;
}
@ -23,18 +28,32 @@ public class MultiSink<S extends Sink> implements Source, Sink {
public void start() {}
/**
* Send to a single sink looked up by toPort
*
* May throw RuntimeException from underlying sinks
*
* @param from passed along
* @param fromPort passed along
* @param toPort passed along
* @since 0.9.53 added fromPort and toPort parameters
* @throws RuntimeException
*/
public void send(Destination from, byte[] data) {
Sink s = this.cache.get(from);
public void send(Destination from, int fromPort, int toPort, byte[] data) {
Sink s = cache.get(toPort);
if (s == null && toPort == 0 && cache.size() == 1) {
// for now, do the server a favor if the toPort isn't specified
for (Sink ss : cache.values()) {
s = ss;
break;
}
}
if (s == null) {
Log log = I2PAppContext.getGlobalContext().logManager().getLog(MultiSink.class);
log.error("No where to go for " + from.calculateHash().toBase64().substring(0, 6));
String frm = (from != null) ? from.toBase32() : "raw";
if (log.shouldWarn())
log.warn("No where to go for " + frm + " port " + fromPort + " to port " + toPort);
return;
}
s.send(from, data);
s.send(from, fromPort, toPort, data);
}
private Map<Destination, S> cache;
}

View File

@ -1,38 +0,0 @@
package net.i2p.i2ptunnel.socks;
import java.util.Map;
import net.i2p.data.Destination;
import net.i2p.i2ptunnel.udp.*;
import net.i2p.util.Log;
/**
* Track who the reply goes to
* @author zzz
*/
public class ReplyTracker<S extends Sink> implements Source, Sink {
public ReplyTracker(S reply, Map<Destination, S> cache) {
this.reply = reply;
this.cache = cache;
}
public void setSink(Sink sink) {
this.sink = sink;
}
public void start() {}
/**
* May throw RuntimeException from underlying sink
* @throws RuntimeException
*/
public void send(Destination to, byte[] data) {
this.cache.put(to, this.reply);
this.sink.send(to, data);
}
private S reply;
private Map<Destination, S> cache;
private Sink sink;
}

View File

@ -1,8 +1,12 @@
package net.i2p.i2ptunnel.socks;
import java.util.Arrays;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.socks.SOCKS5Constants.AddressType;
import net.i2p.util.Addresses;
/**
* Save the SOCKS header from a datagram
@ -11,9 +15,12 @@ import net.i2p.data.Destination;
* @author zzz
*/
public class SOCKSHeader {
private byte[] header;
private static final byte[] beg = {0,0,0,3,60};
/**
* @param data the whole packet
* @throws IllegalArgumentException on bad socks format
*/
public SOCKSHeader(byte[] data) {
if (data.length <= 8)
@ -24,14 +31,12 @@ public class SOCKSHeader {
throw new IllegalArgumentException("We can't handle fragments!");
int headerlen = 0;
int addressType = data[3];
if (addressType == 1) {
// this will fail in getDestination()
if (addressType == AddressType.IPV4) {
headerlen = 6 + 4;
} else if (addressType == 3) {
} else if (addressType == AddressType.DOMAINNAME) {
headerlen = 6 + 1 + (data[4] & 0xff);
} else if (addressType == 4) {
// this will fail in getDestination()
// but future garlicat partial hash lookup possible?
} else if (addressType == AddressType.IPV6) {
// future garlicat partial hash lookup possible?
headerlen = 6 + 16;
} else {
throw new IllegalArgumentException("Unknown address type: " + addressType);
@ -42,33 +47,62 @@ public class SOCKSHeader {
this.header = new byte[headerlen];
System.arraycopy(data, 0, this.header, 0, headerlen);
}
private static final byte[] beg = {0,0,0,3,60};
private static final byte[] end = {0,0};
/**
* Make a dummy header from a dest,
* for those cases where we want to receive unsolicited datagrams.
* Unused for now.
*
* @param port I2CP port 0-65535
* @since 0.9.53 add port param
*/
public SOCKSHeader(Destination dest) {
this.header = new byte[beg.length + 60 + end.length];
public SOCKSHeader(Destination dest, int port) {
this.header = new byte[beg.length + 60 + 2];
System.arraycopy(beg, 0, this.header, 0, beg.length);
String b32 = dest.toBase32();
System.arraycopy(DataHelper.getASCII(b32), 0, this.header, beg.length, 60);
System.arraycopy(end, 0, this.header, beg.length + 60, end.length);
DataHelper.toLong(header, beg.length + 60, 2, port);
}
/**
* As of 0.9.53, returns IP address as a string for address types 1 and 4.
*
* @return hostname or null for unknown address type
*/
public String getHost() {
int addressType = this.header[3];
if (addressType != 3)
return null;
int namelen = (this.header[4] & 0xff);
byte[] nameBytes = new byte[namelen];
System.arraycopy(this.header, 5, nameBytes, 0, namelen);
return DataHelper.getUTF8(nameBytes);
if (addressType == AddressType.DOMAINNAME) {
int namelen = (this.header[4] & 0xff);
return DataHelper.getUTF8(header, 5, namelen);
}
if (addressType == AddressType.IPV4)
return Addresses.toString(Arrays.copyOfRange(header, 4, 4));
if (addressType == AddressType.IPV6)
return Addresses.toString(Arrays.copyOfRange(header, 4, 16));
return null;
}
/**
* @return 0 - 65535
* @since 0.9.53
*/
public int getPort() {
int namelen;
int addressType = header[3];
if (addressType == 3)
namelen = 1 + (header[4] & 0xff);
else if (addressType == 1)
namelen = 4;
else if (addressType == 4)
namelen = 16;
else
return 0;
return (int) DataHelper.fromLong(header, 4 + namelen, 2);
}
/**
* @return destination or null
*/
public Destination getDestination() {
String name = getHost();
if (name == null)
@ -80,6 +114,4 @@ public class SOCKSHeader {
public byte[] getBytes() {
return header;
}
private byte[] header;
}

View File

@ -5,6 +5,7 @@ import java.net.InetAddress;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
import net.i2p.client.streaming.I2PSocketAddress;
import net.i2p.data.Destination;
import net.i2p.i2ptunnel.udp.*;
@ -14,22 +15,26 @@ import net.i2p.i2ptunnel.udp.*;
* ports, it happens outside of here.
*
* TX:
* UDPSource -&gt; SOCKSUDPUnwrapper -&gt; ReplyTracker ( -&gt; I2PSink in SOCKSUDPTunnel)
* UDPSource -&gt; SOCKSUDPUnwrapper -&gt; (I2PSink in SOCKSUDPTunnel)
*
* RX:
* UDPSink &lt;- SOCKSUDPWrapper ( &lt;- MultiSink &lt;- I2PSource in SOCKSUDPTunnel)
*
* The Unwrapper passes headers to the Wrapper through a cache.
* The ReplyTracker passes sinks to MultiSink through a cache.
* MultiSink routes packets based on toPort.
*
* @author zzz
*/
public class SOCKSUDPPort implements Source, Sink {
private final UDPSink udpsink;
private final UDPSource udpsource;
private final SOCKSUDPWrapper wrapper;
private final SOCKSUDPUnwrapper unwrapper;
public SOCKSUDPPort(InetAddress host, int port, Map<Destination, SOCKSUDPPort> replyMap) {
public SOCKSUDPPort(InetAddress host, int port, Map<Integer, SOCKSUDPPort> replyMap) {
// this passes the host and port from UDPUnwrapper to UDPWrapper
Map<Destination, SOCKSHeader> cache = new ConcurrentHashMap<Destination, SOCKSHeader>(4);
Map<I2PSocketAddress, SOCKSHeader> cache = new ConcurrentHashMap<I2PSocketAddress, SOCKSHeader>(4);
// rcv from I2P and send to a port
this.wrapper = new SOCKSUDPWrapper(cache);
@ -41,8 +46,6 @@ public class SOCKSUDPPort implements Source, Sink {
this.udpsource = new UDPSource(sock);
this.unwrapper = new SOCKSUDPUnwrapper(cache);
this.udpsource.setSink(this.unwrapper);
this.udptracker = new ReplyTracker<SOCKSUDPPort>(this, replyMap);
this.unwrapper.setSink(this.udptracker);
}
/** Socks passes this back to the client on the TCP connection */
@ -51,7 +54,7 @@ public class SOCKSUDPPort implements Source, Sink {
}
public void setSink(Sink sink) {
this.udptracker.setSink(sink);
this.unwrapper.setSink(sink);
}
public void start() {
@ -66,16 +69,14 @@ public class SOCKSUDPPort implements Source, Sink {
/**
* May throw RuntimeException from underlying sink
* @param from will be passed along
* @param fromPort will be passed along
* @param toPort will be passed along
* @since 0.9.53 added fromPort and toPort parameters
* @throws RuntimeException
*/
public void send(Destination from, byte[] data) {
this.wrapper.send(from, data);
public void send(Destination from, int fromPort, int toPort, byte[] data) {
this.wrapper.send(from, fromPort, toPort, data);
}
private UDPSink udpsink;
private UDPSource udpsource;
private SOCKSUDPWrapper wrapper;
private SOCKSUDPUnwrapper unwrapper;
private ReplyTracker<SOCKSUDPPort> udptracker;
}

View File

@ -4,6 +4,7 @@ import java.net.InetAddress;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Iterator;
import java.util.Map;
import net.i2p.data.Destination;
import net.i2p.i2ptunnel.I2PTunnel;
import net.i2p.i2ptunnel.udpTunnel.I2PTunnelUDPClientBase;
@ -12,18 +13,24 @@ import net.i2p.i2ptunnel.udpTunnel.I2PTunnelUDPClientBase;
* A Datagram Tunnel that can have multiple bidirectional ports on the UDP side.
*
* TX:
* (ReplyTracker in multiple SOCKSUDPPorts -&gt; ) I2PSink
* (multiple SOCKSUDPPorts -&gt; ) I2PSink
*
* RX:
* (SOCKSUDPWrapper in multiple SOCKSUDPPorts &lt;- ) MultiSink &lt;- I2PSource
*
* The reply from a dest goes to the last SOCKSUDPPort that sent to that dest.
* If multiple ports are talking to a dest at the same time, this isn't
* going to work very well.
* The replies must be to the same I2CP toPort as the outbound fromPort.
* If the server does not honor that, the replies will be dropped.
*
* The replies must be repliable. Raw datagrams are not supported, and would
* require a unique source port for each target.
*
* Preliminary, untested, possibly incomplete.
*
* @author zzz modded from streamr/StreamrConsumer
*/
public class SOCKSUDPTunnel extends I2PTunnelUDPClientBase {
private final Map<Integer, SOCKSUDPPort> ports;
private final MultiSink<SOCKSUDPPort> demuxer;
/**
* Set up a tunnel with no UDP side yet.
@ -33,15 +40,14 @@ public class SOCKSUDPTunnel extends I2PTunnelUDPClientBase {
super(null, tunnel, tunnel, tunnel);
this.ports = new ConcurrentHashMap<Integer, SOCKSUDPPort>(1);
this.cache = new ConcurrentHashMap<Destination, SOCKSUDPPort>(1);
this.demuxer = new MultiSink<SOCKSUDPPort>(this.cache);
this.demuxer = new MultiSink<SOCKSUDPPort>(ports);
setSink(this.demuxer);
}
/** @return the UDP port number */
public int add(InetAddress host, int port) {
SOCKSUDPPort sup = new SOCKSUDPPort(host, port, this.cache);
SOCKSUDPPort sup = new SOCKSUDPPort(host, port, ports);
this.ports.put(Integer.valueOf(sup.getPort()), sup);
sup.setSink(this);
sup.start();
@ -52,11 +58,6 @@ public class SOCKSUDPTunnel extends I2PTunnelUDPClientBase {
SOCKSUDPPort sup = this.ports.remove(port);
if (sup != null)
sup.stop();
for (Iterator<Map.Entry<Destination, SOCKSUDPPort>> iter = cache.entrySet().iterator(); iter.hasNext();) {
Map.Entry<Destination, SOCKSUDPPort> e = iter.next();
if (e.getValue() == sup)
iter.remove();
}
}
@Override
@ -81,12 +82,5 @@ public class SOCKSUDPTunnel extends I2PTunnelUDPClientBase {
sup.stop();
}
this.ports.clear();
this.cache.clear();
}
private Map<Integer, SOCKSUDPPort> ports;
private Map<Destination, SOCKSUDPPort> cache;
private MultiSink<SOCKSUDPPort> demuxer;
}

View File

@ -5,20 +5,23 @@ import java.util.Map;
import net.i2p.I2PAppContext;
import net.i2p.data.Destination;
import net.i2p.i2ptunnel.udp.*;
import net.i2p.client.streaming.I2PSocketAddress;
import net.i2p.util.Log;
/**
* Strip a SOCKS header off a datagram, convert it to a Destination
* Strip a SOCKS header off a datagram, convert it to a Destination and port
* Ref: RFC 1928
*
* @author zzz
*/
public class SOCKSUDPUnwrapper implements Source, Sink {
private Sink sink;
private final Map<I2PSocketAddress, SOCKSHeader> cache;
/**
* @param cache put headers here to pass to SOCKSUDPWrapper
*/
public SOCKSUDPUnwrapper(Map<Destination, SOCKSHeader> cache) {
public SOCKSUDPUnwrapper(Map<I2PSocketAddress, SOCKSHeader> cache) {
this.cache = cache;
}
@ -31,9 +34,13 @@ public class SOCKSUDPUnwrapper implements Source, Sink {
/**
*
* May throw RuntimeException from underlying sink
* @param ignored_from ignored
* @param fromPort will be passed along
* @param toPort ignored
* @since 0.9.53 added fromPort and toPort parameters
* @throws RuntimeException
*/
public void send(Destination ignored_from, byte[] data) {
public void send(Destination ignored_from, int fromPort, int toPort, byte[] data) {
SOCKSHeader h;
try {
h = new SOCKSHeader(data);
@ -50,14 +57,14 @@ public class SOCKSUDPUnwrapper implements Source, Sink {
return;
}
cache.put(dest, h);
cache.put(new I2PSocketAddress(dest, toPort), h);
int headerlen = h.getBytes().length;
byte unwrapped[] = new byte[data.length - headerlen];
System.arraycopy(data, headerlen, unwrapped, 0, unwrapped.length);
this.sink.send(dest, unwrapped);
// We pass the local DatagramSocket's port through as the I2CP from port,
// so that it will come back as the toPort in the reply,
// and MultiSink will send it to the right SOCKSUDPWrapper/SOCKSUDPPort
this.sink.send(dest, fromPort, h.getPort(), unwrapped);
}
private Sink sink;
private Map<Destination, SOCKSHeader> cache;
}

View File

@ -2,8 +2,11 @@ package net.i2p.i2ptunnel.socks;
import java.util.Map;
import net.i2p.I2PAppContext;
import net.i2p.client.streaming.I2PSocketAddress;
import net.i2p.data.Destination;
import net.i2p.i2ptunnel.udp.*;
import net.i2p.util.Log;
/**
* Put a SOCKS header on a datagram
@ -12,7 +15,10 @@ import net.i2p.i2ptunnel.udp.*;
* @author zzz
*/
public class SOCKSUDPWrapper implements Source, Sink {
public SOCKSUDPWrapper(Map<Destination, SOCKSHeader> cache) {
private Sink sink;
private final Map<I2PSocketAddress, SOCKSHeader> cache;
public SOCKSUDPWrapper(Map<I2PSocketAddress, SOCKSHeader> cache) {
this.cache = cache;
}
@ -26,13 +32,23 @@ public class SOCKSUDPWrapper implements Source, Sink {
* Use the cached header, which should have the host string and port
*
* May throw RuntimeException from underlying sink
* @since 0.9.53 added fromPort and toPort parameters
* @throws RuntimeException
*/
public void send(Destination from, byte[] data) {
public void send(Destination from, int fromPort, int toPort, byte[] data) {
if (this.sink == null)
return;
if (from == null) {
// TODO to handle raw replies, SOCKSUDPWrapper would have to use a unique
// fromPort for every target or request, and we would lookup the
// destination by toPort
Log log = I2PAppContext.getGlobalContext().logManager().getLog(SOCKSUDPWrapper.class);
if (log.shouldWarn())
log.warn("No support for raw datagrams, from port " + fromPort + " to port " + toPort);
return;
}
SOCKSHeader h = cache.get(from);
SOCKSHeader h = cache.get(new I2PSocketAddress(from, fromPort));
if (h == null) {
// RFC 1928 says drop
// h = new SOCKSHeader(from);
@ -43,9 +59,6 @@ public class SOCKSUDPWrapper implements Source, Sink {
byte wrapped[] = new byte[header.length + data.length];
System.arraycopy(header, 0, wrapped, 0, header.length);
System.arraycopy(data, 0, wrapped, header.length, data.length);
this.sink.send(from, wrapped);
this.sink.send(from, fromPort, toPort, wrapped);
}
private Sink sink;
private Map<Destination, SOCKSHeader> cache;
}

View File

@ -8,6 +8,7 @@ import java.net.Socket;
import java.nio.channels.SelectableChannel;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.client.streaming.I2PSocketAddress;
import net.i2p.client.streaming.I2PSocketOptions;
import net.i2p.data.DataFormatException;
import net.i2p.data.Destination;

View File

@ -14,10 +14,12 @@ import net.i2p.util.Log;
* @author zzz modded for I2PTunnel
*/
public class MultiSource implements Source, Sink {
private Sink sink;
private final List<MSink> sinks;
private final Log log = I2PAppContext.getGlobalContext().logManager().getLog(getClass());
public MultiSource() {
this.sinks = new CopyOnWriteArrayList<Destination>();
this.sinks = new CopyOnWriteArrayList<MSink>();
}
public void setSink(Sink sink) {
@ -32,9 +34,10 @@ public class MultiSource implements Source, Sink {
/**
* May throw RuntimeException from underlying sinks
* @since 0.9.53 added fromPort and toPort parameters
* @throws RuntimeException
*/
public void send(Destination ignored_from, byte[] data) {
public void send(Destination ignored_from, int ignored_fromPort, int ignored_toPort, byte[] data) {
if (sinks.isEmpty()) {
if (log.shouldDebug())
log.debug("No subscribers to send " + data.length + " bytes to");
@ -43,19 +46,53 @@ public class MultiSource implements Source, Sink {
if (log.shouldDebug())
log.debug("Sending " + data.length + " bytes to " + sinks.size() + " subscribers");
for(Destination dest : this.sinks) {
this.sink.send(dest, data);
for(MSink ms : this.sinks) {
this.sink.send(ms.dest, ms.fromPort, ms.toPort, data);
}
}
public void add(Destination sink) {
this.sinks.add(sink);
/**
* @since 0.9.53 changed to MSink parameter
*/
public void add(MSink ms) {
sinks.add(ms);
}
public void remove(Destination sink) {
this.sinks.remove(sink);
/**
* @since 0.9.53 changed to MSink parameter
*/
public void remove(MSink ms) {
sinks.remove(ms);
}
/**
* @since 0.9.53
*/
static class MSink {
public final Destination dest;
public final int fromPort, toPort;
public MSink(Destination dest, int fromPort, int toPort) {
this.dest = dest; this.fromPort = fromPort; this.toPort = toPort;
}
@Override
public int hashCode() {
return dest.hashCode() | fromPort | (toPort << 16);
}
@Override
public boolean equals(Object o) {
if (!(o instanceof MSink))
return false;
MSink s = (MSink) o;
return dest.equals(s.dest) && fromPort == s.fromPort && toPort == s.toPort;
}
@Override
public String toString() {
return "from port " + fromPort + " to " + dest.toBase32() + ':' + toPort;
}
}
private Sink sink;
private final List<Destination> sinks;
}

View File

@ -10,10 +10,21 @@ import net.i2p.util.Log;
* @author welterde/zzz
*/
public class Pinger implements Source, Runnable {
private final Log log = I2PAppContext.getGlobalContext().logManager().getLog(getClass());
protected Sink sink;
protected final Thread thread;
private final Object waitlock = new Object();
protected volatile boolean running;
private final Log log;
private final int fromPort;
public Pinger() {
/**
* @param fromPort the I2CP from port
* @since 0.9.53 added ctx and fromPort params
*/
public Pinger(I2PAppContext ctx, int fromPort) {
this.thread = new I2PAppThread(this);
log = ctx.logManager().getLog(getClass());
this.fromPort = fromPort;
}
public void setSink(Sink sink) {
@ -22,7 +33,6 @@ public class Pinger implements Source, Runnable {
public void start() {
this.running = true;
//this.waitlock = new Object();
this.thread.start();
}
@ -35,9 +45,9 @@ public class Pinger implements Source, Runnable {
byte[] data = new byte[1];
data[0] = 1;
try {
this.sink.send(null, data);
this.sink.send(null, fromPort, 0, data);
if (log.shouldDebug())
log.debug("Sent unsubscribe");
log.debug("Sent unsubscribe from port " + fromPort);
} catch (RuntimeException re) {}
}
@ -47,11 +57,10 @@ public class Pinger implements Source, Runnable {
data[0] = 0;
int i = 0;
while(this.running) {
//System.out.print("p");
try {
this.sink.send(null, data);
this.sink.send(null, fromPort, 0, data);
if (log.shouldDebug())
log.debug("Sent subscribe");
log.debug("Sent subscribe from port " + fromPort);
} catch (RuntimeException re) {
if (log.shouldWarn())
log.warn("error sending", re);
@ -71,9 +80,4 @@ public class Pinger implements Source, Runnable {
}
}
}
protected Sink sink;
protected final Thread thread;
private final Object waitlock = new Object();
protected volatile boolean running;
}

View File

@ -24,11 +24,13 @@ public class StreamrConsumer extends I2PTunnelUDPClientBase {
super(destination, l, notifyThis, tunnel);
// create udp-destination
this.sink = new UDPSink(host, port);
UDPSink udps = new UDPSink(host, port);
int localPort = udps.getPort();
this.sink = udps;
setSink(this.sink);
// create pinger
this.pinger = new Pinger();
this.pinger = new Pinger(_context, localPort);
this.pinger.setSink(this);
}

View File

@ -21,8 +21,7 @@ public class StreamrProducer extends I2PTunnelUDPServerBase {
public StreamrProducer(int port,
File privkey, String privkeyname, Logging l,
EventDispatcher notifyThis, I2PTunnel tunnel) {
// verify subscription requests
super(true, privkey, privkeyname, l, notifyThis, tunnel);
super(privkey, privkeyname, l, notifyThis, tunnel);
// The broadcaster
this.multi = new MultiSource();

View File

@ -20,7 +20,7 @@ public class Subscriber implements Sink {
private final I2PAppContext ctx = I2PAppContext.getGlobalContext();
private final Log log = ctx.logManager().getLog(getClass());
private final Map<Destination, Long> subscriptions;
private final Map<MultiSource.MSink, Long> subscriptions;
private final MultiSource multi;
private final SimpleTimer2.TimedEvent timer;
private volatile boolean timerRunning;
@ -31,7 +31,7 @@ public class Subscriber implements Sink {
public Subscriber(MultiSource multi) {
this.multi = multi;
// subscriptions
this.subscriptions = new ConcurrentHashMap<Destination, Long>();
this.subscriptions = new ConcurrentHashMap<MultiSource.MSink, Long>();
timer = new Expire();
}
@ -40,44 +40,47 @@ public class Subscriber implements Sink {
*
* @param dest to subscribe or unsubscribe
* @param data must be a single byte, 0 to subscribe, 1 to unsubscribe
* @since 0.9.53 added fromPort and toPort parameters
*/
public void send(Destination dest, byte[] data) {
public void send(Destination dest, int fromPort, int toPort, byte[] data) {
if(dest == null || data.length < 1) {
// invalid packet
if (log.shouldWarn())
log.warn("bad subscription from " + dest);
log.warn("bad subscription from " + dest.toBase32() + ':' + fromPort);
} else {
byte ctrl = data[0];
// swap fromPort and toPort for the replies
MultiSource.MSink ms = new MultiSource.MSink(dest, toPort, fromPort);
int ctrl = data[0] & 0xff;
if(ctrl == 0) {
if (this.subscriptions.put(dest, Long.valueOf(ctx.clock().now())) == null) {
if (this.subscriptions.put(ms, Long.valueOf(ctx.clock().now())) == null) {
if (subscriptions.size() > MAX_SUBSCRIPTIONS) {
subscriptions.remove(dest);
if (log.shouldWarn())
log.warn("Too many subscriptions, denying: " + dest.toBase32());
log.warn("Too many subscriptions, denying: " + ms);
return;
}
// subscribe
if (log.shouldWarn())
log.warn("Add subscription: " + dest.toBase32());
this.multi.add(dest);
log.warn("Add subscription: " + ms);
this.multi.add(ms);
if (!timerRunning) {
timer.reschedule(EXPIRATION);
timerRunning = true;
}
} else {
if (log.shouldInfo())
log.info("Continue subscription: " + dest.toBase32());
log.info("Continue subscription: " + ms);
}
} else if(ctrl == 1) {
// unsubscribe
if (log.shouldWarn())
log.warn("Remove subscription: " + dest.toBase32());
if (subscriptions.remove(dest) != null)
multi.remove(dest);
log.warn("Remove subscription: " + ms);
if (subscriptions.remove(ms) != null)
multi.remove(ms);
} else {
// invalid packet
if (log.shouldWarn())
log.warn("bad subscription from " + dest);
log.warn("bad subscription flag " + ctrl + " from " + ms);
}
}
}
@ -95,15 +98,15 @@ public class Subscriber implements Sink {
return;
}
long exp = ctx.clock().now() - EXPIRATION;
for (Iterator<Map.Entry<Destination, Long>> iter = subscriptions.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry<Destination, Long> e = iter.next();
for (Iterator<Map.Entry<MultiSource.MSink, Long>> iter = subscriptions.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry<MultiSource.MSink, Long> e = iter.next();
long then = e.getValue().longValue();
if (then < exp) {
Destination dest = e.getKey();
MultiSource.MSink ms = e.getKey();
iter.remove();
multi.remove(dest);
multi.remove(ms);
if (log.shouldWarn())
log.warn("Expired subscription: " + dest.toBase32());
log.warn("Expired subscription: " + ms);
}
}
if (!subscriptions.isEmpty()) {

View File

@ -14,14 +14,39 @@ import net.i2p.client.datagram.I2PDatagramMaker;
*/
public class I2PSink implements Sink {
protected final boolean raw;
protected final I2PSession sess;
protected final Destination dest;
protected final I2PDatagramMaker maker;
/**
* @since 0.9.53
*/
protected final int toPort;
/**
* repliable (not raw)
*/
public I2PSink(I2PSession sess, Destination dest) {
this(sess, dest, false);
}
/**
* @param raw false for repliable
*/
public I2PSink(I2PSession sess, Destination dest, boolean raw) {
this(sess, dest, raw, I2PSession.PORT_UNSPECIFIED);
}
/**
* @param raw false for repliable
* @param toPort I2CP destination port, 0-65535
* @since 0.9.53
*/
public I2PSink(I2PSession sess, Destination dest, boolean raw, int toPort) {
this.sess = sess;
this.dest = dest;
this.raw = raw;
this.toPort = toPort;
// create maker
if (raw) {
@ -34,31 +59,30 @@ public class I2PSink implements Sink {
/**
* @param src ignored
* @param fromPort I2CP port
* @param ign_toPort ignored
* @since 0.9.53 added fromPort and toPort parameters, breaking change, sorry
* @throws RuntimeException if session is closed
*/
public synchronized void send(Destination src, byte[] data) {
public synchronized void send(Destination src, int fromPort, int ign_toPort, byte[] data) {
//System.out.print("w");
// create payload
byte[] payload;
if(!this.raw) {
if (!this.raw) {
synchronized(this.maker) {
payload = this.maker.makeI2PDatagram(data);
}
} else
} else {
payload = data;
}
// send message
try {
this.sess.sendMessage(this.dest, payload,
(this.raw ? I2PSession.PROTO_DATAGRAM_RAW : I2PSession.PROTO_DATAGRAM),
I2PSession.PORT_UNSPECIFIED, I2PSession.PORT_UNSPECIFIED);
fromPort, toPort);
} catch (I2PSessionException ise) {
throw new RuntimeException("failed to send data", ise);
}
}
protected final boolean raw;
protected final I2PSession sess;
protected final Destination dest;
protected final I2PDatagramMaker maker;
}

View File

@ -14,6 +14,10 @@ import net.i2p.client.datagram.I2PDatagramMaker;
*/
public class I2PSinkAnywhere implements Sink {
protected final boolean raw;
protected final I2PSession sess;
protected final I2PDatagramMaker maker;
public I2PSinkAnywhere(I2PSession sess) {
this(sess, false);
}
@ -35,27 +39,35 @@ public class I2PSinkAnywhere implements Sink {
* @param to - where it's going
* @throws RuntimeException if session is closed
*/
public synchronized void send(Destination to, byte[] data) {
public void send(Destination to, byte[] data) {
send(to, I2PSession.PORT_UNSPECIFIED, I2PSession.PORT_UNSPECIFIED, data);
}
/**
* @param to - where it's going
* @param fromPort I2CP port 0 - 65535
* @param toPort I2CP port 0 - 65535
* @since 0.9.53
* @throws RuntimeException if session is closed
*/
public synchronized void send(Destination to, int fromPort, int toPort, byte[] data) {
// create payload
byte[] payload;
if(!this.raw) {
synchronized(this.maker) {
payload = this.maker.makeI2PDatagram(data);
}
} else
} else {
payload = data;
}
// send message
try {
this.sess.sendMessage(to, payload,
(this.raw ? I2PSession.PROTO_DATAGRAM_RAW : I2PSession.PROTO_DATAGRAM),
I2PSession.PORT_UNSPECIFIED, I2PSession.PORT_UNSPECIFIED);
fromPort, toPort);
} catch (I2PSessionException ise) {
throw new RuntimeException("failed to send data", ise);
}
}
protected final boolean raw;
protected final I2PSession sess;
protected final I2PDatagramMaker maker;
}

View File

@ -1,94 +1,105 @@
package net.i2p.i2ptunnel.udp;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import net.i2p.I2PAppContext;
import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionListener;
import net.i2p.client.I2PSessionMuxedListener;
import net.i2p.client.datagram.I2PDatagramDissector;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
/**
* Refactored in 0.9.53 to support I2CP protocols and ports
*
* @author welterde
*/
public class I2PSource implements Source, Runnable {
public class I2PSource implements Source {
protected final I2PSession sess;
protected Sink sink;
private final Protocol protocol;
private final int port;
private final I2PDatagramDissector diss;
private final Log log;
/**
* @since 0.9.53
*/
public enum Protocol { REPLIABLE, RAW, BOTH }
/**
* Handles both REPLIABLE and RAW on any port
*/
public I2PSource(I2PSession sess) {
this(sess, true, false);
this(sess, Protocol.BOTH);
}
public I2PSource(I2PSession sess, boolean verify) {
this(sess, verify, false);
/**
* Listen on all I2CP ports.
* No support for arbitrary protocol numbers.
*
* @param protocol REPLIABLE, RAW, or BOTH
* @since 0.9.53
*/
public I2PSource(I2PSession sess, Protocol protocol) {
this(sess, protocol, I2PSession.PORT_ANY);
}
public I2PSource(I2PSession sess, boolean verify, boolean raw) {
/**
* @param port I2CP port or I2PSession.PORT_ANY
* @param protocol REPLIABLE, RAW, or BOTH
* @since 0.9.53
*/
public I2PSource(I2PSession sess, Protocol protocol, int port) {
this.sess = sess;
this.verify = verify;
this.raw = raw;
// create queue
this.queue = new ArrayBlockingQueue<Integer>(256);
// create listener
this.sess.setSessionListener(new Listener());
// create thread
this.thread = new I2PAppThread(this);
this.protocol = protocol;
this.port = port;
diss = (protocol != Protocol.RAW) ? new I2PDatagramDissector() : null;
log = I2PAppContext.getGlobalContext().logManager().getLog(getClass());
}
public void setSink(Sink sink) {
this.sink = sink;
}
public void start() {
this.thread.start();
// create listener
Listener l = new Listener();
if (protocol != Protocol.RAW)
sess.addMuxedSessionListener(l, I2PSession.PROTO_DATAGRAM, port);
if (protocol != Protocol.REPLIABLE)
sess.addMuxedSessionListener(l, I2PSession.PROTO_DATAGRAM_RAW, port);
}
public void run() {
// create dissector
I2PDatagramDissector diss = new I2PDatagramDissector();
_running = true;
while (_running) {
protected class Listener implements I2PSessionMuxedListener {
public void messageAvailable(I2PSession sess, int id, long size) {
throw new IllegalStateException("muxed");
}
/**
* @since 0.9.53
*/
public void messageAvailable(I2PSession session, int id, long size, int proto, int fromPort, int toPort) {
if (log.shouldDebug())
log.debug("Got " + size + " bytes, proto: " + proto + " from port: " + fromPort + " to port: " + toPort);
try {
// get id
int id = this.queue.take();
// receive message
byte[] msg = this.sess.receiveMessage(id);
if(!this.raw) {
byte[] msg = session.receiveMessage(id);
if (proto == I2PSession.PROTO_DATAGRAM) {
// load datagram into it
diss.loadI2PDatagram(msg);
// now call sink
if(this.verify)
this.sink.send(diss.getSender(), diss.getPayload());
else
this.sink.send(diss.extractSender(), diss.extractPayload());
sink.send(diss.getSender(), fromPort, toPort, diss.getPayload());
} else if (proto == I2PSession.PROTO_DATAGRAM_RAW) {
sink.send(null, fromPort, toPort, msg);
} else {
// verify is ignored
this.sink.send(null, msg);
if (log.shouldWarn())
log.warn("dropping message with unknown protocol " + proto);
}
//System.out.print("r");
} catch(Exception e) {
Log log = I2PAppContext.getGlobalContext().logManager().getLog(getClass());
if (log.shouldWarn())
log.warn("error sending", e);
break;
}
}
}
protected class Listener implements I2PSessionListener {
public void messageAvailable(I2PSession sess, int id, long size) {
try {
queue.put(id);
} catch(Exception e) {
// ignore
log.warn("error receiving datagram", e);
}
}
@ -97,24 +108,11 @@ public class I2PSource implements Source, Runnable {
}
public void disconnected(I2PSession arg0) {
_running = false;
thread.interrupt();
}
public void errorOccurred(I2PSession arg0, String arg1, Throwable arg2) {
Log log = I2PAppContext.getGlobalContext().logManager().getLog(getClass());
log.error(arg1, arg2);
_running = false;
thread.interrupt();
}
}
protected final I2PSession sess;
protected final BlockingQueue<Integer> queue;
protected Sink sink;
protected final Thread thread;
protected final boolean verify;
protected final boolean raw;
private volatile boolean _running;
}

View File

@ -8,8 +8,11 @@ import net.i2p.data.Destination;
*/
public interface Sink {
/**
* @param src some implementations may ignore
* @param fromPort I2CP source port, 0-65535
* @param toPort I2CP destination port, 0-65535
* @param src some implementations may ignore, may be null in some implementations
* @since 0.9.53 added fromPort and toPort parameters, breaking change, sorry
* @throws RuntimeException in some implementations
*/
public void send(Destination src, byte[] data);
public void send(Destination src, int fromPort, int toPort, byte[] data);
}

View File

@ -13,7 +13,13 @@ import net.i2p.data.Destination;
*/
public class UDPSink implements Sink {
protected final DatagramSocket sock;
protected final InetAddress remoteHost;
protected final int remotePort;
/**
* @param host where to send
* @param port where to send
* @throws IllegalArgumentException on DatagramSocket IOException
*/
public UDPSink(InetAddress host, int port) {
@ -23,18 +29,31 @@ public class UDPSink implements Sink {
} catch (IOException e) {
throw new IllegalArgumentException("failed to open udp-socket", e);
}
this.remoteHost = host;
this.remotePort = port;
}
// remote port
/**
* @param socket existing socket
* @param host where to send
* @param port where to send
* @since 0.9.53
*/
public UDPSink(DatagramSocket socket, InetAddress host, int port) {
sock = socket;
this.remoteHost = host;
this.remotePort = port;
}
/**
* @param src ignored
* @param fromPort ignored
* @param toPort ignored
* @since 0.9.53 added fromPort and toPort parameters, breaking change, sorry
* @throws RuntimeException on DatagramSocket IOException
*/
public void send(Destination src, byte[] data) {
public void send(Destination src, int fromPort, int toPort, byte[] data) {
// if data.length > this.sock.getSendBufferSize() ...
// create packet
@ -48,6 +67,9 @@ public class UDPSink implements Sink {
}
}
/**
* @return the local port of the DatagramSocket we are sending from
*/
public int getPort() {
return this.sock.getLocalPort();
}
@ -60,9 +82,4 @@ public class UDPSink implements Sink {
public void stop() {
this.sock.close();
}
protected final DatagramSocket sock;
protected final InetAddress remoteHost;
protected final int remotePort;
}

View File

@ -13,6 +13,10 @@ import net.i2p.util.Log;
* @author welterde
*/
public class UDPSource implements Source, Runnable {
protected final DatagramSocket sock;
protected Sink sink;
protected final Thread thread;
private final int port;
public static final int MAX_SIZE = 15360;
/**
@ -25,7 +29,7 @@ public class UDPSource implements Source, Runnable {
} catch (IOException e) {
throw new RuntimeException("failed to listen...", e);
}
this.port = port;
// create thread
this.thread = new I2PAppThread(this);
}
@ -33,6 +37,7 @@ public class UDPSource implements Source, Runnable {
/** use socket from UDPSink */
public UDPSource(DatagramSocket sock) {
this.sock = sock;
port = sock.getLocalPort();
this.thread = new I2PAppThread(this);
}
@ -60,7 +65,7 @@ public class UDPSource implements Source, Runnable {
System.arraycopy(pack.getData(), 0, nbuf, 0, nbuf.length);
// transfer to sink
this.sink.send(null, nbuf);
this.sink.send(null, port, 0, nbuf);
//System.out.print("i");
} catch(Exception e) {
Log log = I2PAppContext.getGlobalContext().logManager().getLog(getClass());
@ -71,11 +76,15 @@ public class UDPSource implements Source, Runnable {
}
}
/**
* @return the local port of the DatagramSocket we are receiving on
* @since 0.9.53
*/
public int getPort() {
return port;
}
public void stop() {
this.sock.close();
}
protected final DatagramSocket sock;
protected Sink sink;
protected final Thread thread;
}

View File

@ -12,6 +12,7 @@ import net.i2p.client.I2PClient;
import net.i2p.client.I2PClientFactory;
import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionException;
import net.i2p.client.streaming.I2PSocketAddress;
import net.i2p.crypto.SigType;
import net.i2p.data.Destination;
import net.i2p.i2ptunnel.I2PTunnel;
@ -57,7 +58,6 @@ import net.i2p.util.EventDispatcher;
private final I2PSession _session;
private final Source _i2pSource;
private final Sink _i2pSink;
private final Destination _otherDest;
/**
* @throws IllegalArgumentException if the I2CP configuration is b0rked so
@ -103,19 +103,19 @@ import net.i2p.util.EventDispatcher;
throw new RuntimeException("failed to create session", exc);
}
// Setup the source. Always expect raw unverified datagrams.
_i2pSource = new I2PSource(_session, false, true);
// Setup the source. Handle both repliable and raw datagrams, on all ports.
_i2pSource = new I2PSource(_session, I2PSource.Protocol.BOTH);
// Setup the sink. Always send repliable datagrams.
if (destination != null && destination.length() > 0) {
_otherDest = _context.namingService().lookup(destination);
if (_otherDest == null) {
I2PSocketAddress addr = new I2PSocketAddress(destination);
if (addr.isUnresolved()) {
// unlike in I2PTunnelClient, we don't defer and retry resolution later
l.log("Could not resolve " + destination);
throw new RuntimeException("failed to create session - could not resolve " + destination);
}
_i2pSink = new I2PSink(_session, _otherDest, false);
}
_i2pSink = new I2PSink(_session, addr.getAddress(), false, addr.getPort());
} else {
_otherDest = null;
_i2pSink = new I2PSinkAnywhere(_session, false);
}
}
@ -178,10 +178,11 @@ import net.i2p.util.EventDispatcher;
* Sink Methods
*
* @param to - ignored if configured for a single destination
* (we use the dest specified in the constructor)
* (we use the dest specified in the constructor)
* @since 0.9.53 added fromPort and toPort parameters
* @throws RuntimeException if session is closed
*/
public void send(Destination to, byte[] data) {
_i2pSink.send(to, data);
public void send(Destination to, int fromPort, int toPort, byte[] data) {
_i2pSink.send(to, fromPort, toPort, data);
}
}

View File

@ -67,15 +67,14 @@ public class I2PTunnelUDPServerBase extends I2PTunnelTask implements Source, Sin
* badly that we cant create a socketManager
*
*/
public I2PTunnelUDPServerBase(boolean verify, File privkey, String privkeyname, Logging l,
public I2PTunnelUDPServerBase(File privkey, String privkeyname, Logging l,
EventDispatcher notifyThis, I2PTunnel tunnel) {
super("UDPServer <- " + privkeyname, notifyThis, tunnel);
_log = tunnel.getContext().logManager().getLog(I2PTunnelUDPServerBase.class);
FileInputStream fis = null;
try {
fis = new FileInputStream(privkey);
init(verify, fis, privkeyname, l);
init(fis, privkeyname, l);
} catch (IOException ioe) {
_log.error("Error starting server", ioe);
notifyEvent("openServerResult", "error");
@ -85,7 +84,7 @@ public class I2PTunnelUDPServerBase extends I2PTunnelTask implements Source, Sin
}
}
private void init(boolean verify, InputStream privData, String privkeyname, Logging l) {
private void init(InputStream privData, String privkeyname, Logging l) {
this.l = l;
// create i2pclient
@ -99,8 +98,8 @@ public class I2PTunnelUDPServerBase extends I2PTunnelTask implements Source, Sin
throw new RuntimeException("failed to create session", exc);
}
// Setup the source. Always expect repliable datagrams, optionally verify
_i2pSource = new I2PSource(_session, verify, false);
// Setup the source. Always expect repliable datagrams, listen on all ports.
_i2pSource = new I2PSource(_session, I2PSource.Protocol.REPLIABLE);
// Setup the sink. Always send raw datagrams.
_i2pSink = new I2PSinkAnywhere(_session, true);
@ -188,11 +187,12 @@ public class I2PTunnelUDPServerBase extends I2PTunnelTask implements Source, Sin
* Sink Methods
*
* @param to
* @since 0.9.53 added fromPort and toPort parameters
* @throws RuntimeException if session is closed
*
*/
public void send(Destination to, byte[] data) {
_i2pSink.send(to, data);
public void send(Destination to, int fromPort, int toPort, byte[] data) {
_i2pSink.send(to, fromPort, toPort, data);
}
}

View File

@ -4,16 +4,17 @@
# To contribute translations, see http://www.i2p2.de/newdevelopers
#
# Translators:
# タカハシ, 2022
# Masayuki Hatta <mhatta@mhatta.org>, 2018
# XMPPはいいぞ, 2021
# XMPPはいいぞ, 2021
# daingewuvzeevisiddfddd, 2021
# daingewuvzeevisiddfddd, 2021
msgid ""
msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-02-05 14:31+0000\n"
"PO-Revision-Date: 2021-05-14 01:18+0000\n"
"Last-Translator: XMPPはいいぞ\n"
"PO-Revision-Date: 2022-02-14 11:11+0000\n"
"Last-Translator: タカハシ\n"
"Language-Team: Japanese (http://www.transifex.com/otf/I2P/language/ja/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -554,7 +555,7 @@ msgid ""
"This address will be saved to your Local address book. Select this option "
"for addresses you wish to keep separate from the main router address book, "
"but don't mind publishing."
msgstr ""
msgstr "このアドレスはローカルのアドレス帳に保存されます。メインのルーターアドレス帳とは別に保管したいが、公開しても構わないアドレスに対してこのオプションを選択してください。"
#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:1478
#, java-format
@ -569,7 +570,7 @@ msgstr "このアドレスはプライベートなアドレス帳へ保存され
#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:1507
msgid "Base32 address requires lookup password"
msgstr ""
msgstr "Base32のアドレスにはルックアップパスワードが必要です"
#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:1509
msgid "Base32 address requires encryption key"
@ -577,7 +578,7 @@ msgstr "Base32 アドレスは暗号化鍵を要求します"
#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:1511
msgid "Base32 address requires encryption key and lookup password"
msgstr ""
msgstr "Base32のアドレスには暗号化キーとルックアップパスワードが必要です"
#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:1513
msgid "Base32 address decryption failure, check encryption key"
@ -611,7 +612,7 @@ msgstr "新しいDH暗号化鍵を生成"
#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:1541
msgid "Lookup password"
msgstr ""
msgstr "ルックアップパスワード"
#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:1542
msgid "You must enter the password provided by the server operator."
@ -628,7 +629,7 @@ msgstr "アドレスヘルパー経由で追加"
#: ../java/src/net/i2p/i2ptunnel/localServer/LocalHTTPServer.java:235
msgid "Missing lookup password"
msgstr ""
msgstr "ルックアップパスワードがありません"
#: ../java/src/net/i2p/i2ptunnel/localServer/LocalHTTPServer.java:249
msgid "Missing private key"

View File

@ -9,7 +9,7 @@
# cacapo <handelsehorisont@gmail.com>, 2015-2016
# hottuna <i2p@robertfoss.se>, 2013
# hottuna <i2p@robertfoss.se>, 2012
# Jonatan Nyberg <jonatan@autistici.org>, 2016-2017,2021
# Jonatan Nyberg <jonatan@autistici.org>, 2016-2017,2021-2022
# efef6ec5b435a041fce803c7f8af77d2_2341d43, 2019-2020
# efef6ec5b435a041fce803c7f8af77d2_2341d43, 2017
# WinterFairy <winterfairy@riseup.net>, 2014
@ -18,7 +18,7 @@ msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-02-05 14:31+0000\n"
"PO-Revision-Date: 2021-10-02 15:40+0000\n"
"PO-Revision-Date: 2022-01-14 17:57+0000\n"
"Last-Translator: Jonatan Nyberg <jonatan@autistici.org>\n"
"Language-Team: Swedish (Sweden) (http://www.transifex.com/otf/I2P/language/sv_SE/)\n"
"MIME-Version: 1.0\n"
@ -116,7 +116,7 @@ msgstr "Webbplatsen var inte nåbar."
msgid ""
"The website is offline, there is network congestion, or your router is not "
"yet well-integrated with peers."
msgstr "Webbplatsen är frånkopplad, nätverket är under stor belastning, eller din router är ännu inte välintegrerad med noder."
msgstr "Webbplatsen är frånkopplad, nätverket är under stor belastning, eller din router är ännu inte välintegrerad med jämlikar."
#: ../java/build/Proxy.java:14 ../java/build/Proxy.java:58
#: ../java/build/Proxy.java:109 ../java/build/Proxy.java:129
@ -205,7 +205,7 @@ msgstr "Varning: Ogiltigt Mål"
#: ../java/build/Proxy.java:47
msgid "The Base32 address is invalid."
msgstr ""
msgstr "Base32-adressen är ogiltig."
#: ../java/build/Proxy.java:56
msgid "The website was not reachable, because its lease set was not found."
@ -315,7 +315,7 @@ msgstr ""
msgid ""
"The website destination specified was not valid, or was otherwise "
"unreachable."
msgstr "Webbplatsens angivna destination var inte giltig, eller på annat sätt onåbar. "
msgstr "Den angivna webbplatsdestinationen var inte giltig eller på annat sätt onåbar."
#: ../java/build/Proxy.java:127
msgid ""
@ -335,7 +335,7 @@ msgstr "Varning: Ingen utproxy inställd"
msgid ""
"Your request was for a site outside of I2P, but you have no HTTP outproxy "
"configured."
msgstr "Din förfrågan var för en sida utanför I2P, men du har ingen HTTP utproxy inställd."
msgstr "Din förfrågan gällde en webbplats utanför I2P, men du har ingen HTTP-utproxy konfigurerad."
#: ../java/build/Proxy.java:139
msgid "Please configure an outproxy in I2PTunnel."
@ -362,7 +362,7 @@ msgid ""
"Resolve the conflict by deciding which key you trust, and then either ignore"
" the address helper link, or delete the host entry from your address book "
"and click the address helper link again."
msgstr "Lös konflikten genom att välja vilken nyckel du litar på. Sedan kan du antingen ignorera adressens hjälplänk eller radera posten från din adressbok och klicka på adressens hjälplänk igen. "
msgstr "Lös konflikten genom att bestämma vilken nyckel du litar på och ignorera sedan länken för adresshjälp eller ta bort värdposten från din adressbok och klicka på länken för adresshjälp igen."
#: ../java/build/Proxy.java:150 ../java/build/Proxy.java:156
msgid "Warning: Bad Address Helper"
@ -391,7 +391,7 @@ msgstr "HTTP-utproxyn hittades inte."
msgid ""
"It is offline, there is network congestion, or your router is not yet well-"
"integrated with peers."
msgstr "Den är antingen frånkopplad, nätverket är under stor belastning eller så är din router ännu inte väl integrerad med noder."
msgstr "Den är antingen frånkopplad, nätverket är under stor belastning eller så är din router ännu inte väl integrerad med jämlikar."
#: ../java/build/Proxy.java:172 ../java/build/Proxy.java:178
msgid "Warning: Request Denied"
@ -399,7 +399,7 @@ msgstr "Varning: Förfrågan Nekad"
#: ../java/build/Proxy.java:179
msgid "You attempted to connect to a non-I2P website or location."
msgstr "Du försökte ansluta till en icke-I2P webbplats eller plats."
msgstr "Du försökte ansluta till en icke-I2P-webbplats eller plats."
#: ../java/build/Proxy.java:180
msgid "Proxy Authorization Required"
@ -467,7 +467,7 @@ msgstr "HTTP-proxyn kunde inte nås eftersom den använder krypteringsinställni
#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:692
msgid "This seems to be a bad destination:"
msgstr "Detta verkar vara ett felaktigt mål"
msgstr "Det här verkar vara en dåligt destination:"
#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:693
msgid "i2paddresshelper cannot help you with a destination like that!"
@ -529,7 +529,7 @@ msgstr "Fortsätt utan att spara"
#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:1460
#, java-format
msgid "Save {0} to router address book and continue to website"
msgstr "Spara {0} till routerns adressbok och fortsätt till webbplatsen."
msgstr "Spara {0} i routerns adressbok och fortsätt till webbplatsen"
#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:1461
msgid ""
@ -565,7 +565,7 @@ msgstr ""
#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:1478
#, java-format
msgid "Save {0} to private address book and continue to website"
msgstr "Spara {0} till privata adressboken och fortsätt till webbplatsen."
msgstr "Spara {0} i den privata adressboken och fortsätt till webbplatsen"
#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:1479
msgid ""
@ -626,7 +626,7 @@ msgstr ""
#: ../java/src/net/i2p/i2ptunnel/localServer/LocalHTTPServer.java:196
#, java-format
msgid "Added via address helper from {0}"
msgstr "Tillagd via adresshjälpare från {0}"
msgstr "Tillagd via adresshjälp från {0}"
#: ../java/src/net/i2p/i2ptunnel/localServer/LocalHTTPServer.java:198
msgid "Added via address helper"
@ -701,7 +701,7 @@ msgstr ""
#: ../java/src/net/i2p/i2ptunnel/localServer/LocalHTTPServer.java:379
#: ../java/src/net/i2p/i2ptunnel/localServer/LocalHTTPServer.java:411
msgid "Click here if you are not redirected automatically."
msgstr "Klicka här om du inte omdirigeras automatiskt "
msgstr "Klicka här om du inte omdirigeras automatiskt."
#: ../java/src/net/i2p/i2ptunnel/localServer/LocalHTTPServer.java:409
#, java-format

View File

@ -4,7 +4,7 @@
# To contribute translations, see http://www.i2p2.de/newdevelopers
#
# Translators:
# Kaya Zeren <kayazeren@gmail.com>, 2016-2021
# Kaya Zeren <kayazeren@gmail.com>, 2016-2022
# Ozancan Karataş <ozancankaratas96@outlook.com>, 2015
# zzzi2p, 2018
msgid ""
@ -12,7 +12,7 @@ msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-02-05 14:31+0000\n"
"PO-Revision-Date: 2021-02-15 04:27+0000\n"
"PO-Revision-Date: 2022-02-03 06:12+0000\n"
"Last-Translator: Kaya Zeren <kayazeren@gmail.com>\n"
"Language-Team: Turkish (Turkey) (http://www.transifex.com/otf/I2P/language/tr_TR/)\n"
"MIME-Version: 1.0\n"
@ -443,7 +443,7 @@ msgstr "İstek kötü bir iletişim kuralı kullanıyor."
#: ../java/build/Proxy.java:205
msgid "The I2P HTTP Proxy supports HTTP and HTTPS requests only."
msgstr "I2P HTTP Vekil Sunucusu yalnız HTTP ve HTTPS isteklerini destekler."
msgstr "I2P HTTP Vekil Sunucusu yalnızca HTTP ve HTTPS isteklerini destekler."
#: ../java/build/Proxy.java:206
msgid "Other protocols such as FTP are not allowed."

View File

@ -4,17 +4,19 @@
# To contribute translations, see http://www.i2p2.de/newdevelopers
#
# Translators:
# daingewuvzeevisiddfddd, 2022
# タカハシ, 2013-2014
# タカハシ, 2022
# heizi <lv.kjsn.29yr@gmail.com>, 2016
# XMPPはいいぞ, 2020-2021
# XMPPはいいぞ, 2021
# daingewuvzeevisiddfddd, 2020-2021
# daingewuvzeevisiddfddd, 2021
msgid ""
msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-11-17 13:12+0000\n"
"PO-Revision-Date: 2021-11-17 13:34+0000\n"
"Last-Translator: abbbb bbbb <a1678991@gmail.com>\n"
"PO-Revision-Date: 2022-02-17 12:18+0000\n"
"Last-Translator: daingewuvzeevisiddfddd\n"
"Language-Team: Japanese (http://www.transifex.com/otf/I2P/language/ja/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -31,13 +33,13 @@ msgstr "内部"
#, java-format
msgid "{0} inbound tunnel"
msgid_plural "{0} inbound tunnels"
msgstr[0] ""
msgstr[0] "{0} 個の着信トンネル"
#: ../java/src/net/i2p/i2ptunnel/web/EditBean.java:547
#, java-format
msgid "{0} outbound tunnel"
msgid_plural "{0} outbound tunnels"
msgstr[0] ""
msgstr[0] "{0} 個の送信トンネル"
#: ../java/src/net/i2p/i2ptunnel/web/EditBean.java:549
#, java-format
@ -47,15 +49,15 @@ msgstr[0] "{0}個の着信、{0}個の送信トンネル"
#: ../java/src/net/i2p/i2ptunnel/web/EditBean.java:553
msgid "lower bandwidth and reliability"
msgstr "低い転送量だが低い信頼性"
msgstr "帯域幅も信頼性も低め"
#: ../java/src/net/i2p/i2ptunnel/web/EditBean.java:555
msgid "standard bandwidth and reliability"
msgstr "標準的な転送量と信頼性"
msgstr "帯域幅も信頼性も標準的"
#: ../java/src/net/i2p/i2ptunnel/web/EditBean.java:557
msgid "higher bandwidth and reliability"
msgstr "高い転送量だが高い信頼性"
msgstr "帯域幅も信頼性も高め"
#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:100
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/register_jsp.java:615
@ -602,13 +604,13 @@ msgstr "バックアップの回数"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1623
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1673
msgid "Number of Tunnels in Group"
msgstr ""
msgstr "グループ内のトンネルの数"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:641
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1627
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1677
msgid "Number of Reserve Tunnels"
msgstr ""
msgstr "予備トンネルの数"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:649
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:654
@ -671,12 +673,12 @@ msgstr "接続プロファイル"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:696
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2268
msgid "interactive connection"
msgstr ""
msgstr "双方向接続"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:700
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2272
msgid "bulk connection (downloads/websites/BT)"
msgstr ""
msgstr "バルク接続(ダウンロード/ウェブサイト/BT"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:702
msgid "Delay Connection"
@ -804,11 +806,11 @@ msgstr "ローカルの宛先"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:832
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1279
msgid "Read Only: Local Destination (if known)"
msgstr ""
msgstr "読み込み専用: ローカルの宛先 (知っていれば)"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:836
msgid "Local Base32"
msgstr ""
msgstr "ローカルのBase32"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:847
msgid "Tunnel Filtering Options"
@ -951,7 +953,7 @@ msgstr "アウトプロキシに必要なパスワードを入力してくださ
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1002
msgid "Tunnel Address Lookup Options"
msgstr ""
msgstr "トンネルアドレスのルックアップオプション"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1004
msgid "Jump URL List"
@ -1154,7 +1156,7 @@ msgstr "floodfillによるサーバー発見を防ぐ"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1768
msgid "Blinded"
msgstr ""
msgstr "ブラインド"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1774
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1799
@ -1164,39 +1166,39 @@ msgstr "全ユーザーへパスワードを送信する"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1778
msgid "Blinded with lookup password"
msgstr ""
msgstr "ルックアップパスワードでブラインド化"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1786
msgid "Send key and password to all users."
msgstr ""
msgstr "全ユーザーへキーとパスワードを送信する"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1790
msgid "Encrypted with lookup password"
msgstr ""
msgstr "ルックアップパスワードで暗号化済"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1792
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1798
msgid "Send individual key to each user."
msgstr ""
msgstr "各ユーザーにここのキーを送る"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1796
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1809
msgid "Encrypted with per-user key"
msgstr ""
msgstr "ユーザーごとのキーで暗号化"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1803
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1816
msgid "Encrypted with lookup password and per-user key"
msgstr ""
msgstr "ルックアップパスワードとユーザーごとのキーで暗号化"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1805
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1811
msgid "Enter key from each user."
msgstr ""
msgstr "各ユーザーからキーを入力"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1829
msgid "Optional lookup password"
msgstr ""
msgstr "任意のルックアップパスワード"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1844
msgid "Encryption Key"
@ -1231,7 +1233,7 @@ msgstr "追加"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2055
msgid "Recommended for blinded and encrypted destinations"
msgstr ""
msgstr "ブラインドかつ暗号化された宛先が推奨されます"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2097
msgid "Alternate private key file"
@ -1368,7 +1370,7 @@ msgstr "サーバースロットリング"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2300
msgid "Inbound connection limits"
msgstr ""
msgstr "総接続数制限"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2302
msgid "Per Minute"
@ -1389,7 +1391,7 @@ msgstr "クライアント毎"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2311
msgid "unlimited"
msgstr ""
msgstr "無制限"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2314
msgid ""
@ -1434,7 +1436,7 @@ msgstr "そのサーバーへアクセスが塞がれるまでの、1日毎の
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2340
msgid "Max concurrent connections"
msgstr ""
msgstr "最大接続数制限"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2342
msgid "Maximum number of simultaneous client connections"
@ -1446,11 +1448,11 @@ msgstr "投稿制限"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2352
msgid "Per Period"
msgstr ""
msgstr "一期間あたり"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2354
msgid "Ban Duration"
msgstr ""
msgstr "禁止期間"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2358
msgid ""
@ -1496,7 +1498,7 @@ msgstr "これらはルータが提供するローカルサービスです。"
msgid ""
"By default, most of your client services (email, HTTP proxy, IRC) will share"
" the same set of tunnels and be listed as \"Shared Clients\"."
msgstr "規定では、たいていのあなたのクライアントのサービスEメール、HTTPプロキシ、IRCトンネルのいくつかの組み合わせ共有し、\"共有クライアント\"であると一覧に記載されます。"
msgstr "規定では、たいていのあなたのクライアントのサービスEメール、HTTPプロキシ、IRCトンネルと同じ組み合わせ共有し、\"共有クライアント\"であると一覧に記載されます。"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:177
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/ssl_jsp.java:638
@ -1556,7 +1558,7 @@ msgstr "操作"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:241
msgid "Edit Server Tunnel Settings for"
msgstr ""
msgstr "次のサーバートンネル設定を編集"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:256
msgid "Test HTTPS server, bypassing I2P"
@ -1572,7 +1574,7 @@ msgstr "I2P 経由で HTTP サーバーをテスト"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:294
msgid "No Preview"
msgstr ""
msgstr "プレビューなし"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:304
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:307
@ -1669,12 +1671,12 @@ msgstr "インタフェース"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:479
msgid "Edit Tunnel Settings for"
msgstr ""
msgstr "次のトンネル設定の編集"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:531
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:534
msgid "Standby"
msgstr ""
msgstr "スタンバイ"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:589
msgid "Outproxy"
@ -1994,7 +1996,7 @@ msgstr "トンネルの宛先"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:226
msgid "Binding address and port"
msgstr ""
msgstr "バインドするアドレスとポート"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:232
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:711
@ -2264,11 +2266,11 @@ msgstr "以下は、あなたが選択した選択の概要です:"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:654
msgid "Tunnel description"
msgstr ""
msgstr "トンネル説明"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:680
msgid "Binding address"
msgstr ""
msgstr "バインドするアドレス"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:688
msgid "Tunnel port"
@ -2317,7 +2319,7 @@ msgstr "終了"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:779
msgid "Advance to next page"
msgstr ""
msgstr "次のページに進む"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:782
msgid "Next"

View File

@ -10,7 +10,7 @@
# cacapo <handelsehorisont@gmail.com>, 2015
# hottuna <i2p@robertfoss.se>, 2013
# hottuna <i2p@robertfoss.se>, 2012
# Jonatan Nyberg <jonatan@autistici.org>, 2016-2017,2021
# Jonatan Nyberg <jonatan@autistici.org>, 2016-2017,2021-2022
# efef6ec5b435a041fce803c7f8af77d2_2341d43, 2018-2020
# efef6ec5b435a041fce803c7f8af77d2_2341d43, 2017
# Martin Svensson <digitalmannen@gmail.com>, 2011-2012
@ -19,8 +19,8 @@ msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-11-17 13:12+0000\n"
"PO-Revision-Date: 2021-11-17 13:34+0000\n"
"Last-Translator: cacapo <handelsehorisont@gmail.com>\n"
"PO-Revision-Date: 2022-01-22 09:36+0000\n"
"Last-Translator: Jonatan Nyberg <jonatan@autistici.org>\n"
"Language-Team: Swedish (Sweden) (http://www.transifex.com/otf/I2P/language/sv_SE/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -37,15 +37,15 @@ msgstr "intern"
#, java-format
msgid "{0} inbound tunnel"
msgid_plural "{0} inbound tunnels"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "{0} inkommande tunnel"
msgstr[1] "{0} inkommande tunnlar"
#: ../java/src/net/i2p/i2ptunnel/web/EditBean.java:547
#, java-format
msgid "{0} outbound tunnel"
msgid_plural "{0} outbound tunnels"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "{0} utgående tunnel"
msgstr[1] "{0} utgående tunnlar"
#: ../java/src/net/i2p/i2ptunnel/web/EditBean.java:549
#, java-format
@ -200,7 +200,7 @@ msgstr "Redigera dold tjänst"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:184
msgid "Are you sure you want to delete?"
msgstr ""
msgstr "Är du säker att du vill ta bort?"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:208
msgid "Edit proxy settings"
@ -231,7 +231,7 @@ msgstr "Typ"
msgid ""
"Name of tunnel to be displayed on Tunnel Manager home page and the router "
"console sidebar"
msgstr ""
msgstr "Namnet på tunneln som ska visas på tunnelhanterarens hemsida och routerkonsolens sidofält"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:270
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1123
@ -250,7 +250,7 @@ msgstr "Starta tunnel automatiskt"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1127
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:383
msgid "Description of tunnel to be displayed on Tunnel Manager home page"
msgstr ""
msgstr "Beskrivning av tunneln som ska visas på tunnelhanterarens hemsida"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:278
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1131
@ -258,7 +258,7 @@ msgstr ""
msgid ""
"Enable this option to ensure this service is available when the router "
"starts"
msgstr ""
msgstr "Aktivera det här alternativet för att säkerställa att den här tjänsten är tillgänglig när routern startar"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:282
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1135
@ -270,11 +270,11 @@ msgstr "Starta tunneln automatiskt när routern startar"
msgid ""
"The client tunnel and all other shared client tunnels must be stopped to "
"change this setting"
msgstr ""
msgstr "Klienttunneln och alla andra delade klienttunnlar måste stoppas för att ändra denna inställning"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:287
msgid "The client tunnel must be stopped to change this setting"
msgstr ""
msgstr "Klienttunneln måste stoppas för att ändra denna inställning"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:301
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1154
@ -330,7 +330,7 @@ msgstr "Värdnamn eller IP-adress för servern"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:347
msgid "Local interface (ip address) the client tunnel will be reachable from"
msgstr ""
msgstr "Lokalt gränssnitt (ip-adress) klienttunneln kommer att vara tillgänglig från"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:351
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1229
@ -348,7 +348,7 @@ msgid ""
"If you are accessing a service on a remote I2P router, you may wish to "
"connect with SSL to avoid traffic interception. The client application "
"should be also be configured to use SSL."
msgstr ""
msgstr "Om du använder en tjänst på en fjärransluten I2P-router, kanske du vill ansluta med SSL för att undvika trafikavlyssning. Klientapplikationen bör också konfigureras för att använda SSL."
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:386
msgid "Clients use SSL to connect to tunnel"
@ -357,13 +357,13 @@ msgstr "Klienter använder SSL för att ansluta till tunneln"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:394
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:411
msgid "Outproxies"
msgstr "Utgående proxier"
msgstr "Utproxier"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:396
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:408
msgid ""
"Specify the .i2p address or destination (b32 or b64) of the outproxy here."
msgstr ""
msgstr "Ange .i2p-adressen eller destinationen (b32 eller b64) för utproxyn här."
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:398
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:410
@ -385,7 +385,7 @@ msgstr "Använd Outproxy-insticksmodul"
msgid ""
"If an outproxy plugin is installed (e.g. Orchid), use this instead of any "
"configured outproxies to access websites outside of I2P"
msgstr ""
msgstr "Om en utproxyinsticksmodul är installerad (t.ex. Orchid), använd denna istället för alla konfigurerade utproxier för att komma åt webbplatser utanför I2P"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:424
msgid "Use plugin instead of above-listed proxies if available"
@ -420,11 +420,11 @@ msgid ""
"Traffic from all clients with this feature enabled will be routed over the "
"same set of tunnels. This will make profiling the tunnels by an adversary "
"more difficult, but will link the clients together."
msgstr ""
msgstr "Trafik från alla klienter med denna funktion aktiverad kommer att dirigeras över samma uppsättning tunnlar. Detta kommer att göra det svårare att profilera tunnlarna av en motståndare, men kommer att länka samman klienterna."
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:481
msgid "Share tunnels with other clients?"
msgstr ""
msgstr "Dela tunnlar med andra klienter?"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:499
msgid "Enable DCC"
@ -438,7 +438,7 @@ msgstr "Aktiverar direktchatt och filöverföringar, förbigår I2P"
msgid ""
"Enable Direct Client-to-Client protocol. Note that this will compromise your"
" anonymity and is <i>not</i> recommended."
msgstr ""
msgstr "Aktivera direkt klient-till-klient-protokoll. Observera att detta äventyrar din anonymitet och rekommenderas <i>inte</i>."
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:511
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1403
@ -449,12 +449,12 @@ msgstr "Avancerade nätverksalternativ"
msgid ""
"Note: When this client proxy is configured to share tunnels, then these "
"options are for all the shared proxy clients!"
msgstr ""
msgstr "Obs: När denna klientproxy är konfigurerad att dela tunnlar, är dessa alternativ för alla delade proxyklienter!"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:525
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1405
msgid "Tunnel Length Options"
msgstr ""
msgstr "Alternativ för tunnellängd"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:527
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1416
@ -503,87 +503,87 @@ msgstr "Längd på varje tunnel"
#, java-format
msgid "{0} hop tunnel"
msgid_plural "{0} hop tunnel"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "{0} hopptunnel"
msgstr[1] "{0} hopptunnlar"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:540
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1428
msgid "no anonymity"
msgstr ""
msgstr "ingen anonymitet"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:545
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1433
msgid "low anonymity"
msgstr ""
msgstr "låg anonymitet"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:550
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1438
msgid "medium anonymity"
msgstr ""
msgstr "medium anonymitet"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:555
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1443
msgid "high anonymity"
msgstr ""
msgstr "hög anonymitet"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:587
msgid "Level of Randomization for Tunnel Length"
msgstr ""
msgstr "Randomiseringsnivå för tunnellängd"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:594
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1481
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1572
msgid "0 hop variance"
msgstr ""
msgstr "0 hoppvarians"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:595
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1482
msgid "no randomization, consistent performance"
msgstr ""
msgstr "ingen randomisering, konsekvent prestanda"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:599
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1486
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1576
msgid "+ 0-1 hop variance"
msgstr ""
msgstr "+ 0-1 hoppvariation"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:600
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1487
msgid "medium randomization, lower performance"
msgstr ""
msgstr "medium randomisering, lägre prestanda"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:604
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1491
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1580
msgid "+ 0-2 hop variance"
msgstr ""
msgstr "+ 0-2 hoppvarians"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:605
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1492
msgid "high randomization, very low performance"
msgstr ""
msgstr "hög randomisering, mycket låg prestanda"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:609
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1496
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1584
msgid "+/- 0-1 hop variance"
msgstr ""
msgstr "+/- 0-1 hoppvarians"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:610
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1497
msgid "standard randomization, standard performance"
msgstr ""
msgstr "standard randomisering, standardprestanda"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:614
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1501
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1588
msgid "+/- 0-2 hop variance"
msgstr ""
msgstr "+/- 0-2 hoppvarians"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:615
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1502
msgid "not recommended"
msgstr ""
msgstr "rekommenderas inte"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:626
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1513
@ -594,7 +594,7 @@ msgstr "hoppvariation"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:631
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1608
msgid "Tunnel Quantity Options"
msgstr ""
msgstr "Alternativ för tunnelkvantitet"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:633
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1619
@ -612,13 +612,13 @@ msgstr "Antal reserver"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1623
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1673
msgid "Number of Tunnels in Group"
msgstr ""
msgstr "Antal tunnlar i grupp"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:641
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1627
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1677
msgid "Number of Reserve Tunnels"
msgstr ""
msgstr "Antal reservtunnlar"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:649
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:654
@ -638,32 +638,32 @@ msgstr ""
#, java-format
msgid "{0} backup tunnel"
msgid_plural "{0} backup tunnels"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "{0} reservtunnel"
msgstr[1] "{0} reservtunnlar"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:650
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1635
msgid "no redundancy, no added resource usage"
msgstr ""
msgstr "ingen redundans, ingen extra resursanvändning"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:655
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1640
msgid "low redundancy, low resource usage"
msgstr ""
msgstr "låg redundans, låg resursanvändning"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:660
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1645
msgid "medium redundancy, medium resource usage"
msgstr ""
msgstr "medelhög redundans, medelhög resursanvändning"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:665
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1650
msgid "high redundancy, high resource usage"
msgstr ""
msgstr "hög redundans, hög resursanvändning"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:679
msgid "Tunnel Management Options"
msgstr ""
msgstr "Alternativ för tunnelhantering"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:685
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2259
@ -677,7 +677,7 @@ msgstr "Fördröj anslutning"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:689
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2261
msgid "Connection Profile"
msgstr ""
msgstr "Anslutningsprofil"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:696
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2268
@ -691,7 +691,7 @@ msgstr "massanslutning (hämtningar/webbplatser/BT)"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:702
msgid "Delay Connection"
msgstr ""
msgstr "Fördröj anslutning"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:706
msgid "for request/response connections"
@ -703,13 +703,13 @@ msgstr "Avvakta med att öppna tunnlar tills de behövs"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:720
msgid "Conserve resources by only creating tunnels when required"
msgstr ""
msgstr "Spara resurser genom att bara skapa tunnlar när det behövs"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:724
msgid ""
"Delay opening client tunnel until activity is detected on the configured "
"tunnel port"
msgstr ""
msgstr "Fördröj att öppna klienttunneln tills aktivitet upptäcks på den konfigurerade tunnelporten"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:730
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2278
@ -725,13 +725,13 @@ msgstr ""
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:736
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2282
msgid "Reduce tunnel quantity when idle to conserve resources"
msgstr ""
msgstr "Minska tunnelkvantiteten vid inaktivitet för att spara resurser"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:738
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:740
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2284
msgid "Reduced tunnel count"
msgstr "Minskat antal tunnlar"
msgstr "Minskat tunnelantal"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:744
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:758
@ -1014,7 +1014,7 @@ msgstr "Ta bort den här proxyn (kan inte ångras)"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1047
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2423
msgid "Delete"
msgstr "Radera"
msgstr "Ta bort"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1049
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2425
@ -1108,7 +1108,7 @@ msgstr ""
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1377
msgid "HTTPS configuration"
msgstr ""
msgstr "HTTPS-konfiguration"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:1382
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/ssl_jsp.java:215
@ -1340,7 +1340,7 @@ msgstr "kommaseparerad t.ex. Mozilla,Opera (skiftlägeskänslig)"
msgid ""
"Use unique IP addresses for each connecting client (local non-SSL servers "
"only)"
msgstr ""
msgstr "Använd unika IP-adresser för varje anslutande klient (endast lokala icke-SSL-servrar)"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2245
msgid "Unique Local Address per Client"
@ -1524,11 +1524,11 @@ msgstr "Rensa"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:203
msgid "Global Tunnel Control"
msgstr ""
msgstr "Global tunnelkontroll"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:205
msgid "Tunnel Wizard"
msgstr "Tunnel guide"
msgstr "Tunnelguide"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:209
msgid "Stop All"
@ -1548,7 +1548,7 @@ msgstr "Dolda I2P-tjänster"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:226
msgid "Points at"
msgstr "Pekar på"
msgstr "Hänvisar till"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:228
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:289
@ -1611,7 +1611,7 @@ msgstr "Stoppa"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:548
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:551
msgid "Running"
msgstr "Kör"
msgstr "Körs"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:342
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:345
@ -1916,7 +1916,7 @@ msgstr ""
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/ssl_jsp.java:708
msgid "I2P Port"
msgstr ""
msgstr "I2P-port"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/ssl_jsp.java:710
msgid "Virtual Host"
@ -1925,7 +1925,7 @@ msgstr ""
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/ssl_jsp.java:712
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/ssl_jsp.java:790
msgid "SSL"
msgstr ""
msgstr "SSL"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/ssl_jsp.java:714
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/ssl_jsp.java:784
@ -1982,12 +1982,12 @@ msgstr ""
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:190
msgid "I2P Tunnel Manager - Tunnel Creation Wizard"
msgstr "I2P-tunnelhanterare - Guide för skapande av tunnlar "
msgstr "I2P-tunnelhanterare - Guide för skapande av tunnlar"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:202
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:625
msgid "Server or client tunnel?"
msgstr "Server- eller klient-tunnel"
msgstr "Server eller klienttunnel?"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:208
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:629
@ -1996,7 +1996,7 @@ msgstr "Tunnel typ"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:214
msgid "Tunnel name and description"
msgstr "Tunnelnamn och beskrivning "
msgstr "Tunnelnamn och beskrivning"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:220
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:661
@ -2014,7 +2014,7 @@ msgstr "Tunnel auto-start"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:238
msgid "Wizard completed"
msgstr "Guiden färdig "
msgstr "Guiden färdig"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:252
msgid ""
@ -2026,13 +2026,13 @@ msgstr "Guiden tar dig igenom de olika inställningsmöjligheterna för att skap
msgid ""
"The first thing to decide is whether you want to create a server or a client"
" tunnel."
msgstr "Det första är att bestämma om det skall vara en server- eller klient-tunnel. "
msgstr "Det första du ska bestämma är om du vill skapa en server eller en klienttunnel."
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:256
msgid ""
"If you need to connect to a remote service, such as an IRC server inside I2P"
" or a code repository, then you will require a CLIENT tunnel."
msgstr "Om du behöver ansluta till en fjärrtjänst, till exempel en IRC-server inuti I2P eller ett kodförråd, behöver du en KLIENT-tunnel."
msgstr "Om du behöver ansluta till en fjärrtjänst, till exempel en IRC-server inom I2P eller ett kodförråd, behöver du en KLIENT-tunnel."
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:258
msgid ""
@ -2046,7 +2046,7 @@ msgstr "Server-tunnel"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:262
msgid "Client Tunnel"
msgstr "Klient-tunnel"
msgstr "Klienttunnel"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:280
msgid "There are several types of tunnels to choose from:"
@ -2054,7 +2054,7 @@ msgstr "Det finns flera typer av tunnlar att välja mellan:"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:288
msgid "Basic tunnel for connecting to a single service inside I2P."
msgstr "Grundläggande tunnel för anslutning till en enskild tjänst innanför I2P. "
msgstr "Grundläggande tunnel för anslutning till en enskild tjänst inom I2P."
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:290
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:324
@ -2094,7 +2094,7 @@ msgstr "Med denna tunneltyp kan din IRC-klient ansluta till ett IRC-nätverk i I
msgid ""
"Each IRC network in I2P that you wish to connect to will require its own "
"tunnel. (See Also, SOCKS IRC)"
msgstr "Varje IRC-nätverk inom I2P som du vill ansluta till kräver en egen tunnel (Se även: SOCKS IRC) "
msgstr "Varje IRC-nätverk inom I2P som du vill ansluta till kräver en egen tunnel (Se även: SOCKS IRC)"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:304
msgid "A tunnel that implements the SOCKS protocol."
@ -2104,7 +2104,7 @@ msgstr "En tunnel som implementerar SOCKS protokollet."
msgid ""
"This enables both TCP and UDP connections to be made through a SOCKS "
"outproxy within I2P."
msgstr "Detta möjliggör både TCP och UDP anslutningar genom SOCKS utproxy innanför I2P "
msgstr "Detta möjliggör både TCP- och UDP-anslutningar kan göras genom en SOCKS-utproxy inom I2P."
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:308
msgid ""
@ -2134,7 +2134,7 @@ msgstr "IRC-nätverk utanför I2P kan nås om en SOCKS-proxy innanför I2P är k
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:322
msgid "A basic server tunnel for hosting a generic service inside I2P."
msgstr "En server-tunnel för en godtycklig tjänst innanför I2P."
msgstr "En server-tunnel för en godtycklig tjänst inom I2P."
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:326
msgid "A server tunnel that is customized for HTTP connections."
@ -2152,7 +2152,7 @@ msgstr ""
msgid ""
"Usually, a separate tunnel needs to be created for each IRC server that is "
"to be accessible inside I2P."
msgstr "Vanligtvis behövs en separat tunnel för varje IRC-server som skall anslutas till innanför I2P."
msgstr "Vanligtvis behövs en separat tunnel för varje IRC-server som skall anslutas till inom I2P."
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:338
msgid "Select tunnel type"
@ -2166,7 +2166,7 @@ msgstr "Välj namn och beskrivning av tunneln."
msgid ""
"These can be anything you want - they are just for ease of identifying the "
"tunnel in the routerconsole."
msgstr "Kan vara vad som helst, används enbart för att enkelt identifiera tunneln i routerkonsolen "
msgstr "Dessa kan vara vad du vill - de är bara för att underlätta identifiering av tunneln i routerkonsolen."
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:407
msgid ""
@ -2204,7 +2204,7 @@ msgstr ""
msgid ""
"This is the IP that your service is running on, this is usually on the same "
"machine so 127.0.0.1 is autofilled."
msgstr "Detta är IP-adressen som tjänsten körs på, detta är vanligtvis på samma maskin så 127.0.0.1 fylls i automatiskt. "
msgstr "Detta är IP-adressen som din tjänst körs på, den är vanligtvis på samma maskin så 127.0.0.1 fylls i automatiskt."
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:485
msgid "This is the port that the service is accepting connections on."
@ -2212,13 +2212,13 @@ msgstr "Porten som tjänsten accepterar anslutningar via."
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:508
msgid "This is the port that the client tunnel will be accessed from locally."
msgstr "Porten som klient-tunneln kommer att ansluta till lokalt."
msgstr "Porten som klienttunneln kommer att ansluta från lokalt."
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:531
msgid ""
"How do you want this tunnel to be accessed? By just this machine, your "
"entire subnet, or external internet?"
msgstr "Hur du vill att tunneln ska nås? Enbart denna maskinen, ditt lokala nät eller hela internet? "
msgstr "Hur vill du att den här tunneln ska nås? Med bara den här maskinen, hela ditt undernät eller externt internet?"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:533
msgid "You will most likely want to just allow 127.0.0.1"
@ -2239,7 +2239,7 @@ msgstr ""
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:604
msgid "The wizard has now collected enough information to create your tunnel."
msgstr "Guiden har samlat tillräckligt med information för att skapa tunneln. "
msgstr "Guiden har nu samlat tillräckligt med information för att skapa din tunnel."
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:606
msgid ""
@ -2251,11 +2251,11 @@ msgstr "När du klickar på \"spara\" kommer guiden att skapa tunneln och sedan
msgid ""
"Because you chose to automatically start the tunnel when the router starts, "
"you don't have to do anything further."
msgstr "Efter som du valt att starta tunneln samtidigt som routern startas behövs inget mer göras. "
msgstr "Eftersom du valde att automatiskt starta tunneln när routern startar behöver du inte göra något mer."
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:613
msgid "The router will start the tunnel once it has been set up."
msgstr "Routern startar tunneln när den skapats. "
msgstr "Routern startar tunneln när den har ställts in."
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:617
msgid ""
@ -2289,7 +2289,7 @@ msgstr ""
msgid ""
"Alongside these basic settings, there are a number of advanced options for "
"tunnel configuration."
msgstr "Vid sidan om dessa grundlägande inställningar finns att par avancerade val för tunneln. "
msgstr "Utöver dessa grundinställningar finns det ett antal avancerade alternativ för tunnelkonfiguration."
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:724
msgid ""

View File

@ -4,7 +4,7 @@
# To contribute translations, see http://www.i2p2.de/newdevelopers
#
# Translators:
# Kaya Zeren <kayazeren@gmail.com>, 2016-2021
# Kaya Zeren <kayazeren@gmail.com>, 2016-2022
# Mustafa Berk Çörtoğlu <mbcortoglu@gmail.com>, 2017
# Ozancan Karataş <ozancankaratas96@outlook.com>, 2015
msgid ""
@ -12,7 +12,7 @@ msgstr ""
"Project-Id-Version: I2P\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-11-17 13:12+0000\n"
"PO-Revision-Date: 2021-11-20 07:52+0000\n"
"PO-Revision-Date: 2022-02-03 06:28+0000\n"
"Last-Translator: Kaya Zeren <kayazeren@gmail.com>\n"
"Language-Team: Turkish (Turkey) (http://www.transifex.com/otf/I2P/language/tr_TR/)\n"
"MIME-Version: 1.0\n"
@ -696,7 +696,7 @@ msgstr "Gerekene kadar tünel açılması geciktirilsin"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:720
msgid "Conserve resources by only creating tunnels when required"
msgstr "Bu seçenek etkinleştirildiğinde, tüneller yalnız gerektiğinde açılarak kaynaklar korunur"
msgstr "Bu seçenek etkinleştirildiğinde, tüneller yalnızca gerektiğinde açılarak kaynaklar korunur"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:724
msgid ""
@ -1267,7 +1267,7 @@ msgstr "Reddedilenler Listesi"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2188
msgid "Only allow listed clients to connect to this service"
msgstr "Yalnız listedeki istemciler bu hizmete bağlanabilsin"
msgstr "Yalnızca listedeki istemciler bu hizmete bağlanabilsin"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2192
msgid "Allow List"
@ -1333,7 +1333,7 @@ msgstr "virgül ile ayırarak yazın. Örnek: Mozilla,Opera (büyük küçük ha
msgid ""
"Use unique IP addresses for each connecting client (local non-SSL servers "
"only)"
msgstr "Bağlanan her istemci için benzersiz IP adresi kullanılsın (yalnız yerel ve SSL olmayan sunucular)"
msgstr "Bağlanan her istemci için benzersiz IP adresi kullanılsın (yalnızca yerel ve SSL olmayan sunucular)"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2245
msgid "Unique Local Address per Client"
@ -1341,7 +1341,7 @@ msgstr "Her İstemci için Benzersiz Yerel Adres"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2247
msgid "Only enable if you are hosting this service on multiple routers"
msgstr "Bu seçeneği yalnız bu hizmeti birden çok yöneltici üzerinden sunuyorsanız etkinleştirin"
msgstr "Bu seçeneği yalnızca bu hizmeti birden çok yöneltici üzerinden sunuyorsanız etkinleştirin"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/edit_jsp.java:2251
msgid "Optimize for Multihoming"
@ -1865,7 +1865,7 @@ msgstr "Eski adı ve hedefi belirtin"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/register_jsp.java:584
msgid "This is only required for advanced authentication."
msgstr "Bu seçenek yalnız gelişmiş kimlik doğrulama için gereklidir."
msgstr "Bu seçenek yalnızca gelişmiş kimlik doğrulaması için gereklidir."
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/register_jsp.java:586
msgid "See above for required items."
@ -1893,7 +1893,7 @@ msgstr "SSL Yardımcısı"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/ssl_jsp.java:653
msgid "Experts only!"
msgstr "Yalnız deneyimli kullanıcılar!"
msgstr "Yalnızca deneyimli kullanıcılar!"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/ssl_jsp.java:689
msgid "Base32"
@ -2211,11 +2211,11 @@ msgstr "İstemci tüneline yerel olarak erişilebilecek kapı numarası."
msgid ""
"How do you want this tunnel to be accessed? By just this machine, your "
"entire subnet, or external internet?"
msgstr "Bu tünele nasıl erişilmesini istiyorsunuz? Yalnız bu bilgisayar üzerinden, tüm alt ağınızdan ya da dış İnternet üzerinden?"
msgstr "Bu tünele nasıl erişilmesini istiyorsunuz? Yalnızca bu bilgisayar üzerinden, tüm alt ağınızdan ya da dış İnternet üzerinden?"
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:533
msgid "You will most likely want to just allow 127.0.0.1"
msgstr "Büyük olasılıkla yalnız 127.0.0.1 adresine izin vermek isteyeceksiniz."
msgstr "Büyük olasılıkla yalnızca 127.0.0.1 adresine izin vermek isteyeceksiniz."
#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/wizard_jsp.java:576
msgid ""

View File

@ -1,4 +1,3 @@
body {
margin: 5px 0px 0px;
padding: 0px;
@ -15,6 +14,30 @@ body {
background-repeat: initial initial;
}
h4 {
display: inherit;
}
#jumplinks h4 {
padding-bottom: 10px;
margin-bottom: 10px;
}
#jumplinks a {
display: inline-block;
padding: 2px 0;
line-height: 16px;
}
#jumplinks a::before {
content: "\279F\00A0";
font-size: 16pt;
display: inline-block;
padding: 3px 0;
vertical-align: sub;
line-height: 16px;
}
img {
border: none;
}
@ -211,7 +234,6 @@ hr:last-child {
background-size: 54px, 100%;
background-position: 10px calc(50% + 32px);
background-repeat: no-repeat;
background-image: url(/themes/console/images/itoopie_sm.png);
}
.warning h3 {
@ -220,12 +242,15 @@ hr:last-child {
font-size: 1.1rem;
}
#jumplinks {
text-align: start;
}
@media only screen and (max-width: 600px) {
/*body {
#jumplinks > a {
border: black;
}*/
#jumplinks {
text-align: start;
}
#jumplinks>a {
border: black;
border-top-style: none;
border-top-width: medium;
border-right-style: none;
@ -234,31 +259,30 @@ hr:last-child {
border-bottom-width: medium;
border-left-style: none;
border-left-width: medium;
border-style: outset;
margin: 2px;
float: none;
display: inline-block;
width: 96%;
border-width: 1px;
border-radius: 12px;
vertical-align: middle;
font-size: 1.1rem;
text-align: start;
padding-top: 1.5%;
padding-bottom: 1.5%;
padding-left: 1%;
}
#jumplinks > a:hover {
text-decoration: none;
color: #da736b !important;
border: 1px solid #da736b !important;
box-shadow: inset 0 1px 1px 0 #eff;
}
#jumplinks > h4 {
text-align: left;
font-size: 1.1rem;
border-style: outset;
margin: 2px;
float: none;
display: inline-block;
width: 96%;
border-width: 1px;
border-radius: 12px;
vertical-align: middle;
font-size: 1.1rem;
text-align: start;
padding-top: 1.5%;
padding-bottom: 1.5%;
padding-left: 1%;
}
#jumplinks>a:hover {
text-decoration: none;
color: #da736b !important;
border: 1px solid #da736b !important;
box-shadow: inset 0 1px 1px 0 #eff;
}
#jumplinks>h4 {
text-align: left;
font-size: 1.1rem;
}
}
element {
@ -282,5 +306,4 @@ td {
h1 {
margin-left: 242px !important;
}
}
}

View File

@ -1,5 +1,3 @@
html {
margin: 0px !important;
}
@ -15,6 +13,57 @@ body {
background-repeat: initial initial;
}
button {
color: rgb(59, 107, 191);
border: none;
background: none !important;
cursor: pointer;
text-align: left;
display: inline;
}
.unicodeicon {
font-size: 16pt;
display: inline-block;
padding: 3px 0;
vertical-align: sub;
line-height: 16px;
font-weight: bold;
text-shadow: rgb(255, 255, 255) 0px 1px 1px;
}
#jumplinks h3 {
margin: 0 0 10px;
}
#jumplinks a {
display: block;
padding: 2px 0;
line-height: 16px;
}
#jumplinks a::before {
content: "\279F\00A0";
font-size: 16pt;
display: inline-block;
padding: 3px 0;
vertical-align: sub;
line-height: 16px;
}
@media screen and (min-width: 1400px) {
#jumplinks h4 {
font-size: 10.5pt;
}
}
#jumplinks h4 {
margin-bottom: 10px;
border-color: #7778bf !important;
color: #41465f;
padding-bottom: 10px;
}
b {
color: rgb(65, 70, 95);
}
@ -23,6 +72,10 @@ body {
font-family: 'Droid Sans', 'Noto Sans', Ubuntu, 'Segoe UI', 'Lucida Grande', Verdana, Helvetica, sans-serif;
}
h4 {
display: inherit;
}
* {
outline: none;
}
@ -31,6 +84,15 @@ img {
border: none;
}
td:nth-child(1) {
font-weight: bold;
}
.formaction button p {
display: block;
color: rgb(34, 34, 34);
}
.logo {
float: left;
padding: 10px;
@ -88,7 +150,7 @@ img {
}
.warning:not(old) {
background-image: url(/themes/console/images/itoopie_sm.png), linear-gradient(rgba(248, 248, 255, 0.8), rgba(240, 240, 255, 0.8));
background: linear-gradient(rgba(248, 248, 255, 0.8), rgba(240, 240, 255, 0.8));
background-attachment: scroll, initial;
background-origin: initial, initial;
background-clip: initial, initial;
@ -111,6 +173,10 @@ img {
}
@media screen and (max-width: 800px) {
.formaction button p {
display: inline-block;
color: rgb(34, 34, 34);
}
.warning {
margin: 114px 5px 0px !important;
background-image: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.298039)) !important;
@ -217,24 +283,34 @@ h3 {
}
.hostadd {
height: 10rem;
width: 100%;
border-radius: 12px;
background: #eef;
}
.hostaddform {
width: 48%;
width: 100%;
display: inline-block;
vertical-align: top;
}
#jumplinks {
text-align: start;
}
#jumplinks > a {
border: black;
@media only screen and (max-width: 600px) {
.hostadd {
height: 10rem;
width: 100%;
border-radius: 12px;
background: #eef;
}
.hostaddform {
width: 48%;
display: inline-block;
vertical-align: top;
}
#jumplinks {
text-align: start;
}
#jumplinks>a {
border: black;
border-top-style: none;
border-top-width: medium;
border-right-style: none;
@ -243,38 +319,36 @@ h3 {
border-bottom-width: medium;
border-left-style: none;
border-left-width: medium;
border-style: outset;
margin: 2px;
float: none;
display: inline-block;
width: 96%;
border-width: 1px;
border-radius: 12px;
vertical-align: middle;
font-size: 1.1rem;
text-align: start;
padding-top: 1.5%;
padding-bottom: 1.5%;
padding-left: 1%;
background: #ddd;
background: linear-gradient(to bottom, #eee, #fff);
}
#jumplinks > a:hover {
text-decoration: none;
color: #19191f;
border: 1px solid #f60 !important;
background: #ddd;
background: linear-gradient(to bottom, #eee, #fff);
box-shadow: inset 0 0 0 1px #fff !important;
filter: drop-shadow(0 0 1px rgba(204, 204, 204, 0.8));
transition: ease border 0.7s;
}
#jumplinks > h4 {
text-align: left;
font-size: 1.1rem;
border-style: outset;
margin: 2px;
float: none;
display: inline-block;
width: 96%;
border-width: 1px;
border-radius: 12px;
vertical-align: middle;
font-size: 1.1rem;
text-align: start;
padding-top: 1.5%;
padding-bottom: 1.5%;
padding-left: 1%;
background: #ddd;
background: linear-gradient(to bottom, #eee, #fff);
}
#jumplinks>a:hover {
text-decoration: none;
color: #19191f;
border: 1px solid #f60 !important;
background: #ddd;
background: linear-gradient(to bottom, #eee, #fff);
box-shadow: inset 0 0 0 1px #fff !important;
filter: drop-shadow(0 0 1px rgba(204, 204, 204, 0.8));
transition: ease border 0.7s;
}
#jumplinks>h4 {
text-align: left;
font-size: 1.1rem;
}
}
element {
@ -301,5 +375,4 @@ td {
body {
font-size: 10pt !important;
}
}
}

View File

@ -5,5 +5,5 @@ log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
log4j.appender.stdout.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m{nolookups}%n

View File

@ -39,6 +39,7 @@ fi
# router/ now has its own bundle for some files
ROUTERFILES="\
../../../router/java/src/net/i2p/router/Blocklist.java \
../../../router/java/src/net/i2p/router/Router.java \
../../../router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java \
../../../router/java/src/net/i2p/router/sybil/Analysis.java \
../../../router/java/src/net/i2p/router/tasks/CoalesceStatsEvent.java \

View File

@ -207,8 +207,8 @@ public class BlocklistEntries {
if (br != null) try { br.close(); } catch (IOException ioe) {}
}
if (elist.isEmpty() && rlist.isEmpty()) {
System.err.println("nothing to sign");
System.exit(1);
System.err.println("Signing empty blocklist");
//System.exit(1);
}
if (elist.size() > MAX_ENTRIES) {
System.err.println("too many blocks, max is " + MAX_ENTRIES);

View File

@ -16,6 +16,7 @@ import java.util.Properties;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import net.i2p.CoreVersion;
import net.i2p.I2PAppContext;
import net.i2p.app.ClientAppManager;
import net.i2p.app.ClientAppState;
@ -57,7 +58,7 @@ import net.i2p.util.VersionComparator;
* @since 0.9.4
*/
public class ConsoleUpdateManager implements UpdateManager, RouterApp {
private final RouterContext _context;
private final Log _log;
private final Collection<RegisteredUpdater> _registeredUpdaters;
@ -146,6 +147,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
notifyInstalled(ROUTER_SIGNED, "", RouterVersion.VERSION);
notifyInstalled(ROUTER_SIGNED_SU3, "", RouterVersion.VERSION);
notifyInstalled(ROUTER_DEV_SU3, "", RouterVersion.FULL_VERSION);
notifyInstalled(API, "", CoreVersion.PUBLISHED_VERSION);
String blist = _context.getProperty(NewsFetcher.PROP_BLOCKLIST_TIME);
if (blist != null)
notifyInstalled(BLOCKLIST, Blocklist.ID_FEED, blist);
@ -752,7 +754,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
_log.info("Unregistering " + ru);
_registeredUpdaters.remove(ru);
}
public void register(Checker updater, UpdateType type, UpdateMethod method, int priority) {
RegisteredChecker rc = new RegisteredChecker(updater, type, method, priority);
if (_log.shouldLog(Log.INFO))
@ -783,7 +785,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
if (old != null && _log.shouldLog(Log.WARN))
_log.warn("Duplicate registration " + upp);
}
/**
* Called by the Updater, either after check() was called, or it found out on its own.
* Use this if there is only one UpdateMethod; otherwise use the Map method below.
@ -1249,7 +1251,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
if (old != null && old.compareTo(ver) <= 0)
_available.remove(ui);
}
/** from NewsFetcher */
boolean shouldInstall() {
String policy = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_POLICY);
@ -1259,7 +1261,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
File zip = new File(_context.getRouterDir(), Router.UPDATE_FILE);
return !zip.exists();
}
/**
* Where to find various resources
* @return non-null may be empty
@ -1381,7 +1383,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
upp.updateDownloadedandVerified(updateType, ftype, actualVersion, temp);
_externalRestartPending = true;
} else {
err = "Unsupported su3 file type " + ftype;
err = "Unsupported su3 file type " + ftype + " " + updateType;
}
} else {
err = "Unsupported su3 file type " + ftype;

View File

@ -9,6 +9,8 @@ import java.util.Properties;
import net.i2p.router.RouterContext;
import net.i2p.router.web.PluginStarter;
import net.i2p.update.*;
import net.i2p.util.Log;
import net.i2p.util.SystemVersion;
/**
* Check for or download an updated version of a plugin.
@ -27,12 +29,14 @@ import net.i2p.update.*;
class PluginUpdateHandler implements Checker, Updater {
private final RouterContext _context;
private final ConsoleUpdateManager _mgr;
private final Log _log;
public PluginUpdateHandler(RouterContext ctx, ConsoleUpdateManager mgr) {
_context = ctx;
_log = _context.logManager().getLog(PluginUpdateHandler.class);
_mgr = mgr;
}
/** check a single plugin */
@Override
public UpdateTask check(UpdateType type, UpdateMethod method,
@ -48,6 +52,10 @@ class PluginUpdateHandler implements Checker, Updater {
xpi2pURL = props.getProperty("updateURL");
List<URI> updateSources = null;
if (xpi2pURL != null) {
xpi2pURL = xpi2pURL.replace("$OS", SystemVersion.getOS());
xpi2pURL = xpi2pURL.replace("$ARCH", SystemVersion.getArch());
if (_log.shouldLog(Log.INFO))
_log.info("Checking for updates for " + appName + ": " + xpi2pURL);
try {
updateSources = Collections.singletonList(new URI(xpi2pURL));
} catch (URISyntaxException use) {}
@ -61,7 +69,7 @@ class PluginUpdateHandler implements Checker, Updater {
UpdateRunner update = new PluginUpdateChecker(_context, _mgr, updateSources, appName, oldVersion);
return update;
}
/** download a single plugin */
@Override
public UpdateTask update(UpdateType type, UpdateMethod method, List<URI> updateSources,
@ -83,4 +91,4 @@ class PluginUpdateHandler implements Checker, Updater {
return update;
}
}

View File

@ -101,6 +101,9 @@ public class LocaleWebAppHandler extends HandlerWrapper
} else if (pathInContext.startsWith("/js/")) {
// war internal
httpResponse.setCharacterEncoding("ISO-8859-1");
} else if (pathInContext.endsWith(".css")) {
// war internal
httpResponse.setCharacterEncoding("UTF-8");
}
//System.err.println("New path: " + newPath);
super.handle(newPath, baseRequest, httpRequest, httpResponse);

View File

@ -475,7 +475,7 @@ public class PluginStarter implements Runnable {
if (log.shouldLog(Log.INFO))
log.info("Starting webapp: " + warName);
String path = files[i].getCanonicalPath();
WebAppStarter.startWebApp(ctx, server, warName, path);
WebAppStarter.startWebApp(ctx, server, warName, path, appName);
pluginWars.get(appName).add(warName);
}
} catch (IOException ioe) {
@ -486,9 +486,23 @@ public class PluginStarter implements Runnable {
String icfile = stripHTML(props, "console-icon");
if (icfile != null && !icfile.contains("..")) {
StringBuilder buf = new StringBuilder(32);
buf.append('/').append(appName);
if (!icfile.startsWith("/"))
String url = stripHTML(props, "consoleLinkURL");
if (url != null) {
if (url.endsWith(".html") || url.endsWith(".htm") || url.endsWith(".jsp") || url.endsWith("/home")) {
int slash = url.lastIndexOf('/');
if (slash > 0)
url = url.substring(0, slash);
}
} else {
url = appName;
}
if (!url.startsWith("/"))
buf.append('/');
buf.append(url);
if (!url.endsWith("/") && !icfile.startsWith("/"))
buf.append('/');
else if (url.endsWith("/") && icfile.startsWith("/"))
icfile = icfile.substring(1);
buf.append(icfile);
iconfile = buf.toString();
}
@ -824,6 +838,8 @@ public class PluginStarter implements Runnable {
argVal[i] = argVal[i].replace("$I2P", ctx.getBaseDir().getAbsolutePath());
argVal[i] = argVal[i].replace("$CONFIG", ctx.getConfigDir().getAbsolutePath());
argVal[i] = argVal[i].replace("$PLUGIN", pluginDir.getAbsolutePath());
argVal[i] = argVal[i].replace("$OS", SystemVersion.getOS());
argVal[i] = argVal[i].replace("$ARCH", SystemVersion.getArch());
}
}
ClientApp ca = ctx.routerAppManager().getClientApp(app.className, argVal);
@ -863,6 +879,8 @@ public class PluginStarter implements Runnable {
argVal[i] = argVal[i].replace("$I2P", ctx.getBaseDir().getAbsolutePath());
argVal[i] = argVal[i].replace("$CONFIG", ctx.getConfigDir().getAbsolutePath());
argVal[i] = argVal[i].replace("$PLUGIN", pluginDir.getAbsolutePath());
argVal[i] = argVal[i].replace("$OS", SystemVersion.getOS());
argVal[i] = argVal[i].replace("$ARCH", SystemVersion.getArch());
}
}
@ -873,6 +891,8 @@ public class PluginStarter implements Runnable {
cp = cp.replace("$I2P", ctx.getBaseDir().getAbsolutePath());
cp = cp.replace("$CONFIG", ctx.getConfigDir().getAbsolutePath());
cp = cp.replace("$PLUGIN", pluginDir.getAbsolutePath());
cp = cp.replace("$OS", SystemVersion.getOS());
cp = cp.replace("$ARCH", SystemVersion.getArch());
}
// Old way - add for the whole JVM

Some files were not shown because too many files have changed in this diff Show More