summaryrefslogtreecommitdiff
path: root/app/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main')
-rw-r--r--app/src/main/AndroidManifest.xml15
-rw-r--r--app/src/main/java/de/blinkt/openvpn/LaunchVPN.java13
-rw-r--r--app/src/main/java/de/blinkt/openvpn/VpnProfile.java92
-rw-r--r--app/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java4
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java14
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java45
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java2
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java19
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/OpenVpnService.java84
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/Dashboard.java63
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/EIP.java108
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java306
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/EipStatusReceiver.java17
-rwxr-xr-xapp/src/main/res/values-cs/strings-icsopenvpn.xml6
-rwxr-xr-xapp/src/main/res/values-hu/strings-icsopenvpn.xml284
-rwxr-xr-xapp/src/main/res/values-in/strings-icsopenvpn.xml285
-rwxr-xr-xapp/src/main/res/values-ja/strings-icsopenvpn.xml7
-rwxr-xr-xapp/src/main/res/values-tr/strings-icsopenvpn.xml2
-rwxr-xr-xapp/src/main/res/values/strings-icsopenvpn.xml7
-rw-r--r--app/src/main/res/values/strings.xml5
-rw-r--r--app/src/main/res/values/untranslatable.xml418
21 files changed, 1454 insertions, 342 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a90d6396..507e5bb0 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -17,8 +17,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="se.leap.bitmaskclient"
- android:versionCode="86"
- android:versionName="0.5.4" >
+ android:versionCode="90"
+ android:versionName="0.6.0" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
@@ -48,20 +48,11 @@
android:name="se.leap.bitmaskclient.OnBootReceiver"
android:enabled="true"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED" >
- <intent-filter>
+ <intent-filter android:priority="999">
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
- <receiver
- android:name="se.leap.bitmaskclient.EipStatusReceiver"
- android:enabled="true"
- android:permission="android.permission.ACCESS_NETWORK_STATE" >
- <intent-filter>
- <action android:name="de.blinkt.openvpn.VPN_STATUS" />
- </intent-filter>
- </receiver>
-
<activity
android:theme="@android:style/Theme.DeviceDefault.Light.Dialog"
android:name="de.blinkt.openvpn.activities.DisconnectVPN" />
diff --git a/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java b/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java
index a39e780a..3f80eef0 100644
--- a/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java
+++ b/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java
@@ -4,8 +4,6 @@ import se.leap.bitmaskclient.R;
import se.leap.bitmaskclient.R;
-import java.io.IOException;
-
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
@@ -20,13 +18,17 @@ import android.text.InputType;
import android.text.TextUtils;
import android.text.method.PasswordTransformationMethod;
import android.view.View;
-import android.widget.*;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.EditText;
+
+import java.io.IOException;
import de.blinkt.openvpn.activities.LogWindow;
-import de.blinkt.openvpn.core.VpnStatus;
-import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus;
import de.blinkt.openvpn.core.ProfileManager;
import de.blinkt.openvpn.core.VPNLaunchHelper;
+import de.blinkt.openvpn.core.VpnStatus;
+import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus;
/**
* This Activity actually handles two stages of a launcher shortcut's life cycle.
@@ -111,7 +113,6 @@ public class LaunchVPN extends Activity {
}
}
-
@Override
protected void onActivityResult (int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
diff --git a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
index 0166eb98..d44d0f5a 100644
--- a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
+++ b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
@@ -4,6 +4,7 @@ import se.leap.bitmaskclient.R;
import se.leap.bitmaskclient.R;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -14,6 +15,7 @@ import android.os.Build;
import android.preference.PreferenceManager;
import android.security.KeyChain;
import android.security.KeyChainException;
+import android.text.TextUtils;
import android.util.Base64;
import org.spongycastle.util.io.pem.PemObject;
@@ -115,8 +117,8 @@ public class VpnProfile implements Serializable {
public boolean mUseDefaultRoute = true;
public boolean mUsePull = true;
public String mCustomRoutes;
- public boolean mCheckRemoteCN = false;
- public boolean mExpectTLSCert = true;
+ public boolean mCheckRemoteCN = true;
+ public boolean mExpectTLSCert = false;
public String mRemoteCN = "";
public String mPassword = "";
public String mUsername = "";
@@ -181,6 +183,7 @@ public class VpnProfile implements Serializable {
mUseDefaultRoute = false;
mUseDefaultRoutev6 = false;
mExpectTLSCert = false;
+ mCheckRemoteCN = false;
mPersistTun = false;
mAllowLocalLAN = true;
}
@@ -199,10 +202,7 @@ public class VpnProfile implements Serializable {
public void upgradeProfile(){
if(mProfileVersion< 2) {
/* default to the behaviour the OS used */
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
- mAllowLocalLAN = true;
- else
- mAllowLocalLAN = false;
+ mAllowLocalLAN = Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT;
}
mProfileVersion= CURRENT_PROFILE_VERSION;
@@ -213,7 +213,7 @@ public class VpnProfile implements Serializable {
File cacheDir = context.getCacheDir();
String cfg = "";
- // Enable managment interface
+ // Enable management interface
cfg += "# Enables connection to GUI\n";
cfg += "management ";
@@ -230,6 +230,9 @@ public class VpnProfile implements Serializable {
cfg += "machine-readable-output\n";
+ // Users are confused by warnings that are misleading...
+ cfg += "ifconfig-nowarn\n";
+
boolean useTLSClient = (mAuthenticationType != TYPE_STATICKEYS);
@@ -327,7 +330,7 @@ public class VpnProfile implements Serializable {
else
cfg += insertFileData("tls-auth", mTLSAuthFilename);
- if (nonNull(mTLSAuthDirection)) {
+ if (!TextUtils.isEmpty(mTLSAuthDirection)) {
cfg += "key-direction ";
cfg += mTLSAuthDirection;
cfg += "\n";
@@ -336,10 +339,10 @@ public class VpnProfile implements Serializable {
}
if (!mUsePull) {
- if (nonNull(mIPv4Address))
+ if (!TextUtils.isEmpty(mIPv4Address))
cfg += "ifconfig " + cidrToIPAndNetmask(mIPv4Address) + "\n";
- if (nonNull(mIPv6Address))
+ if (!TextUtils.isEmpty(mIPv6Address))
cfg += "ifconfig-ipv6 " + mIPv6Address + "\n";
}
@@ -377,11 +380,11 @@ public class VpnProfile implements Serializable {
cfg += routes;
if (mOverrideDNS || !mUsePull) {
- if (nonNull(mDNS1))
+ if (!TextUtils.isEmpty(mDNS1))
cfg += "dhcp-option DNS " + mDNS1 + "\n";
- if (nonNull(mDNS2))
+ if (!TextUtils.isEmpty(mDNS2))
cfg += "dhcp-option DNS " + mDNS2 + "\n";
- if (nonNull(mSearchDomain))
+ if (!TextUtils.isEmpty(mSearchDomain))
cfg += "dhcp-option DOMAIN " + mSearchDomain + "\n";
}
@@ -422,11 +425,11 @@ public class VpnProfile implements Serializable {
cfg += "remote-cert-tls server\n";
}
- if (nonNull(mCipher)) {
+ if (!TextUtils.isEmpty(mCipher)) {
cfg += "cipher " + mCipher + "\n";
}
- if (nonNull(mAuth)) {
+ if (!TextUtils.isEmpty(mAuth)) {
cfg += "auth " + mAuth + "\n";
}
@@ -488,13 +491,6 @@ public class VpnProfile implements Serializable {
}
}
- private boolean nonNull(String val) {
- if (val == null || val.equals(""))
- return false;
- else
- return true;
- }
-
private Collection<String> getCustomRoutes(String routes) {
Vector<String> cidrRoutes = new Vector<String>();
if (routes == null) {
@@ -636,8 +632,8 @@ public class VpnProfile implements Serializable {
synchronized String[] getKeyStoreCertificates(Context context,int tries) {
PrivateKey privateKey = null;
- X509Certificate[] cachain;
- Exception exp=null;
+ X509Certificate[] caChain;
+ Exception exp;
try {
privateKey = KeyChain.getPrivateKey(context, mAlias);
mPrivateKey = privateKey;
@@ -645,18 +641,18 @@ public class VpnProfile implements Serializable {
String keystoreChain = null;
- cachain = KeyChain.getCertificateChain(context, mAlias);
- if(cachain == null)
+ caChain = KeyChain.getCertificateChain(context, mAlias);
+ if(caChain == null)
throw new NoCertReturnedException("No certificate returned from Keystore");
- if (cachain.length <= 1 && !nonNull(mCaFilename)) {
+ if (caChain.length <= 1 && TextUtils.isEmpty(mCaFilename)) {
VpnStatus.logMessage(VpnStatus.LogLevel.ERROR, "", context.getString(R.string.keychain_nocacert));
} else {
StringWriter ksStringWriter = new StringWriter();
PemWriter pw = new PemWriter(ksStringWriter);
- for (int i = 1; i < cachain.length; i++) {
- X509Certificate cert = cachain[i];
+ for (int i = 1; i < caChain.length; i++) {
+ X509Certificate cert = caChain[i];
pw.writeObject(new PemObject("CERTIFICATE", cert.getEncoded()));
}
pw.close();
@@ -665,7 +661,7 @@ public class VpnProfile implements Serializable {
String caout = null;
- if (nonNull(mCaFilename)) {
+ if (!TextUtils.isEmpty(mCaFilename)) {
try {
Certificate cacert = X509Utils.getCertificateFromFile(mCaFilename);
StringWriter caoutWriter = new StringWriter();
@@ -684,8 +680,8 @@ public class VpnProfile implements Serializable {
StringWriter certout = new StringWriter();
- if (cachain.length >= 1) {
- X509Certificate usercert = cachain[0];
+ if (caChain.length >= 1) {
+ X509Certificate usercert = caChain[0];
PemWriter upw = new PemWriter(certout);
upw.writeObject(new PemObject("CERTIFICATE", usercert.getEncoded()));
@@ -730,15 +726,14 @@ public class VpnProfile implements Serializable {
}
return getKeyStoreCertificates(context, tries-1);
}
- if (exp != null) {
- exp.printStackTrace();
- VpnStatus.logError(R.string.keyChainAccessError, exp.getLocalizedMessage());
- VpnStatus.logError(R.string.keychain_access);
- if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN) {
- if (!mAlias.matches("^[a-zA-Z0-9]$")) {
- VpnStatus.logError(R.string.jelly_keystore_alphanumeric_bug);
- }
+ exp.printStackTrace();
+ VpnStatus.logError(R.string.keyChainAccessError, exp.getLocalizedMessage());
+
+ VpnStatus.logError(R.string.keychain_access);
+ if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN) {
+ if (!mAlias.matches("^[a-zA-Z0-9]$")) {
+ VpnStatus.logError(R.string.jelly_keystore_alphanumeric_bug);
}
}
return null;
@@ -801,7 +796,7 @@ public class VpnProfile implements Serializable {
}
public boolean requireTLSKeyPassword() {
- if (!nonNull(mClientKeyFilename))
+ if (TextUtils.isEmpty(mClientKeyFilename))
return false;
String data = "";
@@ -842,13 +837,13 @@ public class VpnProfile implements Serializable {
}
if (mAuthenticationType == TYPE_CERTIFICATES || mAuthenticationType == TYPE_USERPASS_CERTIFICATES) {
- if (requireTLSKeyPassword() && !nonNull(mKeyPassword))
+ if (requireTLSKeyPassword() && TextUtils.isEmpty(mKeyPassword))
if (mTransientPCKS12PW == null) {
return R.string.private_key_password;
}
}
- if (isUserPWAuth() && !(nonNull(mUsername) && (nonNull(mPassword) || mTransientPW != null))) {
+ if (isUserPWAuth() && !(!TextUtils.isEmpty(mUsername) && (!TextUtils.isEmpty(mPassword) || mTransientPW != null))) {
return R.string.password;
}
return 0;
@@ -893,12 +888,15 @@ public class VpnProfile implements Serializable {
try {
+ /* ECB is perfectly fine in this special case, since we are using it for
+ the public/private part in the TLS exchange
+ */
+ @SuppressLint("GetInstance")
+ Cipher rsaSigner = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
- Cipher rsasinger = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
-
- rsasinger.init(Cipher.ENCRYPT_MODE, privkey);
+ rsaSigner.init(Cipher.ENCRYPT_MODE, privkey);
- byte[] signed_bytes = rsasinger.doFinal(data);
+ byte[] signed_bytes = rsaSigner.doFinal(data);
return Base64.encodeToString(signed_bytes, Base64.NO_WRAP);
} catch (NoSuchAlgorithmException e) {
diff --git a/app/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java b/app/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java
index da011c98..8e418053 100644
--- a/app/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java
+++ b/app/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java
@@ -43,8 +43,8 @@ public class DisconnectVPN extends Activity implements DialogInterface.OnClickLi
}
@Override
- protected void onStop() {
- super.onStop();
+ protected void onPause() {
+ super.onPause();
unbindService(mConnection);
}
diff --git a/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java b/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java
index 378b6b92..d23b521f 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java
@@ -1,7 +1,5 @@
package de.blinkt.openvpn.core;
-import de.blinkt.openvpn.VpnProfile;
-
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
@@ -10,6 +8,8 @@ import java.util.HashMap;
import java.util.Locale;
import java.util.Vector;
+import de.blinkt.openvpn.VpnProfile;
+
//! Openvpn Config FIle Parser, probably not 100% accurate but close enough
// And remember, this is valid :)
@@ -31,11 +31,17 @@ public class ConfigParser {
BufferedReader br =new BufferedReader(reader);
+ int lineno=0;
while (true){
String line = br.readLine();
+ lineno++;
if(line==null)
break;
+ if (lineno==1 && (line.startsWith("PK\003\004")
+ || (line.startsWith("PK\007\008"))))
+ throw new ConfigParseError("Input looks like a ZIP Archive. Import is only possible for OpenVPN config files (.ovpn/.conf)");
+
// Check for OpenVPN Access Server Meta information
if (line.startsWith("# OVPN_ACCESS_SERVER_")) {
Vector<String> metaarg = parsemeta(line);
@@ -440,8 +446,8 @@ public class ConfigParser {
}
Vector<String> rport = getOption("rport", 1,1);
- if(port!=null){
- np.mServerPort = port.get(1);
+ if(rport!=null){
+ np.mServerPort = rport.get(1);
}
Vector<String> proto = getOption("proto", 1,1);
diff --git a/app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java b/app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java
index 990e70d8..81a17ef9 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java
@@ -5,6 +5,8 @@ import android.text.TextUtils;
import junit.framework.Assert;
+import org.jetbrains.annotations.NotNull;
+
import java.math.BigInteger;
import java.net.Inet6Address;
import java.util.*;
@@ -23,13 +25,18 @@ public class NetworkSpace {
private BigInteger lastAddress;
+ /**
+ * sorts the networks with following criteria:
+ * 1. compares first 1 of the network
+ * 2. smaller networks are returned as smaller
+ */
@Override
- public int compareTo(ipAddress another) {
+ public int compareTo(@NotNull ipAddress another) {
int comp = getFirstAddress().compareTo(another.getFirstAddress());
if (comp != 0)
return comp;
- // bigger mask means smaller address block
+
if (networkMask > another.networkMask)
return -1;
else if (another.networkMask == networkMask)
@@ -38,6 +45,22 @@ public class NetworkSpace {
return 1;
}
+ /**
+ * Warning ignores the included integer
+ *
+ * @param o
+ * the object to compare this instance with.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof ipAddress))
+ return super.equals(o);
+
+
+ ipAddress on = (ipAddress) o;
+ return (networkMask == on.networkMask) && on.getFirstAddress().equals(getFirstAddress());
+ }
+
public ipAddress(CIDRIP ip, boolean include) {
included = include;
netAddress = BigInteger.valueOf(ip.getInt());
@@ -110,10 +133,10 @@ public class NetworkSpace {
public ipAddress[] split() {
- ipAddress firsthalf = new ipAddress(getFirstAddress(), networkMask + 1, included, isV4);
- ipAddress secondhalf = new ipAddress(firsthalf.getLastAddress().add(BigInteger.ONE), networkMask + 1, included, isV4);
- if (BuildConfig.DEBUG) Assert.assertTrue(secondhalf.getLastAddress().equals(getLastAddress()));
- return new ipAddress[]{firsthalf, secondhalf};
+ ipAddress firstHalf = new ipAddress(getFirstAddress(), networkMask + 1, included, isV4);
+ ipAddress secondHalf = new ipAddress(firstHalf.getLastAddress().add(BigInteger.ONE), networkMask + 1, included, isV4);
+ if (BuildConfig.DEBUG) Assert.assertTrue(secondHalf.getLastAddress().equals(getLastAddress()));
+ return new ipAddress[]{firstHalf, secondHalf};
}
String getIPv4Address() {
@@ -185,7 +208,7 @@ public class NetworkSpace {
return ipsDone;
while (currentNet!=null) {
- // Check if it and the next of it are compatbile
+ // Check if it and the next of it are compatible
ipAddress nextNet = networks.poll();
if (BuildConfig.DEBUG) Assert.assertNotNull(currentNet);
@@ -202,9 +225,12 @@ public class NetworkSpace {
// Simply forget our current network
currentNet=nextNet;
} else {
- // our currentnet is included in next and types differ. Need to split the next network
+ // our currentNet is included in next and types differ. Need to split the next network
ipAddress[] newNets = nextNet.split();
+
+ // TODO: The contains method of the Priority is stupid linear search
+
// First add the second half to keep the order in networks
if (!networks.contains(newNets[1]))
networks.add(newNets[1]);
@@ -226,6 +252,7 @@ public class NetworkSpace {
}
// This network is bigger than the next and last ip of current >= next
+ //noinspection StatementWithEmptyBody
if (currentNet.included == nextNet.included) {
// Next network is in included in our network with the same type,
// simply ignore the next and move on
@@ -238,7 +265,7 @@ public class NetworkSpace {
if (BuildConfig.DEBUG) {
Assert.assertTrue (newNets[1].getFirstAddress().equals(nextNet.getFirstAddress()));
Assert.assertTrue (newNets[1].getLastAddress().equals(currentNet.getLastAddress()));
- // Splitted second equal the next network, do not add it
+ // split second equal the next network, do not add it
}
networks.add(nextNet);
} else {
diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java
index 0de54ed7..67c05e7d 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNThread.java
@@ -48,8 +48,6 @@ public class OpenVPNThread implements Runnable {
public void stopProcess() {
mProcess.destroy();
}
-
-
@Override
public void run() {
diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java
index 4cba4f5f..e6e5be25 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java
@@ -9,11 +9,9 @@ import android.os.ParcelFileDescriptor;
import android.preference.PreferenceManager;
import android.util.Log;
-import org.jetbrains.annotations.NotNull;
+import junit.framework.Assert;
-import se.leap.bitmaskclient.R;
-import de.blinkt.openvpn.VpnProfile;
-import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus;
+import org.jetbrains.annotations.NotNull;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -22,7 +20,16 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
-import java.util.*;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.Locale;
+import java.util.Vector;
+
+import se.leap.bitmaskclient.BuildConfig;
+import se.leap.bitmaskclient.R;
+import de.blinkt.openvpn.VpnProfile;
+import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus;
public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
@@ -391,7 +398,7 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement {
*/
if(routeparts.length==5) {
- assert(routeparts[3].equals("dev"));
+ if (BuildConfig.DEBUG) Assert.assertEquals("dev", routeparts[3]);
mOpenVPNService.addRoute(routeparts[0], routeparts[1], routeparts[2], routeparts[4]);
} else if (routeparts.length >= 3) {
mOpenVPNService.addRoute(routeparts[0], routeparts[1], routeparts[2], null);
diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVpnService.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVpnService.java
index 43b27212..0cf93de3 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/OpenVpnService.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVpnService.java
@@ -40,6 +40,8 @@ import de.blinkt.openvpn.core.VpnStatus.StateListener;
import static de.blinkt.openvpn.core.NetworkSpace.ipAddress;
import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_CONNECTED;
+import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_CONNECTING_SERVER_REPLIED;
+import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_NONETWORK;
import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET;
import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT;
@@ -72,6 +74,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
private OpenVPNManagement mManagement;
private String mLastTunCfg;
private String mRemoteGW;
+ private Object mProcessLock = new Object();
// From: http://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java
public static String humanReadableByteCount(long bytes, boolean mbit) {
@@ -110,7 +113,9 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
}
private void endVpnService() {
- mProcessThread = null;
+ synchronized (mProcessLock) {
+ mProcessThread = null;
+ }
VpnStatus.removeByteCountListener(this);
unregisterDeviceStateReceiver();
ProfileManager.setConntectedVpnProfileDisconnected(this);
@@ -161,7 +166,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
mNotificationManager.notify(OPENVPN_STATUS, notification);
- startForeground(OPENVPN_STATUS, notification);
+ // startForeground(OPENVPN_STATUS, notification);
}
private int getIconByConnectionStatus(ConnectionStatus level) {
@@ -314,11 +319,12 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
mProfile = ProfileManager.get(this, profileUUID);
+
String startTitle = getString(R.string.start_vpn_title, mProfile.mName);
String startTicker = getString(R.string.start_vpn_ticker, mProfile.mName);
showNotification(startTitle, startTicker,
false, 0, LEVEL_CONNECTING_NO_SERVER_REPLY_YET);
-
+
// Set a flag that we are starting a new VPN
mStarting = true;
// Stop the previous session by interrupting the thread.
@@ -330,13 +336,14 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
//ignore
}
-
- if (mProcessThread != null) {
- mProcessThread.interrupt();
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- //ignore
+ synchronized (mProcessLock) {
+ if (mProcessThread != null) {
+ mProcessThread.interrupt();
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ //ignore
+ }
}
}
// An old running VPN should now be exited
@@ -380,9 +387,10 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
processThread = new OpenVPNThread(this, argv, env, nativelibdir);
}
- mProcessThread = new Thread(processThread, "OpenVPNProcessThread");
- mProcessThread.start();
-
+ synchronized (mProcessLock) {
+ mProcessThread = new Thread(processThread, "OpenVPNProcessThread");
+ mProcessThread.start();
+ }
if (mDeviceStateReceiver != null)
unregisterDeviceStateReceiver();
@@ -416,11 +424,12 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
@Override
public void onDestroy() {
- if (mProcessThread != null) {
- mManagement.stopVPN();
-
- mProcessThread.interrupt();
+ synchronized (mProcessLock) {
+ if (mProcessThread != null) {
+ mManagement.stopVPN();
+ }
}
+
if (mDeviceStateReceiver != null) {
this.unregisterReceiver(mDeviceStateReceiver);
}
@@ -639,10 +648,10 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
mMtu = mtu;
mRemoteGW=null;
+ long netMaskAsInt = CIDRIP.getInt(netmask);
if (mLocalIP.len == 32 && !netmask.equals("255.255.255.255")) {
// get the netmask as IP
- long netMaskAsInt = CIDRIP.getInt(netmask);
int masklen;
if ("net30".equals(mode))
@@ -655,11 +664,18 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
if ((netMaskAsInt & mask) == (mLocalIP.getInt() & mask )) {
mLocalIP.len = masklen;
} else {
+ mLocalIP.len = 32;
if (!"p2p".equals(mode))
VpnStatus.logWarning(R.string.ip_not_cidr, local, netmask, mode);
- mRemoteGW=netmask;
}
}
+ if (("p2p".equals(mode)) && mLocalIP.len < 32 || "net30".equals("net30") && mLocalIP.len < 30) {
+ VpnStatus.logWarning(R.string.ip_looks_like_subnet, local, netmask, mode);
+ }
+
+
+ // Configurations are sometimes really broken...
+ mRemoteGW=netmask;
}
public void setLocalIPv6(String ipv6addr) {
@@ -686,17 +702,22 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
mDisplayBytecount = true;
mConnecttime = System.currentTimeMillis();
lowpriority = true;
- } else {
+ NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ mNotificationManager.cancel(OPENVPN_STATUS);
+ } else if(!mProfile.mPersistTun || mConnecttime == 0){
mDisplayBytecount = false;
- }
-
- // Other notifications are shown,
- // This also mean we are no longer connected, ignore bytecount messages until next
- // CONNECTED
- // Does not work :(
- String msg = getString(resid);
- String ticker = msg;
- showNotification(msg + " " + logmessage, ticker, lowpriority , 0, level);
+ String msg = getString(resid);
+ String ticker = msg;
+ showNotification(msg + " " + logmessage, ticker, lowpriority , 0, level);
+ } else if(mProfile.mPersistTun && level == LEVEL_NONETWORK) {
+ NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ mNotificationManager.cancel(OPENVPN_STATUS);
+ } else if(mProfile.mPersistTun && mConnecttime > 0) {
+ mDisplayBytecount = false;
+ String msg = "Traffic is blocked until the VPN becomes active.";
+ String ticker = msg;
+ showNotification(msg, ticker, lowpriority , 0, level);
+ }
}
}
@@ -717,9 +738,6 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
humanReadableByteCount(diffIn / OpenVPNManagement.mBytecountInterval, true),
humanReadableByteCount(out, false),
humanReadableByteCount(diffOut / OpenVPNManagement.mBytecountInterval, true));
-
- boolean lowpriority = !mNotificationAlwaysVisible;
- showNotification(netstat, null, lowpriority, mConnecttime, LEVEL_CONNECTED);
}
}
@@ -746,7 +764,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
} else {
String release = Build.VERSION.RELEASE;
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT && !release.startsWith("4.4.3")
- && !release.startsWith("4.4.4") && !release.startsWith("4.4.5"))
+ && !release.startsWith("4.4.4") && !release.startsWith("4.4.5") && !release.startsWith("4.4.6"))
// There will be probably no 4.4.4 or 4.4.5 version, so don't waste effort to do parsing here
return "OPEN_AFTER_CLOSE";
else
diff --git a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
index 117e45d8..fe546a21 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
+++ b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
@@ -33,6 +33,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;
@@ -63,12 +64,14 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
public static final String PARAMETERS = "dashboard parameters";
public static final String START_ON_BOOT = "dashboard start on boot";
final public static String ON_BOOT = "dashboard on boot";
+ public static final String APP_VERSION = "bitmask version";
-
+
+ private EipServiceFragment eipFragment;
private ProgressBar mProgressBar;
private TextView eipStatus;
private static Context app;
- private static SharedPreferences preferences;
+ protected static SharedPreferences preferences;
private static Provider provider;
private TextView providerNameTV;
@@ -81,17 +84,15 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- app = this;
+ app = this;
PRNGFixes.apply();
- // mProgressBar = (ProgressBar) findViewById(R.id.progressbar_dashboard);
- // mProgressBar = (ProgressBar) findViewById(R.id.eipProgress);
- // eipStatus = (TextView) findViewById(R.id.eipStatus);
mProgressBar = (ProgressBar) findViewById(R.id.eipProgress);
preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
-
+ handleVersion();
+
authed_eip = preferences.getBoolean(EIP.AUTHED_EIP, false);
if (preferences.getString(Provider.KEY, "").isEmpty())
startActivityForResult(new Intent(this,ConfigurationWizard.class),CONFIGURE_LEAP);
@@ -99,8 +100,21 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
buildDashboard(getIntent().getBooleanExtra(ON_BOOT, false));
}
+ private void handleVersion() {
+ try {
+ int versionCode = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
+ int lastDetectedVersion = preferences.getInt(APP_VERSION, 0);
+ if(lastDetectedVersion == 0) // New install
+ getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putInt(APP_VERSION, versionCode);
+ else if(lastDetectedVersion < versionCode) {
+ }
+ } catch (NameNotFoundException e) {
+ }
+ }
+
@Override
protected void onDestroy() {
+
super.onDestroy();
}
@@ -122,7 +136,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
invalidateOptionsMenu();
if(data != null && data.hasExtra(LogInDialog.VERB)) {
View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0);
- logInDialog(view, Bundle.EMPTY);
+ logInDialog(Bundle.EMPTY);
}
} else if(resultCode == RESULT_CANCELED && (data == null || data.hasExtra(ACTION_QUIT))) {
finish();
@@ -176,9 +190,9 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
FragmentManager fragMan = getFragmentManager();
if ( provider.hasEIP()){
- EipServiceFragment eipFragment = new EipServiceFragment();
- if (hide_and_turn_on_eip) {
- getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().remove(Dashboard.START_ON_BOOT).commit();
+ eipFragment = new EipServiceFragment();
+ if (hide_and_turn_on_eip) {
+ getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().remove(Dashboard.START_ON_BOOT).commit();
Bundle arguments = new Bundle();
arguments.putBoolean(EipServiceFragment.START_ON_BOOT, true);
eipFragment.setArguments(arguments);
@@ -197,8 +211,10 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
try {
provider_json = new JSONObject(getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE).getString(Provider.KEY, ""));
JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE);
-
- if(service_description.getBoolean(Provider.ALLOW_REGISTRATION)) {
+ boolean authed_eip = preferences.getBoolean(EIP.AUTHED_EIP, false);
+ boolean allow_registered_eip = service_description.getBoolean(Provider.ALLOW_REGISTRATION);
+ preferences.edit().putBoolean(EIP.ALLOWED_REGISTERED, allow_registered_eip);
+ if(allow_registered_eip) {
if(authed_eip) {
menu.findItem(R.id.login_button).setVisible(false);
menu.findItem(R.id.logout_button).setVisible(true);
@@ -238,15 +254,15 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
if (Provider.getInstance().hasEIP()){
if (getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getBoolean(EIP.AUTHED_EIP, false)){
logOut();
- }
+ }
eipStop();
}
- getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().remove(Provider.KEY).commit();
+ getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().clear().commit();
startActivityForResult(new Intent(this,ConfigurationWizard.class), SWITCH_PROVIDER);
return true;
case R.id.login_button:
View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0);
- logInDialog(view, Bundle.EMPTY);
+ logInDialog(Bundle.EMPTY);
return true;
case R.id.logout_button:
logOut();
@@ -305,6 +321,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
if(eipStatus == null) eipStatus = (TextView) findViewById(R.id.eipStatus);
if(eipStatus != null) eipStatus.setText("");
}
+ cancelAuthedEipOn();
}
/**
@@ -343,9 +360,9 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
/**
* Shows the log in dialog.
- * @param view from which the dialog is created.
*/
- public void logInDialog(View view, Bundle resultData) {
+ public void logInDialog(Bundle resultData) {
+ Log.d("Dashboard", "Log In Dialog");
FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction();
Fragment previous_log_in_dialog = getFragmentManager().findFragmentByTag(LogInDialog.TAG);
if (previous_log_in_dialog != null) {
@@ -455,7 +472,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
//Cookie session_id = new BasicClientCookie(session_id_cookie_key, session_id_string);
downloadAuthedUserCertificate(/*session_id*/);
} else if(resultCode == ProviderAPI.SRP_AUTHENTICATION_FAILED) {
- logInDialog(getCurrentFocus(), resultData);
+ logInDialog(resultData);
} else if(resultCode == ProviderAPI.LOGOUT_SUCCESSFUL) {
authed_eip = false;
getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putBoolean(EIP.AUTHED_EIP, authed_eip).commit();
@@ -468,7 +485,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
} else if(resultCode == ProviderAPI.LOGOUT_FAILED) {
setResult(RESULT_CANCELED);
changeStatusMessage(resultCode);
- mProgressBar.setVisibility(ProgressBar.GONE);
+ mProgressBar.setVisibility(ProgressBar.GONE);
} else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) {
setResult(RESULT_OK);
changeStatusMessage(resultCode);
@@ -579,10 +596,4 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
mProgressBar = (ProgressBar) findViewById(R.id.eipProgress);
mProgressBar.setVisibility(visibility);
}
-
- protected void setEipStatus(int status) {
- if(eipStatus == null)
- eipStatus = (TextView) findViewById(R.id.eipStatus);
- eipStatus.setText(status);
- }
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/EIP.java b/app/src/main/java/se/leap/bitmaskclient/EIP.java
index 7374d5ed..41299318 100644
--- a/app/src/main/java/se/leap/bitmaskclient/EIP.java
+++ b/app/src/main/java/se/leap/bitmaskclient/EIP.java
@@ -41,13 +41,16 @@ import de.blinkt.openvpn.core.OpenVpnManagementThread;
import de.blinkt.openvpn.core.OpenVpnService.LocalBinder;
import de.blinkt.openvpn.core.OpenVpnService;
import de.blinkt.openvpn.core.ProfileManager;
+import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus;
import java.io.IOException;
import java.io.StringReader;
+import java.lang.StringBuffer;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.text.SimpleDateFormat;
+import java.util.Date;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
@@ -87,6 +90,7 @@ public final class EIP extends IntentService {
public final static String STATUS = "eip status";
public final static String DATE_FROM_CERTIFICATE = "date from certificate";
public final static String ALLOWED_ANON = "allow_anonymous";
+ public final static String ALLOWED_REGISTERED = "allow_registration";
public final static String CERTIFICATE = "cert";
public final static String PRIVATE_KEY = "private_key";
public final static String KEY = "eip";
@@ -109,6 +113,10 @@ public final class EIP extends IntentService {
private static JSONObject eipDefinition = null;
private static OVPNGateway activeGateway = null;
+
+ protected static ConnectionStatus lastConnectionStatusLevel;
+ protected static boolean mIsDisconnecting = false;
+ protected static boolean mIsStarting = false;
public EIP(){
super("LEAPEIP");
@@ -169,10 +177,6 @@ public final class EIP extends IntentService {
Log.d(TAG, "isRunning() = " + is_connected);
}
-
- private boolean isConnected() {
- return getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(STATUS, "").equalsIgnoreCase("LEVEL_CONNECTED");
- }
/**
* Initiates an EIP connection by selecting a gateway and preparing and sending an
@@ -207,6 +211,9 @@ public final class EIP extends IntentService {
Intent disconnect_vpn = new Intent(this, DisconnectVPN.class);
disconnect_vpn.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(disconnect_vpn);
+ mIsDisconnecting = true;
+ lastConnectionStatusLevel = ConnectionStatus.UNKNOWN_LEVEL; // Wait for the decision of the user
+ Log.d(TAG, "mIsDisconnecting = true");
}
if (mReceiver != null){
@@ -216,6 +223,10 @@ public final class EIP extends IntentService {
}
}
+ protected static boolean isConnected() {
+ return lastConnectionStatusLevel != null && lastConnectionStatusLevel.equals(ConnectionStatus.LEVEL_CONNECTED) && !mIsDisconnecting;
+ }
+
/**
* Loads eip-service.json from SharedPreferences and calls {@link updateGateways()}
* to parse gateway definitions.
@@ -335,31 +346,34 @@ public final class EIP extends IntentService {
private void checkCertValidity() {
String certificate_string = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(CERTIFICATE, "");
- String date_from_certificate_string = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(DATE_FROM_CERTIFICATE, Calendar.getInstance().getTime().toString());
- X509Certificate certificate_x509 = ConfigHelper.parseX509CertificateFromString(certificate_string);
+ if(!certificate_string.isEmpty()) {
+ String date_from_certificate_string = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(DATE_FROM_CERTIFICATE, certificate_date_format.format(Calendar.getInstance().getTime()).toString());
+ X509Certificate certificate_x509 = ConfigHelper.parseX509CertificateFromString(certificate_string);
- Calendar offset_date = Calendar.getInstance();
- try {
- long difference = Math.abs(certificate_date_format.parse(date_from_certificate_string).getTime() - certificate_x509.getNotAfter().getTime())/2;
- long current_date_millis = offset_date.getTimeInMillis();
- offset_date.setTimeInMillis(current_date_millis + difference);
- Log.d(TAG, "certificate not after = " + certificate_x509.getNotAfter());
- } catch(ParseException e) {
- e.printStackTrace();
- }
+ Calendar offset_date = Calendar.getInstance();
+ try {
+ Date date_from_certificate = certificate_date_format.parse(date_from_certificate_string);
+ long difference = Math.abs(date_from_certificate.getTime() - certificate_x509.getNotAfter().getTime())/2;
+ long current_date_millis = offset_date.getTimeInMillis();
+ offset_date.setTimeInMillis(current_date_millis + difference);
+ Log.d(TAG, "certificate not after = " + certificate_x509.getNotAfter());
+ } catch(ParseException e) {
+ e.printStackTrace();
+ }
- Bundle result_data = new Bundle();
- result_data.putString(REQUEST_TAG, ACTION_CHECK_CERT_VALIDITY);
- try {
- Log.d(TAG, "offset_date = " + offset_date.getTime().toString());
- certificate_x509.checkValidity(offset_date.getTime());
- mReceiver.send(Activity.RESULT_OK, result_data);
- Log.d(TAG, "Valid certificate");
- } catch(CertificateExpiredException e) {
- mReceiver.send(Activity.RESULT_CANCELED, result_data);
- Log.d(TAG, "Updating certificate");
- } catch(CertificateNotYetValidException e) {
- mReceiver.send(Activity.RESULT_CANCELED, result_data);
+ Bundle result_data = new Bundle();
+ result_data.putString(REQUEST_TAG, ACTION_CHECK_CERT_VALIDITY);
+ try {
+ Log.d(TAG, "offset_date = " + offset_date.getTime().toString());
+ certificate_x509.checkValidity(offset_date.getTime());
+ mReceiver.send(Activity.RESULT_OK, result_data);
+ Log.d(TAG, "Valid certificate");
+ } catch(CertificateExpiredException e) {
+ mReceiver.send(Activity.RESULT_CANCELED, result_data);
+ Log.d(TAG, "Updating certificate");
+ } catch(CertificateNotYetValidException e) {
+ mReceiver.send(Activity.RESULT_CANCELED, result_data);
+ }
}
}
@@ -432,31 +446,10 @@ public final class EIP extends IntentService {
this.createVPNProfile();
- setUniqueProfileName();
vpl.addProfile(mVpnProfile);
vpl.saveProfile(context, mVpnProfile);
vpl.saveProfileList(context);
}
-
-
- public String locationAsName() {
- try {
- return eipDefinition.getJSONObject("locations").getJSONObject(mGateway.getString("location")).getString("name");
- } catch (JSONException e) {
- Log.v(TAG,"Couldn't read gateway name for profile creation! Returning original name = " + mName);
- e.printStackTrace();
- return (mName != null) ? mName : "";
- }
- }
-
-
- /**
- * Attempts to create a unique profile name
- * based on the location of the gateway.
- */
- private void setUniqueProfileName() {
- mVpnProfile.mName = mName = locationAsName();
- }
/**
* Create and attach the VpnProfile to our gateway object
@@ -464,17 +457,16 @@ public final class EIP extends IntentService {
protected void createVPNProfile(){
try {
ConfigParser cp = new ConfigParser();
- Log.d(TAG, configFromEipServiceDotJson());
- Log.d(TAG, caSecretFromSharedPreferences());
- Log.d(TAG, keySecretFromSharedPreferences());
- Log.d(TAG, certSecretFromSharedPreferences());
cp.parseConfig(new StringReader(configFromEipServiceDotJson()));
cp.parseConfig(new StringReader(caSecretFromSharedPreferences()));
cp.parseConfig(new StringReader(keySecretFromSharedPreferences()));
cp.parseConfig(new StringReader(certSecretFromSharedPreferences()));
+ cp.parseConfig(new StringReader("remote-cert-tls server"));
+ cp.parseConfig(new StringReader("persist-tun"));
VpnProfile vp = cp.convertProfile();
//vp.mAuthenticationType=VpnProfile.TYPE_STATICKEYS;
mVpnProfile = vp;
+ mVpnProfile.mName = mName = locationAsName();
Log.v(TAG,"Created VPNProfile");
} catch (ConfigParseError e) {
// FIXME We didn't get a VpnProfile! Error handling! and log level
@@ -604,6 +596,16 @@ public final class EIP extends IntentService {
return secret_lines;
}
- }
+
+ public String locationAsName() {
+ try {
+ return eipDefinition.getJSONObject("locations").getJSONObject(mGateway.getString("location")).getString("name");
+ } catch (JSONException e) {
+ Log.v(TAG,"Couldn't read gateway name for profile creation! Returning original name = " + mName);
+ e.printStackTrace();
+ return (mName != null) ? mName : "";
+ }
+ }
+ }
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java b/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java
index 5a5bb568..c8a28c0a 100644
--- a/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java
@@ -40,10 +40,6 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe
private View eipDetail;
private TextView eipStatus;
- private boolean eipAutoSwitched = true;
-
- private boolean mEipStartPending = false;
-
private static EIPReceiver mEIPReceiver;
@@ -53,29 +49,19 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
- eipFragment = inflater.inflate(R.layout.eip_service_fragment, container, false);
-
+ eipFragment = inflater.inflate(R.layout.eip_service_fragment, container, false);
eipDetail = ((RelativeLayout) eipFragment.findViewById(R.id.eipDetail));
eipDetail.setVisibility(View.VISIBLE);
View eipSettings = eipFragment.findViewById(R.id.eipSettings);
eipSettings.setVisibility(View.GONE); // FIXME too!
- if (mEipStartPending)
- eipFragment.findViewById(R.id.eipProgress).setVisibility(View.VISIBLE);
+ if (EIP.mIsStarting)
+ eipFragment.findViewById(R.id.eipProgress).setVisibility(View.VISIBLE);
eipStatus = (TextView) eipFragment.findViewById(R.id.eipStatus);
eipSwitch = (Switch) eipFragment.findViewById(R.id.eipSwitch);
-
-
- eipSwitch.setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- eipAutoSwitched = false;
- return false;
- }
- });
eipSwitch.setOnCheckedChangeListener(this);
if(getArguments() != null && getArguments().containsKey(START_ON_BOOT) && getArguments().getBoolean(START_ON_BOOT))
@@ -91,7 +77,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe
mEIPReceiver = new EIPReceiver(new Handler());
if (savedInstanceState != null)
- mEipStartPending = savedInstanceState.getBoolean(IS_EIP_PENDING);
+ EIP.mIsStarting = savedInstanceState.getBoolean(IS_EIP_PENDING);
}
@Override
@@ -113,7 +99,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
- outState.putBoolean(IS_EIP_PENDING, mEipStartPending);
+ outState.putBoolean(IS_EIP_PENDING, EIP.mIsStarting);
}
protected void saveEipStatus() {
@@ -124,71 +110,101 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe
}
if(getActivity() != null)
- getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE).edit().putBoolean(Dashboard.START_ON_BOOT, eip_is_on).commit();
+ Dashboard.preferences.edit().putBoolean(Dashboard.START_ON_BOOT, eip_is_on).commit();
}
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- if (buttonView.equals(eipSwitch) && !eipAutoSwitched){
- boolean allowed_anon = getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE).getBoolean(EIP.ALLOWED_ANON, false);
- String certificate = getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE).getString(EIP.CERTIFICATE, "");
- if(allowed_anon || !certificate.isEmpty()) {
- if (isChecked){
- startEipFromScratch();
- } else {
- if (mEipStartPending){
- AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getActivity());
- alertBuilder.setTitle(getResources().getString(R.string.eip_cancel_connect_title));
- alertBuilder
- .setMessage(getResources().getString(R.string.eip_cancel_connect_text))
- .setPositiveButton(getResources().getString(R.string.eip_cancel_connect_cancel), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- eipCommand(EIP.ACTION_STOP_EIP);
- mEipStartPending = false;
- }
- })
- .setNegativeButton(getResources().getString(R.string.eip_cancel_connect_false), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- eipAutoSwitched = true;
- eipSwitch.setChecked(true);
- eipAutoSwitched = false;
- }
- })
- .show();
- } else {
- eipCommand(EIP.ACTION_STOP_EIP);
- }
- }
- }
- else {
- Dashboard dashboard = (Dashboard)getActivity();
- Bundle waiting_on_login = new Bundle();
- waiting_on_login.putBoolean(IS_EIP_PENDING, true);
- dashboard.logInDialog(getActivity().getCurrentFocus(), waiting_on_login);
- }
- }
- else {
- if(!eipSwitch.isChecked()) {
- if(getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE).getString(EIP.STATUS, "").equalsIgnoreCase(ConnectionStatus.LEVEL_AUTH_FAILED.toString()))
- startEipFromScratch();
- else
- eipStatus.setText(R.string.state_noprocess);
- }
- }
- eipAutoSwitched = true;
- saveEipStatus();
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (buttonView.equals(eipSwitch)){
+ handleSwitch(isChecked);
}
+ }
+
+ private void handleSwitch(boolean isChecked) {
+ if(isChecked)
+ handleSwitchOn();
+ else
+ handleSwitchOff();
+ saveEipStatus();
+ }
+
+ private void handleSwitchOn() {
+ if(canStartEIP())
+ startEipFromScratch();
+ else if(canLogInToStartEIP()) {
+ Log.d(TAG, "Can Log In to start EIP");
+ Dashboard dashboard = (Dashboard) getActivity();
+ dashboard.logInDialog(Bundle.EMPTY);
+ }
+ }
+
+ private boolean canStartEIP() {
+ boolean certificateExists = !Dashboard.preferences.getString(EIP.CERTIFICATE, "").isEmpty();
+ boolean isAllowedAnon = Dashboard.preferences.getBoolean(EIP.ALLOWED_ANON, false);
+ return (isAllowedAnon || certificateExists) && !EIP.mIsStarting && !EIP.isConnected();
+ }
+
+ private boolean canLogInToStartEIP() {
+ boolean isAllowedRegistered = Dashboard.preferences.getBoolean(EIP.ALLOWED_REGISTERED, false);
+ boolean isLoggedIn = Dashboard.preferences.getBoolean(EIP.AUTHED_EIP, false);
+ Log.d(TAG, "Allow registered? " + isAllowedRegistered);
+ Log.d(TAG, "Is logged in? " + isLoggedIn);
+ return isAllowedRegistered && !isLoggedIn && !EIP.mIsStarting && !EIP.isConnected();
+ }
+
+ private void handleSwitchOff() {
+ if(EIP.mIsStarting) {
+ askPendingStartCancellation();
+ } else if(EIP.isConnected()) {
+ Log.d(TAG, "Stopping EIP");
+ stopEIP();
+ }
+ }
+
+ private void askPendingStartCancellation() {
+ AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getActivity());
+ alertBuilder.setTitle(getResources().getString(R.string.eip_cancel_connect_title))
+ .setMessage(getResources().getString(R.string.eip_cancel_connect_text))
+ .setPositiveButton((R.string.yes), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ stopEIP();
+ }
+ })
+ .setNegativeButton(getResources().getString(R.string.no), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Log.d(TAG, "askPendingStartCancellation checks the switch to true");
+ eipSwitch.setChecked(true);
+ }
+ })
+ .show();
+ }
public void startEipFromScratch() {
- mEipStartPending = true;
+ EIP.mIsStarting = true;
eipFragment.findViewById(R.id.eipProgress).setVisibility(View.VISIBLE);
- ((TextView) eipFragment.findViewById(R.id.eipStatus)).setText(R.string.eip_status_start_pending);
- eipSwitch.setChecked(true);
- saveEipStatus();
+ String status = getResources().getString(R.string.eip_status_start_pending);
+ setEipStatus(status);
+
+ if(!eipSwitch.isChecked()) {
+ Log.d(TAG, "startEipFromScratch checks the switch to true");
+ eipSwitch.setChecked(true);
+ saveEipStatus();
+ }
eipCommand(EIP.ACTION_START_EIP);
}
+
+ private void stopEIP() {
+ EIP.mIsStarting = false;
+ View eipProgressBar = getActivity().findViewById(R.id.eipProgress);
+ if(eipProgressBar != null)
+ eipProgressBar.setVisibility(View.GONE);
+
+ String status = getResources().getString(R.string.eip_state_not_connected);
+ setEipStatus(status);
+ eipCommand(EIP.ACTION_STOP_EIP);
+ }
/**
* Send a command to EIP
@@ -204,44 +220,98 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe
getActivity().startService(vpn_intent);
}
- @Override
- public void updateState(final String state, final String logmessage, final int localizedResId, final ConnectionStatus level) {
- // Note: "states" are not organized anywhere...collected state strings:
- // NOPROCESS,NONETWORK,BYTECOUNT,AUTH_FAILED + some parsing thing ( WAIT(?),AUTH,GET_CONFIG,ASSIGN_IP,CONNECTED,SIGINT )
- getActivity().runOnUiThread(new Runnable() {
-
- @Override
- public void run() {
- if (eipStatus != null) {
- boolean switchState = true;
- String statusMessage = "";
- String prefix = getString(localizedResId);
- if (level == ConnectionStatus.LEVEL_CONNECTED){
- statusMessage = getString(R.string.eip_state_connected);
- getActivity().findViewById(R.id.eipProgress).setVisibility(View.GONE);
- mEipStartPending = false;
- } else if ( level == ConnectionStatus.LEVEL_NONETWORK || level == ConnectionStatus.LEVEL_NOTCONNECTED || level == ConnectionStatus.LEVEL_AUTH_FAILED) {
- statusMessage = getString(R.string.eip_state_not_connected);
- if(getActivity() != null && getActivity().findViewById(R.id.eipProgress) != null)
- getActivity().findViewById(R.id.eipProgress).setVisibility(View.GONE);
- mEipStartPending = false;
- switchState = false;
- } else if (level == ConnectionStatus.LEVEL_CONNECTING_SERVER_REPLIED) {
- if(state.equals("AUTH") || state.equals("GET_CONFIG"))
- statusMessage = prefix + " " + logmessage;
- } else if (level == ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET) {
- statusMessage = prefix + " " + logmessage;
- }
-
- eipAutoSwitched = true;
- eipSwitch.setChecked(switchState);
- eipAutoSwitched = false;
- eipStatus.setText(statusMessage);
- }
- }
+ @Override
+ public void updateState(final String state, final String logmessage, final int localizedResId, final ConnectionStatus level) {
+ boolean isNewLevel = EIP.lastConnectionStatusLevel != level;
+ boolean justDecidedOnDisconnect = EIP.lastConnectionStatusLevel == ConnectionStatus.UNKNOWN_LEVEL;
+ Log.d(TAG, "update state with level " + level);
+ if(!justDecidedOnDisconnect && (isNewLevel || level == ConnectionStatus.LEVEL_CONNECTED)) {
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ EIP.lastConnectionStatusLevel = level;
+ handleNewState(state, logmessage, localizedResId, level);
+ }
});
+ } else if(justDecidedOnDisconnect && level == ConnectionStatus.LEVEL_CONNECTED) {
+ EIP.lastConnectionStatusLevel = ConnectionStatus.LEVEL_NOTCONNECTED;
+ updateState(state, logmessage, localizedResId, level);
}
+ }
+
+ private void handleNewState(final String state, final String logmessage, final int localizedResId, final ConnectionStatus level) {
+ if (level == ConnectionStatus.LEVEL_CONNECTED)
+ setConnectedUI();
+ else if (isDisconnectedLevel(level) && !EIP.mIsStarting)
+ setDisconnectedUI();
+ else if (level == ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET)
+ setNoServerReplyUI(localizedResId, logmessage);
+ else if (level == ConnectionStatus.LEVEL_CONNECTING_SERVER_REPLIED)
+ setServerReplyUI(state, localizedResId, logmessage);
+ }
+
+ private boolean isDisconnectedLevel(final ConnectionStatus level) {
+ return level == ConnectionStatus.LEVEL_NONETWORK || level == ConnectionStatus.LEVEL_NOTCONNECTED || level == ConnectionStatus.LEVEL_AUTH_FAILED;
+ }
+
+ private void setConnectedUI() {
+ hideProgressBar();
+ Log.d(TAG, "mIsDisconnecting = false in setConnectedUI");
+ EIP.mIsStarting = false; //TODO This should be done in the onReceiveResult from START_EIP command, but right now LaunchVPN isn't notifying anybody the resultcode of the request so we need to listen the states with this listener.
+ EIP.mIsDisconnecting = false; //TODO See comment above
+ String status = getString(R.string.eip_state_connected);
+ setEipStatus(status);
+ adjustSwitch();
+ }
+ private void setDisconnectedUI(){
+ hideProgressBar();
+ EIP.mIsStarting = false; //TODO See comment in setConnectedUI()
+ Log.d(TAG, "mIsDisconnecting = false in setDisconnectedUI");
+ EIP.mIsDisconnecting = false; //TODO See comment in setConnectedUI()
+
+ String status = getString(R.string.eip_state_not_connected);
+ setEipStatus(status);
+ adjustSwitch();
+ }
+
+ private void adjustSwitch() {
+ if(EIP.isConnected()) {
+ if(!eipSwitch.isChecked()) {
+ eipSwitch.setChecked(true);
+ }
+ } else {
+ if(eipSwitch.isChecked()) {
+ eipSwitch.setChecked(false);
+ }
+ }
+ }
+
+ private void setNoServerReplyUI(int localizedResId, String logmessage) {
+ if(eipStatus != null) {
+ String prefix = getString(localizedResId);
+ setEipStatus(prefix + " " + logmessage);
+ }
+ }
+
+ private void setServerReplyUI(String state, int localizedResId, String logmessage) {
+ if(eipStatus != null)
+ if(state.equals("AUTH") || state.equals("GET_CONFIG")) {
+ String prefix = getString(localizedResId);
+ setEipStatus(prefix + " " + logmessage);
+ }
+ }
+
+ protected void setEipStatus(String status) {
+ if(eipStatus == null)
+ eipStatus = (TextView) getActivity().findViewById(R.id.eipStatus);
+ eipStatus.setText(status);
+ }
+
+ private void hideProgressBar() {
+ if(getActivity() != null && getActivity().findViewById(R.id.eipProgress) != null)
+ getActivity().findViewById(R.id.eipProgress).setVisibility(View.GONE);
+ }
/**
* Inner class for handling messages related to EIP status and control requests
@@ -273,8 +343,10 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe
} else if (request == EIP.ACTION_START_EIP) {
switch (resultCode){
case Activity.RESULT_OK:
+ Log.d(TAG, "Action start eip = Result OK");
checked = true;
eipFragment.findViewById(R.id.eipProgress).setVisibility(View.VISIBLE);
+ EIP.mIsStarting = false;
break;
case Activity.RESULT_CANCELED:
checked = false;
@@ -307,9 +379,10 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe
break;
case Activity.RESULT_CANCELED:
Dashboard dashboard = (Dashboard) getActivity();
-
+
dashboard.setProgressBarVisibility(ProgressBar.VISIBLE);
- dashboard.setEipStatus(R.string.updating_certificate_message);
+ String status = getResources().getString(R.string.updating_certificate_message);
+ setEipStatus(status);
Intent provider_API_command = new Intent(getActivity(), ProviderAPI.class);
if(dashboard.providerAPI_result_receiver == null) {
@@ -323,10 +396,6 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe
break;
}
}
-
- eipAutoSwitched = true;
- eipSwitch.setChecked(checked);
- eipAutoSwitched = false;
}
}
@@ -341,6 +410,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe
public void checkEipSwitch(boolean checked) {
eipSwitch.setChecked(checked);
- onCheckedChanged(eipSwitch, checked);
+ // Log.d(TAG, "checkEipSwitch");
+ // onCheckedChanged(eipSwitch, checked);
}
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/EipStatusReceiver.java b/app/src/main/java/se/leap/bitmaskclient/EipStatusReceiver.java
deleted file mode 100644
index 8793cf36..00000000
--- a/app/src/main/java/se/leap/bitmaskclient/EipStatusReceiver.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package se.leap.bitmaskclient;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-
-
-public class EipStatusReceiver extends BroadcastReceiver {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals("de.blinkt.openvpn.VPN_STATUS")) {
- context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, Context.MODE_PRIVATE).edit().putString(EIP.STATUS, intent.getStringExtra("status")).commit();
- }
- }
-}
diff --git a/app/src/main/res/values-cs/strings-icsopenvpn.xml b/app/src/main/res/values-cs/strings-icsopenvpn.xml
index 179f81f1..b13bfcdd 100755
--- a/app/src/main/res/values-cs/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-cs/strings-icsopenvpn.xml
@@ -215,6 +215,7 @@
<string name="vpn_import_hint">Použij ikonu &lt;img src=\"ic_menu_archive\"/&gt; k imporu existujícího (.ovpn nebo .conf) profilu z SD karty.</string>
<string name="faq_hint">Ujisti se, že jsi si pročetl FAQ. Je zde nápověda pro rychlý start.</string>
<string name="faq_routing_title">Nastavení směrování/rozhraní</string>
+ <string name="faq_routing">Směrování a konfigurace rozhraní není provedena pomocí tradičních příkazů ifconfig/route, ale pomocí VPNService API. To má za následek odlišnou konfiguraci směrování, než na jiných operačních systémech. Konfigurace VPN tunelu se skládá z IP adresy a sítě, která má být směrována skrze toto rozhraní. Zejména není potřeba adresa protistrany nebo brány. Speciální směrování pro dosažení VPN serveru (například v případě použití redirect-gataway direktivy) také není potřeba. Aplikace bude toto nastavení při importu konfigurace ignorovat. Aplikace pomocí VPNService API zajišťuje, že spojení k VPN serveru není směrováno skrze tunel. Povoleno je pouze specifikování sítí, které se mají směrovat skrze tunel. Aplikace se snaží detekovat sítě, které by neměli procházet tunelem (např. route x.x.x.x y.y.y.y net_gateway) a vypočítává nastavení směrování tak, aby emulovalo správné chováni jako na ostatních platformách. Logovací okno ukazuje konfiguraci VPNService při navázání spojení.</string>
<string name="persisttun_summary">Nevracej se ke spojení mimo VPN, zatímco se OpenVPN připojuje.</string>
<string name="persistent_tun_title">Trvalý tun</string>
<string name="openvpn_log">OpenVPN Log</string>
@@ -311,10 +312,11 @@
<string name="unhandled_exception_context">%3$s: %1$s\n\n%2$s</string>
<string name="faq_system_dialog_xposed">Pokud máš rootnuté zařízení, můžeš nainstalovat &lt;a href=\"http://xposed.info/\"&gt;Xposed framework&lt;/a&gt; a &lt;a href=\"http://repo.xposed.info/module/de.blinkt.vpndialogxposed\"&gt;VPN potvrzovací modul&lt;/a&gt; na vlastní nebezpečí\"</string>
<string name="full_licenses">Plné licence</string>
- <string name="blocklocal_summary">Sítě přímo připojené na lokální interface nebudou směrovány skrze VPN. Odškrtnutím této volby bude přesměrován všechen lokální provoz do VPN.</string>
+ <string name="blocklocal_summary">Sítě přímo připojené na lokální rozhraní nebudou směrovány skrze VPN. Odškrtnutím této volby bude přesměrován všechen lokální provoz do VPN.</string>
<string name="blocklocal_title">Nepoužívat VPN pro lokální sítě</string>
<string name="userpw_file">Soubor pro Jméno/Heslo</string>
<string name="imported_from_file">[Importováno z: %s]</string>
- <string name="files_missing_hint">Některé soubory nemohly být nalezeny. Prosím vyberte profil, který chcete importovat:</string>
+ <string name="files_missing_hint">Některé soubory nemohly být nalezeny. Prosím vyber profil, který chceš importovat:</string>
+ <string name="openvpn_is_no_free_vpn">Pro používání této aplikace je potřeba VPN poskytovatel/brána, která podporuje OpenVPN (často je to zaměstnavatel). Pro více informací a návod na nastavení OpenVPN serveru navštiv http://community.openvpn.net/</string>
<string name="import_log">Import logu:</string>
</resources>
diff --git a/app/src/main/res/values-hu/strings-icsopenvpn.xml b/app/src/main/res/values-hu/strings-icsopenvpn.xml
new file mode 100755
index 00000000..99c5201f
--- /dev/null
+++ b/app/src/main/res/values-hu/strings-icsopenvpn.xml
@@ -0,0 +1,284 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.net-->
+<!-- Generated by crowdin.net -->
+<resources>
+
+ <string name="address">Szerver cím:</string>
+ <string name="port">Szerver port:</string>
+ <string name="location">Hely</string>
+ <string name="cant_read_folder">A könyvtár nem olvasható</string>
+ <string name="select">Választ</string>
+ <string name="cancel">Mégsem</string>
+ <string name="no_data">Nincs Adat</string>
+ <string name="useLZO">LZO tömörítés</string>
+ <string name="client_no_certificate">Nincs Tanúsítvány</string>
+ <string name="client_certificate_title">Kliens Tanúsítvány</string>
+ <string name="client_key_title">Kliens Privátkulcs</string>
+ <string name="client_pkcs12_title">PKCS12 Fájl</string>
+ <string name="ca_title">CA Tanúsítvány</string>
+ <string name="no_certificate">Válasszon egy tanúsítványt</string>
+ <string name="copyright_guicode">A forráskód és a hibakezelő elérhetősége http://code.google.com/p/ics-openvpn/</string>
+ <string name="copyright_others">A program a következő komponenseket használja; a licenszek összes részletei a forráskódban találhatóak</string>
+ <string name="about">Névjegy</string>
+ <string name="vpn_list_title">Profilok</string>
+ <string name="vpn_type">Típus</string>
+ <string name="pkcs12pwquery">PKCS12 Jelszó</string>
+ <string name="file_select">Válasszon&#8230;</string>
+ <string name="file_nothing_selected">Válasszon egy fájlt</string>
+ <string name="useTLSAuth">TLS-hitelesítés használata</string>
+ <string name="tls_direction">TLS irány</string>
+ <string name="ipv6_dialog_tile">Adja meg az IPv6 címet CIDR formában (pl.: 2000:dd::23/64)</string>
+ <string name="ipv4_dialog_title">Adja meg az IPv4 címet CIDR formában (pl.: 1.2.3.4/24)</string>
+ <string name="ipv4_address">IPv4 Cím</string>
+ <string name="ipv6_address">IPv6 Cím</string>
+ <string name="custom_option_warning">Egyéni OpenVPN opciók megadása. Körültekintéssel használja! Vegye figyelembe, hogy a tun-nal kapcsolatos OpenVPN beállítások nem támogatottak a VPNSettings felépítéséből adódóan. Ha úgy gondolja, hogy egy fontos opció hiányzik, lépjen kapcsolatba a fejlesztőkkel</string>
+ <string name="auth_username">Felhasználónév</string>
+ <string name="auth_pwquery">Jelszó</string>
+ <string name="static_keys_info">A statikus konfigurációhoz a TLS Auth Key-ek statikus kulcsokként lesznek használva</string>
+ <string name="configure_the_vpn">A VPN beállítása</string>
+ <string name="menu_add_profile">Profil hozzáadása</string>
+ <string name="add_profile_name_prompt">Adja meg az új Profil nevét</string>
+ <string name="duplicate_profile_name">Kérlek, egyedi profilnevet válassz magadnak</string>
+ <string name="profilename">Profil név</string>
+ <string name="no_keystore_cert_selected">Válassz egy felhasználói tanúsítványt</string>
+ <string name="no_error_found">hiba nem található</string>
+ <string name="config_error_found">Hiba a beállításokban</string>
+ <string name="ipv4_format_error">Hiba az IPv4 cím elemzésekor</string>
+ <string name="custom_route_format_error">Hiba az egyéni útvonalak elemzésekor</string>
+ <string name="pw_query_hint">(a lekérdezés igénye szerint hagyja üresen)</string>
+ <string name="vpn_shortcut">OpenVPN parancsikon</string>
+ <string name="vpn_launch_title">Csatlakozás a VPN-hez</string>
+ <string name="shortcut_profile_notfound">A parancsikonban kiválasztott Profil nem létezik</string>
+ <string name="random_host_prefix">Véletlen Host Prefix</string>
+ <string name="random_host_summary">6 random karakter hozzáadása a hosztnév elejére</string>
+ <string name="custom_config_title">Egyéni Beállítások engedélyezése</string>
+ <string name="custom_config_summary">Egyéni beállítások megadása. Óvatosan használja!</string>
+ <string name="route_rejected">Az Android elutasította az útvonalat</string>
+ <string name="cancel_connection">Szétkapcsolás</string>
+ <string name="cancel_connection_long">VPN kapcsolat szétkapcsolása</string>
+ <string name="clear_log">napló törlése</string>
+ <string name="title_cancel">jóváhagyás törlése</string>
+ <string name="cancel_connection_query">VPN kapcsolat/kapcsolódás megszakítása?</string>
+ <string name="remove_vpn">VPN kapcsolat eltávolítása</string>
+ <string name="check_remote_tlscert">Ellenőrzi, hogy a kiszolgáló használ-e tanúsitványt TLS Server kiterjesztéssel (--remote-cert-tls server)</string>
+ <string name="check_remote_tlscert_title">TLS server tanúsítvány megkövetelése</string>
+ <string name="remote_tlscn_check_summary">Ellenőrzi a Távoli Kiszolgáló Tanúsítvány Subject DN mezőt</string>
+ <string name="remote_tlscn_check_title">Tanúsítvány Kiszolgálónév Ellenőrzés</string>
+ <string name="enter_tlscn_dialog">Adja meg a távoli tanúsítvány DN ellenőrzését (pl.: C=DE, L=Paderborn, OU=Avian IP Carriers, CN=openvpn.blinkt.de)\n\nAdja meg a teljes DN-t vagy az RDN-t (openvpn.blinkt.de a példában) vagy egy RDN prefix-et az ellenőrzéshez.\n\nRDN prefix használatakor a \"Server\" egyezik a \"Server-1\"-gyel és a \"Server-2\"-vel\n\nA mező üresen hagyásakor az RDN a kiszolgáló nevével kerül ellenőrzésre.\n\nTovábbi részleteket az OpenVPN 2.3.1+ manuál oldalon talál —verify-x509-name</string>
+ <string name="enter_tlscn_title">Távoli tanúsítvány tárgy</string>
+ <string name="tls_key_auth">TLS Key Hitelesítés engedélyetése</string>
+ <string name="tls_auth_file">TLS Auth Fájl</string>
+ <string name="pull_on_summary">IP címek, útvonalak és időzítések lekérése a kiszolgálótól.</string>
+ <string name="pull_off_summary">Nem történt információkérés a kiszolgálótól. Alul meg kell adni a beállításokat.</string>
+ <string name="use_pull">Pull Beállítások</string>
+ <string name="dns">DNS</string>
+ <string name="override_dns">A kiszolgálótól kapott DNS Beállítások felülbírálása</string>
+ <string name="dns_override_summary">Saját DNS Szerverek használata</string>
+ <string name="searchdomain">searchDomain</string>
+ <string name="dns1_summary">a használatban levő DNS-kiszolgáló.</string>
+ <string name="dns_server">DNS szerver</string>
+ <string name="secondary_dns_message">A másodlagos DNS-kiszolgáló használható, ha a normál DNS-kiszolgáló nem érhető el.</string>
+ <string name="backup_dns">tartalék DNS szerver</string>
+ <string name="ignored_pushed_routes">Push-olt útvonalak figyelmen kívül hagyása</string>
+ <string name="ignore_routes_summary">A szerver által push-olt útvonalak figyelmen kívül hagyása.</string>
+ <string name="default_route_summary">A teljes forgalom átirányítása a VPN-re</string>
+ <string name="use_default_title">használja az alapértelmezett útvonalat</string>
+ <string name="custom_route_message">Egyéni útvonalak megadása. A célt csak CIDR formátumban adja meg. \"10.0.0.0/8 2002::/16\" átirányítaná a 10.0.0.0/8 és 2002::/16 hálózatokat a VPN-en.</string>
+ <string name="custom_route_message_excluded">Útvonalak amikek nem a VPN-en át kell route-olni.</string>
+ <string name="custom_routes_title">Egyéni útvonalak</string>
+ <string name="custom_routes_title_excluded">Hálózat kivételek</string>
+ <string name="log_verbosity_level">Napló részletességi szint</string>
+ <string name="float_summary">Hitelesített csomagok engedélyezése minden IP-ről</string>
+ <string name="float_title">Lebegő szerver engedélyezése</string>
+ <string name="custom_options_title">Egyéni beállítások</string>
+ <string name="edit_vpn">VPN-beállítások szerkesztése</string>
+ <string name="remove_vpn_query">\'%s\' VPN Profil eltávolítása?</string>
+ <string name="tun_error_helpful">Néhány egyedi ICS image-en a /dev/tun hozzáférési jogai rosszak lehetnek, vagy a tun modul teljesen hiányzik. CM9 imagek-en próbálja a fix tulajdonos opciót az általános beállításokban</string>
+ <string name="tun_open_error">Nem sikerült megnyitni a tun interfészt</string>
+ <string name="error">"Hiba:"</string>
+ <string name="clear">töröl</string>
+ <string name="last_openvpn_tun_config">tun interfész megnyitása:</string>
+ <string name="local_ip_info">Helyi IPv4: %1$s/%2$d IPv6: %3$s MTU: %4$d</string>
+ <string name="dns_server_info">DNS Szerver: %1$s, Domain: %2$s</string>
+ <string name="routes_info_incl">Útvonalak: %1$s %2$s</string>
+ <string name="routes_info_excl">Kizárt útvonalak: %1$s %2$s</string>
+ <string name="routes_debug">VpnService útvonalak telepítve: %1$s %2$s</string>
+ <string name="ip_not_cidr">Érkezett interfész információk: %1$s és %2$s, feltételezve a második cím a távoli oldali cím. /32 alhálózati maszk lesz használva a helyi IP-hez. OpenVPN beállította a módokat: \"%3$s\".</string>
+ <string name="route_not_cidr">Nincs értelme a %1$s és %2$s-nek, mint IP útvonalnak CIDR alhálózati maszkkal, /32 alhálózati maszk kerül használatra.</string>
+ <string name="route_not_netip">Az %1$s/%2$s útvonal javítva: %3$s/%2$s</string>
+ <string name="keychain_access">Nem sikerült hozzáférni az Android Keychain Tanúsivànyokhoz. Ezt egy firmware frissítés vagy az alkalmazás/beállításainak visszaállítása okozhatja. Kérem szerkessze meg a VPN-t, és újra válassza ki a tanúsítványokat az alapvető beállításoknál, hogy visszaálljanak a tanúsítványok hozzáférési jogai.</string>
+ <string name="version_info">%1$s %2$s</string>
+ <string name="send_logfile">naplófájl küldése</string>
+ <string name="send">küld</string>
+ <string name="ics_openvpn_log_file">ICS OpenVPN naplófájl</string>
+ <string name="copied_entry">Naplóbejegyzés másolva a vágólapra</string>
+ <string name="tap_mode">Tap mód</string>
+ <string name="faq_tap_mode">Tap mód nem lehetséges nem-root VPN API-val. Ez által az alkalmazás nem kínál tap támogatást</string>
+ <string name="tap_faq2">Megint? Viccelsz? Nem, a tap mód tényleg nem támogatott és további levelek küldése hogy támogatott lesz-e sem fog segíteni.</string>
+ <string name="tap_faq3">Harmadszor is? Tulajdonképpen lehetne írni egy tap emulátort a tun alapján ami képes layer2 adatokat is küldeni és fogadni, de ennek a tap emulátornak implementálnia kell ARP-t és lehetőleg egy DHCP klienst is. Nem tudok róla, hogy bárki is ezen az irányon dolgozna. Ha lenne kedve ilyet kódolni, lépjen kapcsolatba velem.</string>
+ <string name="faq">GYIK</string>
+ <string name="copying_log_entries">naplóbejegyzések másolása</string>
+ <string name="faq_copying">Másoláshoz nyomja le és tartsa lenyomva a naplóbejegyzést. A teljes napló küldéséhez használja a Napló Küldése opciót. Használja a hardver menü gombot ha nem látható a GUI-ban.</string>
+ <string name="faq_shortcut">Parancsikon az indításhoz</string>
+ <string name="faq_howto_shortcut">Az asztalra helyezhet egy OpenVPN parancsikont. A képernyőkezelő programtól függően parancsikont vagy widget-et helyezhet el.</string>
+ <string name="no_vpn_support_image">Az image-ed nem támogatja a VPNService API-t, elnézést :(</string>
+ <string name="encryption">Titkosítás</string>
+ <string name="cipher_dialog_title">Adja meg a titkosítási módszert</string>
+ <string name="chipher_dialog_message">Adja meg az OpenVPN által használt titkosítási algoritmust. Hagyja üresen az alapértelmezett kódoláshoz.</string>
+ <string name="auth_dialog_message">Adja meg az OpenVPN által használt authentication digest-et. Hagyja üresen az alapértelmezett digest-hez.</string>
+ <string name="settings_auth">Hitelesítés/Titkosítás</string>
+ <string name="file_explorer_tab">Fájlkezelő</string>
+ <string name="inline_file_tab">Beágyazott fájl</string>
+ <string name="error_importing_file">Hiba a fájl importálása közben</string>
+ <string name="import_error_message">Nem sikerült importálni a Fájlt a fájlrendszerből</string>
+ <string name="inline_file_data">[[Beágyazott fájladatok]]</string>
+ <string name="opentun_no_ipaddr">IP információ nélküli tun eszköz megnyitás megtagadva</string>
+ <string name="menu_import">Profil import ovpn fájlból</string>
+ <string name="menu_import_short">Import</string>
+ <string name="import_content_resolve_error">Nem sikerült beolvasni az importálási profilt</string>
+ <string name="error_reading_config_file">Hiba a konfigurációs fájl olvasása közben</string>
+ <string name="add_profile">Profil hozzáadása</string>
+ <string name="import_could_not_open">%1$s fájl nem található, pedig az importált konfigurációs fájlban hivatkozás van rá</string>
+ <string name="importing_config">Konfigurációs fájl importálása %1$s forrásból</string>
+ <string name="import_warning_custom_options">A konfiguráció tartalmaz néhány opciót, amik nincsenek UI konfigurációhoz rendelve. Ezek az opciók az egyéni konfiguráció alatt találhatók. Az egyéni konfiguráció lent látható:</string>
+ <string name="import_done">Konfigurációs fájl olvasása kész.</string>
+ <string name="nobind_summary">Ne bind-eljen helyi címhez és porthoz</string>
+ <string name="no_bind">Nincs helyi bind</string>
+ <string name="import_configuration_file">Konfigurációs fájl importálása</string>
+ <string name="faq_security_title">Biztonsági szempontok</string>
+ <string name="import_vpn">Import</string>
+ <string name="broken_image_cert_title">Hiba a tanúsítvány kiválasztása során</string>
+ <string name="broken_image_cert">Exception történt az Android 4.0+ tanúsítvány legördülő megjelenítésekor. Ennek sohasem szabad megtörténnie, mivel ez egy szavványos Android 4.0+ funkció. Lehet, hogy az Android ROM tanúsítványtár támogatása nem működik megfelelően</string>
+ <string name="ipv4">IPv4</string>
+ <string name="ipv6">IPv6</string>
+ <string name="speed_waiting">Állapot üzenetre várakozás&#8230;</string>
+ <string name="converted_profile">importált profil</string>
+ <string name="converted_profile_i">%d profil importálva</string>
+ <string name="broken_images">Működésképtelen image-ek</string>
+ <string name="pkcs12_file_encryption_key">PKCS12 Fájltitkosítási kulcs</string>
+ <string name="private_key_password">Privát kulcs jelszó</string>
+ <string name="password">Jelszó</string>
+ <string name="file_icon">fájlikon</string>
+ <string name="tls_authentication">TLS hitelesítés</string>
+ <string name="generated_config">Generált konfiguráció</string>
+ <string name="generalsettings">Beállítások</string>
+ <string name="owner_fix_summary">/dev/tun tulajdonosának beállítása. Néhány CM9 image-hez ez kell, hogy a VPNService API működjön. Root szükséges.</string>
+ <string name="owner_fix">Fix tulajdonos a /dev/tun-hoz</string>
+ <string name="generated_config_summary">Generált OpenVPN konfigurációs fájl megmutatása</string>
+ <string name="edit_profile_title">\"%s\" szerkesztése</string>
+ <string name="building_configration">Konfiguráció felépítése&#8230;</string>
+ <string name="netchange_summary">Ennek az opciónak a bekapcsolása erőlteti az újracsatlakozást ha a hálózati állapot megváltozik (pl.: WiFi-re/ről mobil-ra/ról)</string>
+ <string name="netchange">Újracsatlakozás hálózatváltáskor</string>
+ <string name="netstatus">Hálózati állapot: %s</string>
+ <string name="extracahint">A CA tanúsítvány általában visszajön az Android Keystore-ból. Adjon meg egy külön tanúsítványt ha tanúsítvány-ellenőrzési hibát kap.</string>
+ <string name="select_file">Választ</string>
+ <string name="keychain_nocacert">Nem jött vissza CA tanúsítvány az Android keystore olvasása során. A hitelesítés valószínűleg sikertelen lesz.</string>
+ <string name="show_log_summary">Napló ablak mutatása a csatlakozás alatt. A napló ablak mindig elérető a rolóról is.</string>
+ <string name="show_log_window">Naplózási ablak mutatása</string>
+ <string name="mobile_info">%1$s (%2$s) %3$s, Android API %4$d</string>
+ <string name="error_rsa_sign">Hiba az Android keystore %1$s: %2$s kulccsal való belépéskor</string>
+ <string name="faq_system_dialogs_title">Kapcsolat figyelmeztetés és értesítés hang</string>
+ <string name="translationby">A magyar fordítást készítette Juhász Sándor &lt;msc@digitaltrip.hu&gt;</string>
+ <string name="ipdns">IP és DNS</string>
+ <string name="basic">Alapvető</string>
+ <string name="routing">Útválasztás</string>
+ <string name="obscure">Obscure OpenVPN beállítások. Általában nem szükséges.</string>
+ <string name="advanced">Speciális</string>
+ <string name="export_config_title">ICS Openvpn Konfiguráció</string>
+ <string name="warn_no_dns">Nincsenek DNS szerverek használatban. A névfeloldás nem működik. Fontolja meg az egyéni DNS szerverek beállítását. Kérjük, vegye figyelembe, hogy az Android továbbra is ugyanazokat a proxy beállításokat fogja használni a mobil/WiFi csatlakozáshoz, mint amit a DNS szerverek megadása előtt.</string>
+ <string name="dns_add_error">Nem lehet hozzáadni a %1$s DNS szervert, a rendszer elutasította: %2$s</string>
+ <string name="ip_add_error">A \"%1$s\" IP címet nem lehet konfigurálni, a rendszer elutasította: %2$s</string>
+ <string name="faq_howto_title">Quick Start</string>
+ <string name="setting_loadtun_summary">Próbálja meg betölteni a tun.ko kernel modult mielőtt megpróbál csatlakozni. Root-olt eszköz szükséges.</string>
+ <string name="setting_loadtun">Tun modul betöltése</string>
+ <string name="importpkcs12fromconfig">PKCS12 konfiguráció importálása az Android Keystore-ba</string>
+ <string name="getproxy_error">Hiba a proxy beállítások lekérésekor: %s</string>
+ <string name="using_proxy">Proxy használatban: %1$s %2$d</string>
+ <string name="use_system_proxy">Rendszerproxy használata</string>
+ <string name="use_system_proxy_summary">Rendszerszintű konfiguráció használata a HTTP/HTTPS proxy csatlakozáshoz.</string>
+ <string name="donatewithpaypal">&lt;a href=\"https://www.paypal.com/cgi-bin/webscr?hosted_button_id=R2M6ZP9AF25LS&amp;amp;cmd=_s-xclick\"&gt;Adakozhat PayPal-al&lt;/a&gt; </string>
+ <string name="onbootrestartsummary">Az OpenVPN újracsatlakozik a VPN-hez ha az aktív volt az újraindításkoz/leállításkor.</string>
+ <string name="onbootrestart">Újracsatlakozás újraindításkor</string>
+ <string name="ignore">Hagyja figyelmen kívül</string>
+ <string name="restart">Újraindítás</string>
+ <string name="restart_vpn_after_change">A konfiguráció változások a VPN újraindítása után lépnek életbe. (Újra)indítja most a VPN-t?</string>
+ <string name="configuration_changed">A konfiguráció megváltozott</string>
+ <string name="log_no_last_vpn">A legutóbb csatlakozott profil nem található</string>
+ <string name="no_vpn_profiles_defined">Nincsenek VPN profilok definiálva.</string>
+ <string name="add_new_vpn_hint">Használd az &lt;img src=\"ic_menu_add\"/&gt; ikont új VPN hozzáadásához</string>
+ <string name="vpn_import_hint">Használd az &lt;img src=\"ic_menu_archive\"/&gt; ikont egy SD-kártyán meglevő (.ovpn or .conf) profil importálásához.</string>
+ <string name="faq_hint">Tekintse meg a FAQ-ot. Ott van egy a kezdeti lépéseket segítő leírás.</string>
+ <string name="faq_routing_title">Routing/Interfész Beállítás</string>
+ <string name="persisttun_summary">Ne térjen vissza VPN kapcsolat nélküli módba, amikor az OpenVPN újracsatlakozik.</string>
+ <string name="persistent_tun_title">Megmaradó tun</string>
+ <string name="openvpn_log">OpenVPN Napló</string>
+ <string name="import_config">OpenVPN konfiguráció importálása</string>
+ <string name="battery_consumption_title">Akkumulátor használat</string>
+ <string name="vpn_tethering_title">VPN és Internetmegosztás</string>
+ <string name="connection_retries">Csatlakozás újrapróbálkozások</string>
+ <string name="reconnection_settings">Újracsatlakozás beállítások</string>
+ <string name="connectretrymessage">Csatlakozási próbálkozások közötti várakozási idő másodpercben.</string>
+ <string name="connectretrywait">Csatlakozások közotti idő másodpercben</string>
+ <string name="minidump_generated">Az OpenVPN váratlanul összeomlott. Kérem, gondolja meg a főmenüben levő Minidump elküldése opció használatát</string>
+ <string name="send_minidump">Minidump elküldése a fejlesztőnek</string>
+ <string name="send_minidump_summary">Hibakeresési információkat küld a fejlesztőnek a legutóbbi összeomlásról</string>
+ <string name="notifcation_title">OpenVPN - %s</string>
+ <string name="session_ipv4string">%1$s - %2$s</string>
+ <string name="session_ipv6string">%1$s - %3$s, %2$s</string>
+ <string name="state_connecting">Csatlakozás</string>
+ <string name="state_wait">Várakozás a szerver válaszára</string>
+ <string name="state_auth">Hitelesítés</string>
+ <string name="state_get_config">Kliens konfiguráció lekérése</string>
+ <string name="state_assign_ip">IP címek kiosztása</string>
+ <string name="state_add_routes">Útvonalak hozzáadása</string>
+ <string name="state_connected">Csatlakoztatva</string>
+ <string name="state_disconnected">Szétkapcsolás</string>
+ <string name="state_reconnecting">Újracsatlakozás</string>
+ <string name="state_exiting">Kilépés</string>
+ <string name="state_noprocess">Nem fut</string>
+ <string name="state_resolve">Állomásnevek feloldása</string>
+ <string name="state_tcp_connect">Csatlakozás (TCP)</string>
+ <string name="state_auth_failed">Hitelesítési hiba</string>
+ <string name="state_nonetwork">Várakozás használható hálózatra</string>
+ <string name="statusline_bytecount">↓%2$s/s %1$s - ↑%4$s/s %3$s</string>
+ <string name="notifcation_title_notconnect">Nincs kapcsolat</string>
+ <string name="start_vpn_title">Csatlakozás VPN-hez %s</string>
+ <string name="start_vpn_ticker">Csatlakozás VPN-hez %s</string>
+ <string name="jelly_keystore_alphanumeric_bug">Néhány Android 4.1-es verzió alatt problémába ütközhet ha a hitelesítési tanúsítvány nevében nem csak alfanumerikus karakterek szerepelnek (mint pl szóköz, alulvonás vagy kötőjel). Speciális karakterek nélkül próbálja újra importálni</string>
+ <string name="encryption_cipher">Titkosítás</string>
+ <string name="packet_auth">Csomag hitelesítés</string>
+ <string name="auth_dialog_title">Adja meg a csomaghitelesítési metódust</string>
+ <string name="mobile_info_extended">%1$s (%2$s) %3$s, Android API %4$d, %5$s, %6$s verzió</string>
+ <string name="built_by">%s fordítóval</string>
+ <string name="debug_build">hibakeresési fordítás</string>
+ <string name="official_build">hivatalos build</string>
+ <string name="make_selection_inline">Másolás profilba</string>
+ <string name="crashdump">Crashdump</string>
+ <string name="add">Hozzáad</string>
+ <string name="send_config">Konfig fájl küldése</string>
+ <string name="complete_dn">Teljes DN</string>
+ <string name="remotetlsnote">Az importált konfiguráció a régi tls-remote konfigurációt használta, ami egy másik DN formátumban volt.</string>
+ <string name="rdn">RDN (közös név)</string>
+ <string name="rdn_prefix">RDN előtag</string>
+ <string name="tls_remote_deprecated">tls-remote (elavult)</string>
+ <string name="help_translate">Segíthetsz fordítani ha meglátogatod http://crowdin.net/project/ics-openvpn/invite</string>
+ <string name="prompt">%1$s próbálkozás %2$s vezérlésre</string>
+ <string name="remote_trust">Megbízom ebben az alkalmazásban.</string>
+ <string name="no_external_app_allowed">Egy alkalmazás sem használhat külső API-t</string>
+ <string name="allowed_apps">Engedélyezett alkalmazások: %s</string>
+ <string name="clearappsdialog">Engedélyezett külső alkalmazások listájának törlése?\nAz engedélyezett alkalmazások aktuális listája:\n\n%s</string>
+ <string name="screenoff_title">VPN kapcsolat szüneteltetése a képernyő lekapcsolása után</string>
+ <string name="screenoff_pause">Kapcsolat szüneteltetése a képernyő kikapcsolt állapotában: kevesebb mint %1$s %2$ss alatt</string>
+ <string name="screen_nopersistenttun">Figyelmeztetés: Megmaradó tun nem engedélyezett ehhez a VPN-hez. A forgalom a normál internetcsatlakozáson megy amikor a képernyő ki van kapcsolva.</string>
+ <string name="save_password">Jelszó mentése</string>
+ <string name="timestamp_short">Rövid</string>
+ <string name="timestamp_iso">ISO</string>
+ <string name="timestamps">Időbélyegzők</string>
+ <string name="timestamps_none">Egyik sem</string>
+ <string name="uploaded_data">Feltöltés</string>
+ <string name="downloaded_data">Letöltés</string>
+ <string name="vpn_status">Vpn állapot</string>
+ <string name="logview_options">Nézet beállításai</string>
+ <string name="unhandled_exception">Nem kezelt kivétel: %1$s\n\n%2$s</string>
+ <string name="full_licenses">Teljes engedélyek</string>
+</resources>
diff --git a/app/src/main/res/values-in/strings-icsopenvpn.xml b/app/src/main/res/values-in/strings-icsopenvpn.xml
new file mode 100755
index 00000000..ccb60754
--- /dev/null
+++ b/app/src/main/res/values-in/strings-icsopenvpn.xml
@@ -0,0 +1,285 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.net-->
+<!-- Generated by crowdin.net -->
+<resources>
+
+ <string name="address">Alamat Server:</string>
+ <string name="port">Port server:</string>
+ <string name="location">Lokasi</string>
+ <string name="cant_read_folder">Gagal membaca direktori</string>
+ <string name="select">Pilih</string>
+ <string name="cancel">Batal</string>
+ <string name="no_data">Tak ada data</string>
+ <string name="useLZO">Kompresi LZO</string>
+ <string name="client_no_certificate">Tanpa Sertifikat</string>
+ <string name="client_certificate_title">Sertifikat Klien</string>
+ <string name="client_key_title">Kunci Sertifikat Klien</string>
+ <string name="client_pkcs12_title">Berkas PKCS12</string>
+ <string name="ca_title">Sertifikat CA</string>
+ <string name="no_certificate">Anda harus memilih sertifikat</string>
+ <string name="copyright_guicode">Kode program dan perekam masalah tersedia di</string>
+ <string name="copyright_others">Aplikasi memakai komponen berikut; lihat kode program untuk lebih jelas mengenai lisensi</string>
+ <string name="about">Tentang…</string>
+ <string name="vpn_list_title">Profil</string>
+ <string name="vpn_type">Tipe</string>
+ <string name="pkcs12pwquery">Password PKCS12</string>
+ <string name="file_select">Pilih&#8230;</string>
+ <string name="file_nothing_selected">Anda harus memilih berkas (file)</string>
+ <string name="useTLSAuth">Pakai otentikasi TLS</string>
+ <string name="tls_direction">Pengarah TLS</string>
+ <string name="ipv6_dialog_tile">Masukkan IPv6 Address/Netmask dalam format CIDR (contoh: 2000:dd::23/64)</string>
+ <string name="ipv4_dialog_title">Masukkan IPv4 Address/Netmask dalam format CIDR (contoh: 1.2.3.4/24)</string>
+ <string name="ipv4_address">Alamat IPv4</string>
+ <string name="ipv6_address">Alamat IPv6</string>
+ <string name="custom_option_warning">Masukan seting openvpn. Gunakan dengan hati-hati. Harap dicatat, TUN yanng terkait seting OpenVPN tidak didukung oleh VPNsettings. Jika anda berpikir ada hal penting belum tersedia, hubungi pembuatnya</string>
+ <string name="auth_username">Nama Penguna</string>
+ <string name="auth_pwquery">Password</string>
+ <string name="static_keys_info">Untuk konfigurasi statis, kunci otentifikasi TLS akan digunakan sebagai kunci konfigurasi statis</string>
+ <string name="configure_the_vpn">Konfigurasi VPN</string>
+ <string name="menu_add_profile">Tambah Profil</string>
+ <string name="add_profile_name_prompt">Masukkan nama profil yang baru</string>
+ <string name="duplicate_profile_name">Silakan masukan UPN (Unique Profile Name)</string>
+ <string name="profilename">Nama profil</string>
+ <string name="no_keystore_cert_selected">Anda harus memilih sertifikat pengguna</string>
+ <string name="no_error_found">Tidak ada kesalahan</string>
+ <string name="config_error_found">Konfigurasi Salah</string>
+ <string name="ipv4_format_error">Gagal menganalisa alamat IPV4</string>
+ <string name="custom_route_format_error">Gagal menganalisa rute buatan</string>
+ <string name="pw_query_hint">(biarkan kosong untuk antrian permintaan)</string>
+ <string name="vpn_shortcut">Jalan Pintas OpenVPN</string>
+ <string name="vpn_launch_title">Hubungkan VPN</string>
+ <string name="shortcut_profile_notfound">Profil di shrotcut tidak ada</string>
+ <string name="random_host_prefix">Acak awalan Host </string>
+ <string name="random_host_summary">Tambah 6 karakter acak di depan nama host</string>
+ <string name="custom_config_title">Aktifkan pilihan buatan</string>
+ <string name="custom_config_summary">Tentukan seting buatan. Gunakan hati-hati</string>
+ <string name="route_rejected">Rute ditolak Android</string>
+ <string name="cancel_connection">Putus</string>
+ <string name="cancel_connection_long">Memutuskan sambungan VPN</string>
+ <string name="clear_log">Bersihkan catatan</string>
+ <string name="title_cancel">Batal Konfirmasi</string>
+ <string name="cancel_connection_query">Putuskan sambungan VPN/Batalkan usaha menyambungkan VPN?</string>
+ <string name="remove_vpn">Singkirkan VPN</string>
+ <string name="check_remote_tlscert">Memeriksa apakah server menggunakan sertifikat dengan ekstensi TLS Server (--server remote-cert-tls)</string>
+ <string name="check_remote_tlscert_title">Mengharapkan sertifikat server TLS</string>
+ <string name="remote_tlscn_check_summary">Memeriksa sertifikat Remote Server Subjek DN</string>
+ <string name="remote_tlscn_check_title">Cek nama sertifikat Host</string>
+ <string name="enter_tlscn_dialog">Tentukan nilai ynag digunakan untuk memverifikasi sertifikat remote DN (misal C=nama perusahaan, L=Kota lokasi, OU=nama departemen perusahaan, CN=openvpn.blinkt.de. Tentukan DN atau RDN yang lengkap (dalam contoh : openvpn.blinkt.de) atau sebuah awalan RDN untuk verifikasi. Saat memakai RDN awalan \"server\" cocok dengan \"server-1\" dan \"server-2\". Mengosongkan field akan membuat RDN diperiksa dengan nama host server. Lebih jelasnya lihat OpenVPN 2.3.1 manpage di bagian -verify-x509-name</string>
+ <string name="enter_tlscn_title">Subyek sertifikat remote</string>
+ <string name="tls_key_auth">Aktifkan otentifikasi kunci TLS</string>
+ <string name="tls_auth_file">Berkas otintikasi TLS</string>
+ <string name="pull_on_summary">Meminta pilihan alamat IP, rute dan waktu dari server.</string>
+ <string name="pull_off_summary">Tidak ada informasi diminta dari server. Seting harus ditentukan di bawah ini</string>
+ <string name="use_pull">Tarik pengaturan</string>
+ <string name="dns">DNS</string>
+ <string name="override_dns">Menimpa pengaturan DNS oleh Server</string>
+ <string name="dns_override_summary">Gunakan server DNS pribadi</string>
+ <string name="searchdomain">Cari domain</string>
+ <string name="dns1_summary">Server DNS yang akan digunakan</string>
+ <string name="dns_server">Server DNS</string>
+ <string name="secondary_dns_message">Server DNS sekunder digunakan jika Server DNS yang normal tidak dapat dicapai.</string>
+ <string name="backup_dns">Server DNS cadangan</string>
+ <string name="ignored_pushed_routes">Abaikan rute yang diberikan</string>
+ <string name="ignore_routes_summary">Abaikan rute yang diberikan server</string>
+ <string name="default_route_summary">Alihkan semua lalulintas data melalui VPN</string>
+ <string name="use_default_title">Gunakan rute standar</string>
+ <string name="custom_route_message">Masukkan rute butan sendiri. Masukkan tujuan dalam format CIDR. \"10.0.0.0/8 2002:: / 16\" akan mengarahkan jaringan 10.0.0.0/8 dan 2002:: / 16 melalui jaringan VPN</string>
+ <string name="custom_routes_title">Rute buatan sendiri</string>
+ <string name="log_verbosity_level">Tingkat rincian catatan</string>
+ <string name="float_summary">Ijinkan paket terotentifikasi dari semua IP</string>
+ <string name="float_title">Ijinkan server mengambang</string>
+ <string name="custom_options_title">Pilihan buatan</string>
+ <string name="edit_vpn">Ubah seting OpenVPN</string>
+ <string name="remove_vpn_query">Hapus profil \'%s\'?</string>
+ <string name="tun_error_helpful">Pada beberapa setelan manual gambar ICS izin pada/dev/tun mungkin salah, atau modul tun mungkin hilang sepenuhnya. Untuk gambar CM9, coba perbaiki pilihan kepemilikannya di bawah pengaturan umum</string>
+ <string name="tun_open_error">Gagal membuka layanan antarmuka TUN</string>
+ <string name="error">"Kesalahan: "</string>
+ <string name="clear">Bersihkan</string>
+ <string name="last_openvpn_tun_config">Membuka interface tun :</string>
+ <string name="local_ip_info">IPv4 lokal : %1$s/%2$d IPv6: %3$s MTU: %4$d</string>
+ <string name="dns_server_info">DNS Server: %1$s, Domain: %2$s</string>
+ <string name="ip_not_cidr">Memilki informasi antarmuka %1$s dan %2$s, asumsi alamat kedua adalah alamat remote. Menggunakan netmask /32 untuk IP lokal. Mode yang diberikan oleh OpenVPN adalah \"%3$s\".</string>
+ <string name="route_not_cidr">Tidak masuk akal membuat %1$s dan %2$s sebagai rute IP dengan netmask CIDR, Gunakan /32 sebagai netmask.</string>
+ <string name="route_not_netip">rute yang diperbaiki %1$s/%2$s hingga %3$s/%2$s</string>
+ <string name="keychain_access">Tidak dapat mengakses sertifikat Keychain Android. Dapat disebabkan karena upgrade firmware atau pengembalian backup pengaturan app. Mohon ubah VPN, dan pilih ulang sertifikat berbasis pengaturan dasar agar izin mengakses sertifikat dapat dibuat ulang.</string>
+ <string name="version_info">%1$s %2$s</string>
+ <string name="send_logfile">Kirim berkas catatan</string>
+ <string name="send">Kirim</string>
+ <string name="ics_openvpn_log_file">Berkas catatan ICS OpenVPN</string>
+ <string name="copied_entry">Salin catatan masuk ke clipboard</string>
+ <string name="tap_mode">Mode TAP</string>
+ <string name="faq_tap_mode">Mode TAP tidak diijinkan tanpa VPN API non admin/root. Karena itu aplikasi ini tidak dapat memberikan dukungan mode TAP</string>
+ <string name="tap_faq2">Lagi ? Becanda ? mode TAP benar-benar tidak didukung dan mengirim email menanyakan apakah akan ada dukungan TAP, tidak akan membantu</string>
+ <string name="tap_faq3">Untuk ketiga kalinya? Sebenarnya, seseorang bisa menulis emulator TAP berdasarkan tun yang akan menambahkan lapisan2 informasi pengiriman dan lapisan2 informasi penerimaan. Tapi emulator TAP ini juga harus menerapkan ARP dan mungkin klien DHCP. Saya tidak tau apakah ada yang bekerja ke arah ini. Hubungi saya jika Anda ingin memulai menulis kode2 emulator TAP ini.</string>
+ <string name="faq">FAQ</string>
+ <string name="copying_log_entries">Menyalin catatan</string>
+ <string name="faq_copying">Untuk menyalin satu catatan masuk, Tekan dan tahan di catatan masuk. Untuk meyanlin\mengirim seluruh catatan, gunakan opsi Kirim Log. Gunakan tombol perangkat keras jika tidak terlihat di GUI.</string>
+ <string name="faq_shortcut">Jalan pintas memulai</string>
+ <string name="faq_howto_shortcut">Anda dapat menempatkan jalan pintas untuk memulai OpenVPN pada desktop Anda. Tergantung pada program homescreen Anda, Anda harus menambahkan jalan pintas atau widget.</string>
+ <string name="no_vpn_support_image">Gambar Anda tidak mendukung VPNService API, maaf:(</string>
+ <string name="encryption">Enkripsi</string>
+ <string name="cipher_dialog_title">Masukkan metode enkripsi</string>
+ <string name="chipher_dialog_message">Masukkan sandi enkripsi algoritma yang digunakan oleh OpenVPN. Biarkan kosong untuk menggunakan sandi default.</string>
+ <string name="auth_dialog_message">Masukkan digest otentikasi yang digunakan OpenVPN. Biarkan kosong untuk menggunakan standar digest.</string>
+ <string name="settings_auth">Otentikasi/Enkripsi</string>
+ <string name="file_explorer_tab">Penjelajah berkas</string>
+ <string name="inline_file_tab">Inline File</string>
+ <string name="error_importing_file">Gagal mengambil berkas</string>
+ <string name="import_error_message">Tidak dapat mengambil berkas dari filesystem</string>
+ <string name="inline_file_data">[[Inline file data]]</string>
+ <string name="opentun_no_ipaddr">TUN tidak dapat dibuka tanpa informasi IP</string>
+ <string name="menu_import">Ambil profil dari berkas ovpn</string>
+ <string name="menu_import_short">Ambil</string>
+ <string name="import_content_resolve_error">Tidak dapat membaca profil yang akan diambil</string>
+ <string name="error_reading_config_file">Kesalahan membaca berkas konfigurasi</string>
+ <string name="add_profile">Tambah Profil</string>
+ <string name="import_could_not_open">Tidak dapat menemukan berkas %1$s yang disebut dalam berkas konfigurasi</string>
+ <string name="importing_config">Mengambil berkas konfigurasi dari sumber %1$s</string>
+ <string name="import_warning_custom_options">Konfigurasi Anda memiliki beberapa pilihan konfigurasi yang tidak dipetakan ke konfigurasi UI. Pilihan ini ditambahkan sebagai opsi konfigurasi kustom. Konfigurasi kustom ditampilkan di bawah ini:</string>
+ <string name="import_done">Berkas konfigurasi selesai dibaca</string>
+ <string name="nobind_summary">Jangan kaitkan ke alamat dan port lokal</string>
+ <string name="no_bind">Tidak ada ikatan lokal</string>
+ <string name="import_configuration_file">Ambil berkas konfigurasi</string>
+ <string name="faq_security_title">Pertimbangan Keamanan</string>
+ <string name="faq_security">"Karena OpenVPN adalah sensitif pada isu keamanan, beberapa catatan tentang keamanan dianggap perlu. Semua data pada sdcard pada dasarnya tidak aman. Setiap app dapat membaca (misalnya program ini tidak perlu hak khusus untuk membaca sd-card). Data dari aplikasi ini hanya dapat dibaca oleh aplikasi itu sendiri. Dengan menggunakan opsi impor untuk cacert/cert/kunci dalam file dialog data yang disimpan dalam profil VPN. Profil VPN hanya dapat diakses oleh aplikasi ini. (Jangan lupa untuk menghapus salinan pada sd-card setelah itu). Bahkan meskipun dapat diakses hanya dengan aplikasi ini data masih tidak terenkripsi. Dengan melakukan rooting atau eksploitasi lainnya maka memungkinkan mengambil data. Sandi-sandi (passwords) juga tersimpan dalam teks biasa. Berkas pkcs12 sangat dianjurkan Anda mengimpornya ke android keystore."</string>
+ <string name="import_vpn">Impor</string>
+ <string name="broken_image_cert_title">Kesalahan menampilkan sertifikat</string>
+ <string name="broken_image_cert">Mendapat pesan kesalahan saat berusaha menampilkan layar pemilihan sertifikat Android 4.0+. Ini seharusnya tidak terjadi karena ini fitur standar Android 4.0 +. Mungkin ROM Android anda yang mengurus penyimpanan sertifikat rusak</string>
+ <string name="ipv4">IPv4</string>
+ <string name="ipv6">IPv6</string>
+ <string name="speed_waiting">Menunggu pesan status&#8230;</string>
+ <string name="converted_profile">Profil yang diambil</string>
+ <string name="converted_profile_i">profil yang diambil %d</string>
+ <string name="broken_images">Gambar rusak</string>
+ <string name="broken_images_faq">Image HTC yang resmi diketahui memiliki masalah routing yang ganjilyang menyebabkan trafik data tidak melalui tunnel (Lihat di &lt;a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=18\"&gt;Issue 18&lt;/a&gt; di bagian bug tracker.))&lt;/p&gt;&lt;p&gt; Image SONY resmi yang lama dari Xperia Arc S and Xperia Ray telah dilaporkan tidak memiliki VPNService dalam Imagenya. (Lihat juga &lt;a href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=29\"&gt;Issue 29&lt;/a&gt; di bagian bug tracker.))&lt;/p&gt;&lt;p&gt;Pada image yang dibuat non resmi, modul TUN mungkin tak ada atau hak /dev/tun mungkin salah. Beberapa image CM9 memerlukan pilihan \"Fix ownership\" di bagian \"Device specific hacks\" diaktfikan. .&lt;/p&gt;&lt;p&gt; Lebih penting lagi, jika device anda memiliki image android yang lengkap, laporkan pada vendor anda. Semakin banyak laporan masuk, semakin tinggi kemungkinan vendor melakukan perbaikan.&lt;/p&gt;</string>
+ <string name="pkcs12_file_encryption_key">Berkas kunci enkripsi PKCS12</string>
+ <string name="private_key_password">Sandi kunci pribadi</string>
+ <string name="password">Sandi</string>
+ <string name="file_icon">ikon berkas</string>
+ <string name="tls_authentication">Otentikasi TLS</string>
+ <string name="generated_config">Konfigurasi Dibuat</string>
+ <string name="generalsettings">Pengaturan</string>
+ <string name="owner_fix_summary">Mencoba menetapkan pemilik /dev/tun ke sistem. Beberapa gambar CM9 memerlukan ini untuk membuat API VPNService bekerja. Memerlukan akses Root.</string>
+ <string name="owner_fix">Perbaiki kepemilikan /dev/tun</string>
+ <string name="generated_config_summary">Tunjukkan berkas konfigurasi OpenVPN yang dibuat</string>
+ <string name="edit_profile_title">Mengubah \"%s\"</string>
+ <string name="building_configration">Membuat konfigurasi&#8230;</string>
+ <string name="netchange_summary">Menyalakan pilihan ini akan memaksa menyambung kembali jika keadaan jaringan berubah (misalnya WiFi dari mobile)</string>
+ <string name="netchange">Koneksi ulang saat ganti jaringan</string>
+ <string name="netstatus">Status jaringan: %s</string>
+ <string name="extracahint">Sertifikat CA biasanya kembali dari Android Keystore. Tentukan sertifikat terpisah jika Anda mendapatkan kesalahan verifikasi sertifikat.</string>
+ <string name="select_file">Pilih</string>
+ <string name="keychain_nocacert">Tidak ada sertifikat CA yang didapat saat membaca dari Android Keystore. Otentifikasi mungkin gagal</string>
+ <string name="show_log_summary">Tampilkan jendela catatan saat terkoneksi. Jendela catatan juga dapat diakses melalui status notifikasi</string>
+ <string name="show_log_window">Tampilkan jendela catatan</string>
+ <string name="mobile_info">Berjalan di %1$s (%2$s) %3$s, Android API %4$d</string>
+ <string name="error_rsa_sign">Kesalahan masuk dengan kunci Android keystore %1$s: %2$s</string>
+ <string name="faq_system_dialogs">Peringatan sambungan VPN yang memberitahukan Anda bahwa aplikasi ini dapat mencegat semua lalu lintas dikeluarkan oleh sistem untuk mencegah penyalahgunaan dari sambungan VPNService API.\nPemberitahuan sambungan VPN (simbol kunci) juga dikeluarkan oleh sistem Android untuk memberitahu VPN yang sedang berlangsung. Pada beberapa gambar pemberitahuan ini memainkan suara. \nAndroid memperkenalkan sistem dialog ini untuk keselamatan Anda sendiri dan memastikan bahwa mereka tidak membuat masalah. (Pada beberapa gambar sayangnya ini termasuk peringatan suara)</string>
+ <string name="faq_system_dialogs_title">Peringatan sambungan dan pemberitahuan melalui suara</string>
+ <string name="translationby">Terjemah Bahasa Indonesia oleh Dayro</string>
+ <string name="ipdns">IP dan DNS</string>
+ <string name="basic">Dasar</string>
+ <string name="routing">Rute</string>
+ <string name="obscure">Mengaburkan pengaturan OpenVPN. Biasanya tidak diperlukan.</string>
+ <string name="advanced">Lanjutan</string>
+ <string name="export_config_title">Konfigurasi ICS Openvpn</string>
+ <string name="warn_no_dns">Tidak DNS server yang digunakan. Name Resolution mungkin akan gagal bekerja. Pertimbangkan pengaturan server DNS. Harap dicatat Android akan terus memakai pengaturan proxy untuk koneksi mobile/wifi saat tidak ada server DNS diatur.</string>
+ <string name="dns_add_error">Tak bisa menambahkan Server DNS \"%1$s\", ditolak oleh sistem: %2$s</string>
+ <string name="faq_howto">&lt;p&gt; Ambil konfigurasi yang dapat berjalan (diuji pada komputer Anda atau download dari penyedia/organisasi) &lt;/p&gt; &lt;p&gt; Satu file(berkas) saja tanpa tambahan berkas pem/pks12. Anda dapat kirim imel berkas dan membuka lampirannya. Jika Anda memiliki beberapa berkas, salin ke sd-card &lt;/p&gt; &lt;p&gt; klik pada lampiran imel atau gunakan ikon folder dalam daftar vpn untuk mengimpor berkas konfigurasi &lt;/p&gt; &lt;p&gt; jika ada berkas yang kurang, salin file hilang ke sd-card. &lt;/p&gt; &lt;p&gt; klik pada simbol Simpan untuk menambahkan VPN yang diimpor ke daftar VPN &lt;/p&gt; &lt;p &gt; Connect VPN dengan mengklik nama VPN &lt;/p&gt; &lt;p&gt; jika ada kesalahan atau peringatan di catatan, coba pahami peringatannya dan coba untuk memperbaikinya &lt;/p&gt; </string>
+ <string name="faq_howto_title">Mulai Cepat</string>
+ <string name="setting_loadtun_summary">Coba pakai tun.ko kernel sebelum mencoba koneksi. Membutuhkan perangkat yang sudah diroot. Google: android superuser</string>
+ <string name="setting_loadtun">Pakai modul TUN</string>
+ <string name="importpkcs12fromconfig">Ambil PKCS12 dari konfigurasi ke Android Keystore</string>
+ <string name="getproxy_error">Gagal mendapatkan pengaturan proxy: %s</string>
+ <string name="using_proxy">Menggunakan proxy %1$s %2$d</string>
+ <string name="use_system_proxy">Gunakan sistem proxy</string>
+ <string name="use_system_proxy_summary">Gunakan konfigurasi lebih luas untuk menyambung system melalui proxy HTTP/HTTPS</string>
+ <string name="donatewithpaypal">Anda dapat melakukan donasi &lt;a href=\"https://www.paypal.com/cgi-bin/webscr?hosted_button_id=R2M6ZP9AF25LS&amp;amp;cmd=_s-xclick\"&gt;dengan PayPal&lt;/a&gt; </string>
+ <string name="onbootrestartsummary">OpenVPN akan menyambung kembali VPN jika VPN aktif pada saat sistem reboot/shutdown. Silakan baca FAQ tentang peringatan sambungan sebelum menggunakan pilihan ini.</string>
+ <string name="onbootrestart">Koneksi ulang saat perangkat dihidupkan kembali</string>
+ <string name="ignore">Abaikan</string>
+ <string name="restart">Restart</string>
+ <string name="restart_vpn_after_change">Perubahan konfigurasi baru diterapkan setelah restart VPN. Restart VPN sekarang?</string>
+ <string name="configuration_changed">Konfigurasi berubah</string>
+ <string name="log_no_last_vpn">Tak bisa menentukan profil terhubung terakhir untuk diubah</string>
+ <string name="faq_duplicate_notification_title">Pemberitahuan berganda</string>
+ <string name="faq_duplicate_notification">Jika Android kekurangan sistem memori (RAM), aplikasi dan layanan yang tidak diperlukan pada saat itu akan dihapus dari memori aktif. Sambungan VPN yang sedang aktif juga ditutup. Untuk memastikan bahwa sambungan/OpenVPN tetap berjalan, OpenVPN diberikan prioritas yang lebih tinggi. Untuk menjalankan dengan prioritas lebih tinggi, aplikasi harus menampilkan pemberitahuan. Ikon pemberitahuan dijalankan oleh sistem seperti dijelaskan dalam FAQ entri sebelumnya. Ini tidak dihitung sebagai pemberitahuan app yang berjalan dengan prioritas lebih tinggi.</string>
+ <string name="no_vpn_profiles_defined">Tak ada profil VPN yang didefinisikan.</string>
+ <string name="add_new_vpn_hint">Gunakan ikon &lt; img src = \"ic_menu_add\" / &gt; untuk menambah VPN baru</string>
+ <string name="vpn_import_hint">Gunakan ikon &lt; img src = \"ic_menu_archive\" / &gt; untuk mengimpor profil (.ovpn atau .conf) yang ada dari sdcard Anda.</string>
+ <string name="faq_hint">Pastikan untuk juga memeriksa FAQ. Ada petunjuk untuk memudahkan anda.</string>
+ <string name="faq_routing_title">Konfigurasi rute\antarmuka</string>
+ <string name="persisttun_summary">Jangan kembali ke status tidak ada koneksi VPN ketika OpenVPN mencoba terhubung kembali.</string>
+ <string name="persistent_tun_title">Paksa mode TUN</string>
+ <string name="openvpn_log">Catatan OpenVPN</string>
+ <string name="import_config">Ambil konfigurasi VPN</string>
+ <string name="battery_consumption_title">Konsumsi baterai</string>
+ <string name="baterry_consumption">Berdasarkan tes pribadi, alasan utama tingginya konsumsi baterai oleh OpenVPN adalah paket keepalive. Sebagian besar server OpenVPN memiliki parameter konfigurasi seperti \'keepalive 10 60\' yang membuat klien dan server bertukar paket keepalive setiap 10 detik. &lt;p&gt; Dengan kecilnya paket ini dan tidak memakai trafik terlalu banyak, mereka menjaga jaringan radio mobile tetap sibuk dan meningkatkan konsumsi energi. (See also &lt;a href=\"http://developer.android.com/training/efficient-downloads/efficient-network-access.html#RadioStateMachine\"&gt;The Radio State Machine | Android Developers&lt;/a&gt;) &lt;p&gt; Seting keepalive ini tidak bisa dirubah di klien. Hanya Admin sistem OpenVPN yang dapat merubah seting ini. &lt;p&gt; Sayangnya membuat keepalive lebih besar dari 60 detik tanpa UDP dapat membuat beberapa gateway NAT memutus koneksi karena anggapan tidak ada aktifitas pada periode tertentu (timeout). Memakai TCP dengan waktu timeout lebih lama dapat bekerja, tapi membuat tunnel TCP di jalur TCP menyebabkan koneksi yang buruk dan tingginya angka kehilangan paket data ((See &lt;a href=\"http://sites.inka.de/bigred/devel/tcp-tcp.html\"&gt;Why TCP Over TCP Is A Bad Idea&lt;/a&gt;)</string>
+ <string name="faq_tethering">Fitur penggandengan Android (melalui WiFi, USB atau Bluetooth) dan API VPNService (digunakan oleh program ini) tidak bekerja bersama-sama. Untuk keterangan lanjut lihat &lt; href=\"http://code.google.com/p/ics-openvpn/issues/detail?id=34\" &gt; mengeluarkan #34 &lt;/a&gt;</string>
+ <string name="vpn_tethering_title">VPN dan penarikan</string>
+ <string name="connection_retries">Mengulang koneksi</string>
+ <string name="reconnection_settings">Pengaturan rekoneksi</string>
+ <string name="connectretrymessage">Jumlah detik untuk menunggu antar usaha koneksi</string>
+ <string name="connectretrywait">Detik antar koneksi</string>
+ <string name="minidump_generated">OpenVPN crash tak terduga. Silakan mempertimbangkan mengirim menggunakan pilihan Minidump di Menu Utama</string>
+ <string name="send_minidump">Mengirim MiniDump untuk pengembang</string>
+ <string name="send_minidump_summary">Mengirim informasi debug tentang kegagalan aplikasi yang terakhir ke pengembang</string>
+ <string name="notifcation_title">OpenVPN - %s</string>
+ <string name="session_ipv4string">%1$s - %2$s</string>
+ <string name="session_ipv6string">%1$s - %3$s, %2$s</string>
+ <string name="state_connecting">Menghubungkan</string>
+ <string name="state_wait">Menunggu jawaban server</string>
+ <string name="state_auth">Melakukan otentifikasi</string>
+ <string name="state_get_config">Mengambil konfigurasi klien</string>
+ <string name="state_assign_ip">Menetapkan alamat IP</string>
+ <string name="state_add_routes">Menambahkan rute</string>
+ <string name="state_connected">Terhubung</string>
+ <string name="state_disconnected">Putus</string>
+ <string name="state_reconnecting">Menghubungkan kembali</string>
+ <string name="state_exiting">Keluar</string>
+ <string name="state_noprocess">Tidak berjalan</string>
+ <string name="state_resolve">Mengenali nama host</string>
+ <string name="state_tcp_connect">Menghubungkan (TCP)</string>
+ <string name="state_auth_failed">Otentifikasi gagal</string>
+ <string name="state_nonetwork">Menunggu jaringan yang dapat dipakai</string>
+ <string name="statusline_bytecount">↓%2$s/s %1$s - ↑%4$s/s %3$s</string>
+ <string name="notifcation_title_notconnect">Tidak terhubung</string>
+ <string name="start_vpn_title">Menghubungkan ke VPN %s</string>
+ <string name="start_vpn_ticker">Menghubungkan ke VPN %s</string>
+ <string name="jelly_keystore_alphanumeric_bug">Beberapa versi Android 4.1 memiliki masalah jika nama sertifikat keystore berisi karakter non alfanumerik (seperti spasi, garis bawah atau tanda hubung). Cobalah import ulang sertifikat tanpa karakter khusus</string>
+ <string name="encryption_cipher">Enkripsi sandi</string>
+ <string name="packet_auth">Otentikasi paket</string>
+ <string name="auth_dialog_title">Masukkan metode otentikasi paket</string>
+ <string name="mobile_info_extended">Berjalan pada Android API %4$d, versi %5$s %1$s (%2$s) %3$s, %6$s</string>
+ <string name="built_by">dibangun oleh %s</string>
+ <string name="debug_build">Pengembangan debug</string>
+ <string name="official_build">Build Resmi</string>
+ <string name="make_selection_inline">Salin ke profil</string>
+ <string name="crashdump">Data saat terjadi crash</string>
+ <string name="add">Tambahkan</string>
+ <string name="send_config">Mengirim config file</string>
+ <string name="complete_dn">DN lengkap</string>
+ <string name="remotetlsnote">Konfigurasi yang diimpor menggunakan opsi tls-remote DEPRECATED tua dengan menggunakan format DN yang berbeda.</string>
+ <string name="rdn">RDN (nama umum)</string>
+ <string name="rdn_prefix">RDN awalan</string>
+ <string name="tls_remote_deprecated">TLS-remote (DEPRECATED)</string>
+ <string name="help_translate">Anda dapat membantu menerjemahkan dengan mengunjungi http://crowdin.net/project/ics-openvpn/invite</string>
+ <string name="prompt">%1$s berusaha mengendalikan %2$s</string>
+ <string name="remote_trust">Saya percaya aplikasi ini.</string>
+ <string name="no_external_app_allowed">App tidak diizinkan untuk menggunakan API eksternal</string>
+ <string name="allowed_apps">apps yang diijinkan : %s</string>
+ <string name="clearappsdialog">Hapus daftar aplikasi eksternal yang dibolehkan? \nDaftar apps yang dibolehkan terkini:\n\n%s </string>
+ <string name="screenoff_summary">\"Pause VPN ketika layar off dan data yang ditransfer dalam 60 detik kurang dari 64kB. Ketika opsi \"Persistent Tun\" diaktifkan, memberhentikan VPN akan membuat perangkat Anda tidak memiliki koneksi jaringan. Jika tidak memakai \"Persistent Tun\" maka perangkat akan menampilkan Tidak ada koneksi VPN.</string>
+ <string name="screenoff_title">Sambungan VPN jeda setelah layar mati</string>
+ <string name="screenoff_pause">Hentikan sambungan dalam kondisi layar mati: kurang dari %1$s dalam %2$ss</string>
+ <string name="screen_nopersistenttun">Peringatan: Pemaksaan tun tidak diaktifkan untuk VPN ini. Lalu lintas akan menggunakan koneksi Internet normal ketika layar dimatikan.</string>
+ <string name="save_password">Menyimpan sandi</string>
+ <string name="pauseVPN">Jeda VPN</string>
+ <string name="resumevpn">Lanjutkan VPN</string>
+ <string name="state_userpause">Pause VPN diminta oleh pengguna</string>
+ <string name="state_screenoff">VPN dijeda - layar off</string>
+ <string name="device_specific">Perangkat dengan spesifikasi Hacks</string>
+ <string name="cannotparsecert">Tidak dapat menampilkan informasi sertifikat</string>
+ <string name="appbehaviour">Prilaku Aplikasi</string>
+ <string name="vpnbehaviour">Prilaku VPN</string>
+</resources>
diff --git a/app/src/main/res/values-ja/strings-icsopenvpn.xml b/app/src/main/res/values-ja/strings-icsopenvpn.xml
index 2ce290a3..c96b9b8e 100755
--- a/app/src/main/res/values-ja/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-ja/strings-icsopenvpn.xml
@@ -286,6 +286,7 @@ OpenVPNの接続を保証するためには、アプリケーションを高い
<string name="tls_remote_deprecated"> tls-remote (非推奨)</string>
<string name="help_translate">翻訳作業を手伝っていただける方は次のURLへ http://crowdin.net/project/ics-openvpn/invite</string>
<string name="prompt">%1$s は %2$s を制御しようとしています。</string>
+ <string name="remote_warning">このまま進むと、あなたはOpenVPN for Androidの完全な制御とすべての通信を傍受する権限をアプリケーションに対し与えることになります。<b>アプリケーションが信頼できない限り、承諾しないでください。</b>さもないと、あなたのデータがマルウェアにより漏洩させられる危険があります。</string>
<string name="remote_trust">私はこのアプリケーションを信頼します</string>
<string name="no_external_app_allowed">外部APIの使用を許可されたアプリはありません</string>
<string name="allowed_apps">許可アプリ: %s</string>
@@ -307,6 +308,7 @@ OpenVPNの接続を保証するためには、アプリケーションを高い
<string name="permission_icon_app">OpenVPN for Androidを使用しようと試みるアプリのアイコン</string>
<string name="faq_vpndialog43_title">Android 4.3以降用VPN確認ダイアログ</string>
<string name="donatePlayStore">ほかの手段として、Play Storeで私に寄付できます。</string>
+ <string name="thanks_for_donation">%s の寄付をお寄せいただきありがとうございます!</string>
<string name="logCleared">ログがクリアされました。</string>
<string name="show_password">パスワードを表示する</string>
<string name="keyChainAccessError">キーチェーン アクセス エラー: %s</string>
@@ -316,12 +318,17 @@ OpenVPNの接続を保証するためには、アプリケーションを高い
<string name="uploaded_data">アップロード</string>
<string name="downloaded_data">ダウンロード</string>
<string name="vpn_status">VPNの状態</string>
+ <string name="logview_options">オプションを表示</string>
<string name="unhandled_exception">未処理の例外: %1$s\n\n%2$s</string>
<string name="unhandled_exception_context">%3$s: %1$s\n\n%2$s</string>
<string name="faq_system_dialog_xposed">もしあなたがデバイスをroot化しているのであれば、 &lt;a href=\"http://xposed.info/\"&gt;Xposed framework&lt;/a&gt;と&lt;a href=\"http://repo.xposed.info/module/de.blinkt.vpndialogxposed\"&gt;VPN Dialog confirm module&lt;/a&gt; を自己責任においてインストールできます</string>
<string name="full_licenses">フルライセンス</string>
<string name="blocklocal_summary">ローカルインターフェイスに直接接続されているネットワークはVPNを経由しません。
このオプションを外すとローカルネットワーク宛のすべての通信をVPNにリダイレクトします。</string>
+ <string name="blocklocal_title">ローカルネットワークはVPNを経由しない</string>
+ <string name="userpw_file">ユーザー名/パスワードファイル</string>
+ <string name="imported_from_file">[インポート元: %s]</string>
<string name="files_missing_hint">いくつかのファイルが見つかりませんでした。プロファイルをインポートするファイルを選択してください:</string>
+ <string name="openvpn_is_no_free_vpn">このアプリを使用するには、(多くの場合、あなたの雇用者によって提供される)OpenVPNをサポートするVPNプロバイダ/ VPNゲートウェイが必要です。あなた独自のOpenVPNサーバーをセットアップするためにはhttp://community.openvpn.net/ をチェックしてください。</string>
<string name="import_log">インポートログ:</string>
</resources>
diff --git a/app/src/main/res/values-tr/strings-icsopenvpn.xml b/app/src/main/res/values-tr/strings-icsopenvpn.xml
index 26ac47ad..a40df5bf 100755
--- a/app/src/main/res/values-tr/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-tr/strings-icsopenvpn.xml
@@ -309,4 +309,6 @@
<string name="full_licenses">Lisanslar</string>
<string name="blocklocal_title">Yerel ağlar için Bypass VPN</string>
<string name="userpw_file">Kullanıcı adı / Şifre dosyası</string>
+ <string name="imported_from_file">[Buradan içeri aktar: %s]</string>
+ <string name="import_log">Kaydı içe aktar:</string>
</resources>
diff --git a/app/src/main/res/values/strings-icsopenvpn.xml b/app/src/main/res/values/strings-icsopenvpn.xml
index 6ab41787..40698afa 100755
--- a/app/src/main/res/values/strings-icsopenvpn.xml
+++ b/app/src/main/res/values/strings-icsopenvpn.xml
@@ -117,7 +117,7 @@
<string name="tap_faq3">A third time? Actually, one could write a a tap emulator based on tun that would add layer2 information on send and strip layer2 information on receive. But this tap emulator would also have to implement ARP and possibly a DHCP client. I am not aware of anybody doing any work in this direction. Contact me if you want to start coding on this.</string>
<string name="faq">FAQ</string>
<string name="copying_log_entries">Copying log entries</string>
- <string name="faq_copying">To copy a single log entry press and hold on the log entry. To copy/send the whole log use the Send Log option. Use the hardware menu button if not visible in the GUI.</string>
+ <string name="faq_copying">To copy a single log entry press and hold on the log entry. To copy/send the whole log use the Send Log option. Use the hardware menu button, if the button is not visible in the GUI.</string>
<string name="faq_shortcut">Shortcut to start</string>
<string name="faq_howto_shortcut">You can place a shortcut to start OpenVPN on your desktop. Depending on your homescreen program you will have to add either a shortcut or a widget.</string>
<string name="no_vpn_support_image">Your image does not support the VPNService API, sorry :(</string>
@@ -190,7 +190,7 @@
<string name="warn_no_dns">No DNS servers being used. Name resolution may not work. Consider setting custom DNS Servers. Please also note that Android will keep using your proxy settings specified for your mobile/Wi-Fi connection when no DNS servers are set.</string>
<string name="dns_add_error">Could not add DNS Server \"%1$s\", rejected by the system: %2$s</string>
<string name="ip_add_error">Could not configure IP Address \"%1$s\", rejected by the system: %2$s</string>
- <string name="faq_howto">&lt;p&gt;Get a working config (tested on your computer or download from your provider/organisation)&lt;/p&gt;&lt;p&gt;If it is a single file no with no extra pem/pks12 files you can email the file yourself and open the attachment. If you have multiple files put them on your sd card.&lt;/p&gt;&lt;p&gt;Click on the email attachment/Use the folder icon in the vpn list to import the config file&lt;/p&gt;&lt;p&gt;If there are errors about missing files put the missing files on your sd card.&lt;/p&gt;&lt;p&gt;Click on the save symbol to add the imported VPN to your VPN list&lt;/p&gt;&lt;p&gt;Connect the VPN by clicking on the name of the VPN&lt;/p&gt;&lt;p&gt;If there are error or warnings in the log try to understand the warnings/error and try to fix them&lt;/p&gt; </string>
+ <string name="faq_howto">&lt;p&gt;Get a working config (tested on your computer or download from your provider/organisation)&lt;/p&gt;&lt;p&gt;If it is a single file with no extra pem/pks12 files you can email the file yourself and open the attachment. If you have multiple files put them on your sd card.&lt;/p&gt;&lt;p&gt;Click on the email attachment/Use the folder icon in the vpn list to import the config file&lt;/p&gt;&lt;p&gt;If there are errors about missing files put the missing files on your sd card.&lt;/p&gt;&lt;p&gt;Click on the save symbol to add the imported VPN to your VPN list&lt;/p&gt;&lt;p&gt;Connect the VPN by clicking on the name of the VPN&lt;/p&gt;&lt;p&gt;If there are error or warnings in the log try to understand the warnings/error and try to fix them&lt;/p&gt; </string>
<string name="faq_howto_title">Quick Start</string>
<string name="setting_loadtun_summary">Try to load the tun.ko kernel module before trying to connect. Needs rooted devices.</string>
<string name="setting_loadtun">Load tun module</string>
@@ -214,7 +214,7 @@
<string name="vpn_import_hint">Use the &lt;img src=\"ic_menu_archive\"/&gt; icon to import an existing (.ovpn or .conf) profile from your sdcard.</string>
<string name="faq_hint">Be sure to also check out the FAQ. There is a quick start guide.</string>
<string name="faq_routing_title">Routing/Interface Configuration</string>
- <string name="faq_routing">The Routing and interface configuration is not done via traditional ifconfig/route commands but by using the VPNService API. This results in a different routing configuration than on other OSes. The configuration for the VPN tunnel consists of the IP address and the networks that should be routed over this interface. Especially no peer partner address or gateway address is needed. Special routes to reach the VPN Server (for example added when using redirect-gateway) are not needed either. The application will consequently ignore these settings when importing a configuration. The app ensures with the VPNService API that the connection to the server is not routed through the VPN tunnel. Only specifying networks to be routed via tunnel is supported. The app tries to detect networks that should not be routed over tunnel (e.g. route x.x.x.x y.y.y.y net_gateway) and calculates a route set that excludes this routes to emulate the behaviour of other platforms. The log windows shows the configuration of the VPNService upon establishing a connection.</string>
+ <string name="faq_routing">The Routing and interface configuration is not done via traditional ifconfig/route commands but by using the VPNService API. This results in a different routing configuration than on other OSes. \nThe configuration of the VPN tunnel consists of the IP address and the networks that should be routed over this interface. Especially, no peer partner address or gateway address is needed or required. Special routes to reach the VPN Server (for example added when using redirect-gateway) are not needed either. The application will consequently ignore these settings when importing a configuration. The app ensures with the VPNService API that the connection to the server is not routed through the VPN tunnel.\nThe VPNService API does not allow specifying networks that should not be routed via the VPN. As a workaround the app tries to detect networks that should not be routed over tunnel (e.g. route x.x.x.x y.y.y.y net_gateway) and calculates a set of routes that excludes this routes to emulate the behaviour of other platforms. The log windows shows the configuration of the VPNService upon establishing a connection.\nBehind the scenes: Android 4.4+ does use policy routing. Using route/ifconfig will not show the installed routes. Instead use ip rule, iptables -t mangle -L</string>
<string name="persisttun_summary">Do not fallback to no VPN connection when OpenVPN is reconnecting.</string>
<string name="persistent_tun_title">Persistent tun</string>
<string name="openvpn_log">OpenVPN Log</string>
@@ -318,4 +318,5 @@
<string name="files_missing_hint">Some files could not be found. Please select the files to import the profile:</string>
<string name="openvpn_is_no_free_vpn">To use this app you need a VPN provider/VPN gateway supporting OpenVPN (often provided by your employer). Check out http://community.openvpn.net/ for more information on OpenVPN and how to setup your own OpenVPN server.</string>
<string name="import_log">Import log:</string>
+ <string name="ip_looks_like_subnet">Vpn topology \"%3$s\" specified but ifconfig %1$s %2$s looks more like an IP address with a network mask. Assuming \"subnet\" topology.</string>
</resources>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 1dbe8fee..8c815786 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -41,6 +41,7 @@
<string name="error_io_exception_user_message">Try again: I/O error</string>
<string name="error_json_exception_user_message">Try again: Bad response from the server</string>
<string name="error_no_such_algorithm_exception_user_message">Update the app</string>
+ <string name="signup_or_login_button">Sign Up/Log In</string>
<string name="login_button">Log In</string>
<string name="logout_button">Log Out</string>
<string name="signup_button">Sign Up</string>
@@ -67,8 +68,8 @@
<string name="eip_status_start_pending">Initiating connection</string>
<string name="eip_cancel_connect_title">Cancel connection?</string>
<string name="eip_cancel_connect_text">There is a connection attempt in progress. Do you wish to cancel it?</string>
- <string name="eip_cancel_connect_cancel">Yes</string>
- <string name="eip_cancel_connect_false">No</string>
+ <string name="yes">Yes</string>
+ <string name="no">No</string>
<string name="eip_state_not_connected">"Not running! Connection not secure!"</string>
<string name="eip_state_connected">Connection Secure.</string>
</resources>
diff --git a/app/src/main/res/values/untranslatable.xml b/app/src/main/res/values/untranslatable.xml
index f956b6bd..90090c52 100644
--- a/app/src/main/res/values/untranslatable.xml
+++ b/app/src/main/res/values/untranslatable.xml
@@ -893,4 +893,422 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
</resources> \ No newline at end of file