summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArne Schwabe <arne@rfc2549.org>2012-05-12 21:18:37 +0200
committerArne Schwabe <arne@rfc2549.org>2012-05-12 21:18:37 +0200
commit5a65e0c5e80d147909acffa14b04d3c99d48de1a (patch)
tree0987dc015729bc6e3201198102bd44ffcc69664a
parent016c2b5baddc374bebb606d3bcbef559c1bc7588 (diff)
Almost working configuration import
-rw-r--r--AndroidManifest.xml41
-rw-r--r--res/menu/import_menu.xml18
-rw-r--r--res/values/strings.xml13
-rw-r--r--res/xml/vpn_headers.xml1
-rw-r--r--src/de/blinkt/openvpn/ConfigConverter.java195
-rw-r--r--src/de/blinkt/openvpn/ConfigParser.java227
-rw-r--r--src/de/blinkt/openvpn/FileSelect.java28
-rw-r--r--src/de/blinkt/openvpn/FileSelectLayout.java4
-rw-r--r--src/de/blinkt/openvpn/FileSelectionFragment.java10
-rw-r--r--src/de/blinkt/openvpn/Settings_Authentication.java2
-rw-r--r--src/de/blinkt/openvpn/VPNProfileList.java41
-rw-r--r--src/de/blinkt/openvpn/VpnProfile.java19
12 files changed, 552 insertions, 47 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 8943334a..50d6c9f1 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -39,6 +39,7 @@
<intent-filter>
<action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
@@ -52,6 +53,46 @@
</service>
<activity
+ android:name=".ConfigConverter"
+ android:label="Convert Config File" >
+ <intent-filter android:label="foo" >
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data android:mimeType="application/x-openvpn-profile" />
+ </intent-filter>
+ <intent-filter android:label="foo" >
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data android:mimeType="application/ovpn" />
+ </intent-filter>
+ <intent-filter android:label="foo" >
+ <action android:name="android.intent.action.VIEW" />
+
+ <category android:name="android.intent.category.BROWSABLE" />
+ <category android:name="android.intent.category.DEFAULT" />
+
+ <data
+ android:pathPattern=".*\\.ovpn"
+ android:scheme="content" />
+ </intent-filter>
+ <intent-filter android:label="foo" >
+ <action android:name="android.intent.action.VIEW" />
+
+ <category android:name="android.intent.category.BROWSABLE" />
+ <category android:name="android.intent.category.DEFAULT" />
+
+ <data
+ android:pathPattern=".*\\.ovpn"
+ android:scheme="file" />
+ </intent-filter>
+ </activity>
+ <activity
android:name=".LaunchVPN"
android:label="@string/vpn_launch_title" >
<intent-filter>
diff --git a/res/menu/import_menu.xml b/res/menu/import_menu.xml
new file mode 100644
index 00000000..27498da3
--- /dev/null
+++ b/res/menu/import_menu.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <item
+ android:id="@+id/ok"
+ android:icon="@android:drawable/ic_menu_save"
+ android:showAsAction="ifRoom|withText"
+ android:title="@string/add_profile"
+ android:titleCondensed="@string/clear"/>
+ <item
+ android:id="@+id/cancel"
+ android:icon="@android:drawable/ic_menu_close_clear_cancel"
+ android:showAsAction="ifRoom|withText"
+ android:title="@android:string/cancel"
+ android:titleCondensed="@string/cancel"/>
+
+
+</menu> \ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5d605e08..a5a88219 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -195,5 +195,16 @@
<string name="error_importing_file">Error importing File</string>
<string name="import_error_message">Could not import File from Filesystem</string>
<string name="inline_file_data">[[Inline file data]]</string>
- <string name="opentun_no_ipaddr">Refusing to open tun device without IP information</string>
+ <string name="opentun_no_ipaddr">Refusing to open tun device without IP information</string>
+ <string name="menu_import">Import Profile from ovpn file</string>
+ <string name="menu_import_short">Import</string>
+ <string name="import_content_resolve_error">Could not read Profile to import</string>
+ <string name="error_reading_config_file">Error reading Config file</string>
+ <string name="add_profile">add Profile</string>
+ <string name="trying_to_read">Trying to read file: %1$s</string>
+ <string name="import_could_not_open">Could not find file %1$s mentioned in the imported Config file</string>
+ <string name="importing_config">Importing config file from source %1$s</string>
+ <string name="import_pkcs12_to_keystore">Your config file specified a pkcs12 file. Please import the file by selecting select in the Basic Settings configuration of the converted VPN</string>
+ <string name="import_warning_custom_options">Your configuration had a few configuration options that could be parsed. These options were added as custom configuration options. The custom configuration is displayed below:</string>
+ <string name="import_done">Done reading config file.</string>
</resources>
diff --git a/res/xml/vpn_headers.xml b/res/xml/vpn_headers.xml
index 60ddce7c..c299d2a5 100644
--- a/res/xml/vpn_headers.xml
+++ b/res/xml/vpn_headers.xml
@@ -4,7 +4,6 @@
<header
android:tag="BasicSettings"
android:fragment="de.blinkt.openvpn.Settings_Basic"
- android:summary="Server, port and authentication method. Normally you should only settings specified here."
android:title="Basic Settings"
android:id="@+id/basicsettingsid"/>
<!-- android:icon="@drawable/ic_settings_applications" -->
diff --git a/src/de/blinkt/openvpn/ConfigConverter.java b/src/de/blinkt/openvpn/ConfigConverter.java
new file mode 100644
index 00000000..1973e0ac
--- /dev/null
+++ b/src/de/blinkt/openvpn/ConfigConverter.java
@@ -0,0 +1,195 @@
+package de.blinkt.openvpn;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+
+import android.app.Activity;
+import android.app.ListActivity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Environment;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.widget.ArrayAdapter;
+import android.widget.Toast;
+import de.blinkt.openvpn.ConfigParser.ConfigParseError;
+
+public class ConfigConverter extends ListActivity {
+
+ public static final String IMPORT_PROFILE = "de.blinkt.openvpn.IMPORT_PROFILE";
+
+ private VpnProfile mResult;
+ private ArrayAdapter<String> mArrayAdapter;
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Toast.makeText(this, "Got called!", Toast.LENGTH_LONG).show();
+ }
+
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if(item.getItemId()==R.id.cancel){
+ setResult(Activity.RESULT_CANCELED);
+ finish();
+ } else if(item.getItemId()==R.id.ok) {
+ if(mResult==null) {
+ log("Importing the config had error, cannot save it");
+ }
+ Intent result = new Intent();
+ ProfileManager vpl = ProfileManager.getInstance(this);
+ vpl.addProfile(mResult);
+ result.putExtra(VpnProfile.EXTRA_PROFILEUUID,mResult.getUUID().toString());
+ setResult(Activity.RESULT_OK, result);
+ finish();
+ }
+
+ return super.onOptionsItemSelected(item);
+
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.import_menu, menu);
+ return true;
+ }
+
+
+ private String embedFile(String filename)
+ {
+ if(filename == null || filename.equals(""))
+ return null;
+ // Already embedded, nothing to do
+ if(filename.startsWith(VpnProfile.INLINE_TAG))
+ return filename;
+
+ // Try diffent path relative to /mnt/sdcard
+ File sdcard = Environment.getExternalStorageDirectory();
+ File root = new File("/");
+ File[] dirlist = {root, sdcard};
+ String[] fileparts = filename.split("/");
+ for(File rootdir:dirlist){
+ String suffix="";
+ for(int i=fileparts.length-1; i >=0;i--) {
+ if(i==fileparts.length-1)
+ suffix = fileparts[i];
+ else
+ suffix = fileparts[i] + "/" + suffix;
+
+ File possibleFile = new File(rootdir,suffix);
+ if(!possibleFile.canRead())
+ continue;
+
+ // read the file inline
+ String filedata = VpnProfile.INLINE_TAG;
+ byte[] buf =new byte[2048];
+
+ log(R.string.trying_to_read, possibleFile.getAbsolutePath());
+ try {
+ FileInputStream fis = new FileInputStream(possibleFile);
+ int len = fis.read(buf);
+ while( len > 0){
+ filedata += new String(buf,0,len);
+ len = fis.read(buf);
+ }
+ return filedata;
+ } catch (FileNotFoundException e) {
+ log(e.getLocalizedMessage());
+ } catch (IOException e) {
+ log(e.getLocalizedMessage());
+ }
+
+
+ }
+ }
+ log(R.string.import_could_not_open,filename);
+ return null;
+ }
+
+ void embedFiles() {
+ // This where I would like to have a c++ style
+ // void embedFile(std::string & option)
+
+ mResult.mCaFilename = embedFile(mResult.mCaFilename);
+ mResult.mClientCertFilename = embedFile(mResult.mClientCertFilename);
+ mResult.mClientKeyFilename = embedFile(mResult.mClientKeyFilename);
+ mResult.mTLSAuthFilename = embedFile(mResult.mTLSAuthFilename);
+ }
+
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+
+ mArrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
+ getListView().setAdapter(mArrayAdapter);
+ final android.content.Intent intent = getIntent ();
+
+ if (intent != null)
+ {
+ final android.net.Uri data = intent.getData ();
+ if (data != null)
+ {
+ log(R.string.importing_config,data.toString());
+ try {
+ InputStream is = getContentResolver().openInputStream(data);
+ doImport(is);
+ } catch (FileNotFoundException e) {
+ log(R.string.import_content_resolve_error);
+ }
+ }
+ }
+
+ return;
+ }
+
+ private void log(String logmessage) {
+ mArrayAdapter.add(logmessage);
+ }
+
+ private void doImport(InputStream is) {
+ ConfigParser cp = new ConfigParser();
+ try {
+ cp.parseConfig(is);
+ VpnProfile vp = cp.convertProfile();
+ mResult = vp;
+ embedFiles();
+ displayWarnings();
+ log(R.string.import_done);
+ return;
+
+ } catch (IOException e) {
+ log(R.string.error_reading_config_file);
+ log(e.getLocalizedMessage());
+ } catch (ConfigParseError e) {
+ log(R.string.error_reading_config_file);
+ log(e.getLocalizedMessage());
+ }
+ mResult=null;
+
+ }
+
+ private void displayWarnings() {
+ if(mResult.mUseCustomConfig) {
+ log(R.string.import_warning_custom_options);
+ log(mResult.mCustomConfigOptions);
+ }
+
+ if(mResult.mAuthenticationType==VpnProfile.TYPE_KEYSTORE) {
+ log(R.string.import_pkcs12_to_keystore);
+ }
+
+ }
+
+
+ private void log(int ressourceId, Object... formatArgs) {
+ log(getString(ressourceId,formatArgs));
+ }
+}
diff --git a/src/de/blinkt/openvpn/ConfigParser.java b/src/de/blinkt/openvpn/ConfigParser.java
index 97ca6396..8fde12b8 100644
--- a/src/de/blinkt/openvpn/ConfigParser.java
+++ b/src/de/blinkt/openvpn/ConfigParser.java
@@ -1,9 +1,11 @@
package de.blinkt.openvpn;
import java.io.BufferedReader;
-import java.io.FileReader;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.util.HashMap;
+import java.util.Map.Entry;
import java.util.Vector;
//! Openvpn Config FIle Parser, probably not 100% accurate but close enough
@@ -16,12 +18,13 @@ public class ConfigParser {
private HashMap<String,Vector<String>> options = new HashMap<String, Vector<String>>();
- private void parseConfig(String filename) throws IOException, ConfigParseError {
+ public void parseConfig(InputStream inputStream) throws IOException, ConfigParseError {
- FileReader fr = new FileReader(filename);
+ InputStreamReader fr = new InputStreamReader(inputStream);
BufferedReader br =new BufferedReader(fr);
+ @SuppressWarnings("unused")
int lineno=0;
while (true){
@@ -29,8 +32,6 @@ public class ConfigParser {
if(line==null)
break;
lineno++;
- System.out.print("LINE:");
- System.out.println(line);
Vector<String> args = parseline(line);
if(args.size() ==0)
continue;
@@ -51,7 +52,7 @@ public class ConfigParser {
// CHeck for <foo>
if(arg0.startsWith("<") && arg0.endsWith(">")) {
String argname = arg0.substring(1, arg0.length()-1);
- String inlinefile = "";
+ String inlinefile = VpnProfile.INLINE_TAG;
String endtag = String.format("</%s>",argname);
do {
@@ -192,37 +193,217 @@ public class ConfigParser {
return parameters;
}
- void convertProfile() throws ConfigParseError{
- VpnProfile newprofile = new VpnProfile("converted Profile");
+
+ final String[] unsupportedOptions = { "config",
+ "connection",
+ "proto-force",
+ "remote-random",
+ "tls-server"
+
+ };
+
+ // Ignore all scripts
+ // in most cases these won't work and user who wish to execute scripts will
+ // figure out themselves
+ final String[] ignoreOptions = { "tls-client",
+ "askpass",
+ "auth-nocache",
+ "up",
+ "down",
+ "route-up",
+ "ipchange",
+ "route-up",
+ "auth-user-pass-verify"
+ };
+ // Missing
+ // proto tcp-client|udp
+
+ VpnProfile convertProfile() throws ConfigParseError{
+ VpnProfile np = new VpnProfile("converted Profile");
// Pull, client, tls-client
-
+ np.clearDefaults();
+
if(options.containsKey("client") || options.containsKey("pull")) {
- newprofile.mUsePull=true;
+ np.mUsePull=true;
options.remove("pull");
options.remove("client");
}
-
- if(options.containsKey("secret")){
- newprofile.mAuthenticationType=VpnProfile.TYPE_STATICKEYS;
- options.remove("secret");
+
+ Vector<String> secret = getOption("secret", 1, 2);
+ if(secret!=null)
+ {
+ np.mAuthenticationType=VpnProfile.TYPE_STATICKEYS;
+ np.mUseTLSAuth=true;
+ np.mTLSAuthFilename=secret.get(1);
+ if(secret.size()==3)
+ np.mTLSAuthDirection=secret.get(2);
}
-
+
+ Vector<String> tlsauth = getOption("tls-auth", 1, 2);
+ if(tlsauth!=null)
+ {
+ np.mUseTLSAuth=true;
+ np.mTLSAuthFilename=tlsauth.get(1);
+ if(tlsauth.size()==3)
+ np.mTLSAuthDirection=tlsauth.get(2);
+ }
+
+ Vector<String> direction = getOption("key-direction", 1, 1);
+ if(direction!=null)
+ np.mTLSAuthDirection=direction.get(1);
+
if(options.containsKey("redirect-gateway")) {
options.remove("redirect-gateway");
- newprofile.mUseDefaultRoute=true;
+ np.mUseDefaultRoute=true;
} else {
- newprofile.mUseDefaultRoute=true;
+ np.mUseDefaultRoute=true;
}
-
- Vector<String> mode = options.get("mode");
+
+ Vector<String> dev =getOption("dev",1,1);
+ Vector<String> devtype =getOption("dev-type",1,1);
+
+ if( (devtype !=null && devtype.get(1).equals("tun")) ||
+ (dev!=null && dev.get(1).startsWith("tun")) ||
+ (devtype ==null && dev == null) ) {
+ //everything okay
+ } else {
+ throw new ConfigParseError("Sorry. Only tun mode is supported. See the FAQ for more detail");
+ }
+
+
+
+ Vector<String> mode =getOption("mode",1,1);
if (mode != null){
- options.remove("mode");
- if(mode.size() != 2)
- throw new ConfigParseError("--mode has more than one parameter");
if(!mode.get(1).equals("p2p"))
- throw new ConfigParseError("Invalid mode for --mode specified");
+ throw new ConfigParseError("Invalid mode for --mode specified, need p2p");
+ }
+
+ // Parse remote config
+ Vector<String> remote = getOption("remote",1,3);
+ if(remote != null){
+ switch (remote.size()) {
+ case 4:
+ String proto = remote.get(3);
+ if(proto.equals("udp"))
+ np.mUseUdp=true;
+ else if (proto.equals("tcp"))
+ np.mUseUdp=false;
+ else
+ throw new ConfigParseError("remote protocol must be tcp or udp");
+ case 3:
+ np.mServerPort = remote.get(2);
+ case 2:
+ np.mServerName = remote.get(1);
+ }
}
+ Vector<String> proto = getOption("proto, ", 1,1);
+ if(proto!=null){
+ if(proto.get(1).equals("udp"))
+ np.mUseUdp=true;
+ else if (proto.get(1).equals("tcp-client"))
+ np.mUseUdp=false;
+ else
+ throw new ConfigParseError("Unsupported option to --proto " + proto.get(1));
+
+ }
+
+ Vector<String> dhcpoption = getOption("dhcp-options", 1, 3);
+ if(dhcpoption!=null) {
+ String type=dhcpoption.get(1);
+
+ }
+
+ if(getOption("remote-random-hostname", 0, 0)!=null)
+ np.mUseRandomHostname=true;
+
+ if(getOption("float", 0, 0)!=null)
+ np.mUseFloat=true;
+
+ if(getOption("comp-lzo", 0, 1)!=null)
+ np.mUseLzo=true;
+
+ Vector<String> cipher = getOption("cipher", 1, 1);
+ if(cipher!=null)
+ np.mCipher= cipher.get(1);
+
+ Vector<String> ca = getOption("ca",1,1);
+ if(ca!=null){
+ np.mCaFilename = ca.get(1);
+ }
+
+ Vector<String> cert = getOption("cert",1,1);
+ if(cert!=null){
+ np.mClientCertFilename = cert.get(1);
+ np.mAuthenticationType = VpnProfile.TYPE_CERTIFICATES;
+ }
+ Vector<String> key= getOption("key",1,1);
+ if(key!=null)
+ np.mClientKeyFilename=key.get(1);
+
+ Vector<String> pkcs12 = getOption("pkcs12",1,1);
+ if(pkcs12!=null) {
+ np.mPKCS12Filename = pkcs12.get(1);
+ np.mAuthenticationType = VpnProfile.TYPE_KEYSTORE;
+ }
+
+ Vector<String> tlsremote = getOption("tls-remote",1,1);
+ if(tlsremote!=null){
+ np.mRemoteCN = tlsremote.get(1);
+ np.mCheckRemoteCN=true;
+ }
+
+ Vector<String> verb = getOption("verb",1,1);
+ if(verb!=null){
+ np.mVerb=verb.get(1);
+ }
+
+ // Check the other options
+
+ for(String option:unsupportedOptions)
+ if(options.containsKey(option))
+ throw new ConfigParseError(String.format("Unsupported Option %s encountered in config file. Aborting",option));
+
+ for(String option:ignoreOptions)
+ // removing an item which is not in the map is no error
+ options.remove(option);
+
+ if(options.size()> 0) {
+ String custom = "# These Options were found in the config file but not parsed:\n";
+ for(Entry<String, Vector<String>> option:options.entrySet()) {
+ for (String arg : option.getValue()) {
+ custom+= arg + " ";
+ }
+ custom+="\n";
+ }
+ np.mCustomConfigOptions = custom;
+ np.mUseCustomConfig=true;
+
+ }
+
+
+ fixup(np);
+
+ return np;
+ }
+
+ private void fixup(VpnProfile np) {
+ if(np.mRemoteCN.equals(np.mServerName)) {
+ np.mRemoteCN="";
+ }
+ }
+
+ private Vector<String> getOption(String option, int minarg, int maxarg) throws ConfigParseError {
+ Vector<String> args = options.get(option);
+ if(args==null)
+ return null;
+ if(args.size()< (minarg+1) || args.size() > maxarg+1) {
+ String err = String.format("Option %s has %d parameters, expected between %d and %d",
+ option,args.size()-1,minarg,maxarg );
+ throw new ConfigParseError(err);
+ }
+ options.remove(option);
+ return args;
}
}
diff --git a/src/de/blinkt/openvpn/FileSelect.java b/src/de/blinkt/openvpn/FileSelect.java
index 3cc060c6..12a3ae01 100644
--- a/src/de/blinkt/openvpn/FileSelect.java
+++ b/src/de/blinkt/openvpn/FileSelect.java
@@ -13,19 +13,19 @@ import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Fragment;
import android.app.FragmentTransaction;
-import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
public class FileSelect extends Activity {
public static final String RESULT_DATA = "RESULT_PATH";
public static final String START_DATA = "START_DATA";
- public static final String INLINE_TAG = "[[INLINE]]";
+ public static final String NO_INLINE_SELECTION = "de.blinkt.openvpn.NO_INLINE_SELECTION";
private FileSelectionFragment mFSFragment;
private InlineFileTab mInlineFragment;
private String mData;
private Tab inlineFileTab;
private Tab fileExplorerTab;
+ private boolean mNoInline;
public void onCreate(Bundle savedInstanceState)
{
@@ -33,6 +33,10 @@ public class FileSelect extends Activity {
setContentView(R.layout.file_dialog);
mData = getIntent().getStringExtra(START_DATA);
+ if(mData==null)
+ mData="/sdcard";
+
+ mNoInline = getIntent().getBooleanExtra(NO_INLINE_SELECTION, false);
ActionBar bar = getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
@@ -40,13 +44,15 @@ public class FileSelect extends Activity {
inlineFileTab = bar.newTab().setText(R.string.inline_file_tab);
mFSFragment = new FileSelectionFragment();
- mInlineFragment = new InlineFileTab();
+ mFSFragment.setNoInLine();
fileExplorerTab.setTabListener(new MyTabsListener<FileSelectionFragment>(this, mFSFragment));
- inlineFileTab.setTabListener(new MyTabsListener<InlineFileTab>(this, mInlineFragment));
-
bar.addTab(fileExplorerTab);
- bar.addTab(inlineFileTab);
+ if(!mNoInline) {
+ mInlineFragment = new InlineFileTab();
+ inlineFileTab.setTabListener(new MyTabsListener<InlineFileTab>(this, mInlineFragment));
+ bar.addTab(inlineFileTab);
+ }
}
@@ -88,7 +94,7 @@ public class FileSelect extends Activity {
Exception fe = null;
try {
FileInputStream fis = new FileInputStream(ifile);
- String data =INLINE_TAG;
+ String data =VpnProfile.INLINE_TAG;
byte buf[] =new byte[16384];
int len=fis.read(buf);
@@ -116,21 +122,21 @@ public class FileSelect extends Activity {
public void setFile(String path) {
Intent intent = new Intent();
- intent.putExtra(RESULT_DATA, mData);
+ intent.putExtra(RESULT_DATA, path);
setResult(Activity.RESULT_OK,intent);
finish();
}
public String getSelectPath() {
- if(mData.startsWith(INLINE_TAG))
+ if(mData.startsWith(VpnProfile.INLINE_TAG))
return mData;
else
return "/mnt/sdcard";
}
public CharSequence getInlineData() {
- if(mData.startsWith(INLINE_TAG))
- return mData.substring(INLINE_TAG.length());
+ if(mData.startsWith(VpnProfile.INLINE_TAG))
+ return mData.substring(VpnProfile.INLINE_TAG.length());
else
return "";
}
diff --git a/src/de/blinkt/openvpn/FileSelectLayout.java b/src/de/blinkt/openvpn/FileSelectLayout.java
index bbaf7778..0be099af 100644
--- a/src/de/blinkt/openvpn/FileSelectLayout.java
+++ b/src/de/blinkt/openvpn/FileSelectLayout.java
@@ -57,7 +57,9 @@ public class FileSelectLayout extends LinearLayout implements OnClickListener {
public void setData(String data) {
mData = data;
- if(mData.startsWith(FileSelect.INLINE_TAG))
+ if(data==null)
+ mDataView.setText(mFragment.getString(R.string.no_data));
+ else if(mData.startsWith(VpnProfile.INLINE_TAG))
mDataView.setText(R.string.inline_file_data);
else
mDataView.setText(data);
diff --git a/src/de/blinkt/openvpn/FileSelectionFragment.java b/src/de/blinkt/openvpn/FileSelectionFragment.java
index 31390280..41c7a1eb 100644
--- a/src/de/blinkt/openvpn/FileSelectionFragment.java
+++ b/src/de/blinkt/openvpn/FileSelectionFragment.java
@@ -51,6 +51,7 @@ public class FileSelectionFragment extends ListFragment {
private HashMap<String, Integer> lastPositions = new HashMap<String, Integer>();
private String mStartPath;
private Button importFile;
+ private boolean mHideImport=false;
@Override
@@ -73,6 +74,7 @@ public class FileSelectionFragment extends ListFragment {
}
});
+
importFile = (Button) v.findViewById(R.id.importfile);
importFile.setEnabled(false);
importFile.setOnClickListener(new OnClickListener() {
@@ -83,7 +85,9 @@ public class FileSelectionFragment extends ListFragment {
}
});
-
+ if(mHideImport== true) {
+ importFile.setVisibility(View.GONE);
+ }
return v;
@@ -241,4 +245,8 @@ public class FileSelectionFragment extends ListFragment {
}
}
+ public void setNoInLine() {
+ mHideImport=true;
+ }
+
}
diff --git a/src/de/blinkt/openvpn/Settings_Authentication.java b/src/de/blinkt/openvpn/Settings_Authentication.java
index 5849923d..e8740b5d 100644
--- a/src/de/blinkt/openvpn/Settings_Authentication.java
+++ b/src/de/blinkt/openvpn/Settings_Authentication.java
@@ -131,7 +131,7 @@ public class Settings_Authentication extends PreferenceFragment implements OnPre
private void setTlsAuthSummary(String result) {
if(result==null) result = getString(R.string.no_certificate);
- if(result.startsWith(FileSelect.INLINE_TAG))
+ if(result.startsWith(VpnProfile.INLINE_TAG))
mTLSAuthFile.setSummary(R.string.inline_file_data);
else
mTLSAuthFile.setSummary(result);
diff --git a/src/de/blinkt/openvpn/VPNProfileList.java b/src/de/blinkt/openvpn/VPNProfileList.java
index a578251c..a14c835e 100644
--- a/src/de/blinkt/openvpn/VPNProfileList.java
+++ b/src/de/blinkt/openvpn/VPNProfileList.java
@@ -1,11 +1,13 @@
package de.blinkt.openvpn;
+import de.blinkt.openvpn.FileSelect.MyTabsListener;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ListFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.net.Uri;
import android.os.Bundle;
import android.view.ActionMode;
import android.view.Menu;
@@ -56,11 +58,8 @@ public class VPNProfileList extends ListFragment {
}
});
-
return v;
}
-
-
}
@@ -68,6 +67,13 @@ public class VPNProfileList extends ListFragment {
private static final int MENU_ADD_PROFILE = Menu.FIRST;
private static final int START_VPN_CONFIG = 92;
+ private static final int SELECT_PROFILE = 43;
+ private static final int IMPORT_PROFILE = 231;
+
+ private static final int MENU_IMPORT_PROFILE = Menu.FIRST +1;
+
+
+
private ArrayAdapter<VpnProfile> mArrayadapter;
@@ -104,6 +110,13 @@ public class VPNProfileList extends ListFragment {
.setAlphabeticShortcut('a')
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM
| MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+
+ menu.add(0, MENU_IMPORT_PROFILE, 0, R.string.menu_import)
+ .setIcon(android.R.drawable.ic_menu_myplaces)
+ .setAlphabeticShortcut('a')
+ .setTitleCondensed(getActivity().getString(R.string.menu_import_short))
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM
+ | MenuItem.SHOW_AS_ACTION_WITH_TEXT );
}
@@ -113,6 +126,11 @@ public class VPNProfileList extends ListFragment {
if (itemId == MENU_ADD_PROFILE) {
onAddProfileClicked();
return true;
+ } else if (itemId == MENU_IMPORT_PROFILE) {
+ Intent intent = new Intent(getActivity(),FileSelect.class);
+ intent.putExtra(FileSelect.NO_INLINE_SELECTION, true);
+ startActivityForResult(intent, SELECT_PROFILE);
+ return true;
} else {
return super.onOptionsItemSelected(item);
}
@@ -198,13 +216,26 @@ public class VPNProfileList extends ListFragment {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
- if (requestCode == START_VPN_CONFIG && resultCode == Activity.RESULT_OK) {
- String configuredVPN = data.getStringExtra(getActivity().getPackageName() + ".profileUUID");
+ if(resultCode != Activity.RESULT_OK)
+ return;
+
+ if (requestCode == START_VPN_CONFIG) {
+ String configuredVPN = data.getStringExtra(VpnProfile.EXTRA_PROFILEUUID);
VpnProfile profile = ProfileManager.get(configuredVPN);
getPM().saveProfile(getActivity(), profile);
// Name could be modified
+ } else if(requestCode== SELECT_PROFILE) {
+ String filedata = data.getStringExtra(FileSelect.RESULT_DATA);
+ Intent startImport = new Intent(getActivity(),ConfigConverter.class);
+ startImport.setAction(ConfigConverter.IMPORT_PROFILE);
+ Uri uri = new Uri.Builder().path(filedata).scheme("file").build();
+ startImport.setData(uri);
+ startActivityForResult(startImport, IMPORT_PROFILE);
+ } else if(requestCode == IMPORT_PROFILE) {
+ String profileUUID = data.getStringExtra(VpnProfile.EXTRA_PROFILEUUID);
+ mArrayadapter.add(ProfileManager.get(profileUUID));
}
}
diff --git a/src/de/blinkt/openvpn/VpnProfile.java b/src/de/blinkt/openvpn/VpnProfile.java
index 639619ff..b7297e89 100644
--- a/src/de/blinkt/openvpn/VpnProfile.java
+++ b/src/de/blinkt/openvpn/VpnProfile.java
@@ -38,6 +38,8 @@ public class VpnProfile implements Serializable{
public static final int TYPE_USERPASS_PKCS12 = 6;
public static final int TYPE_USERPASS_KEYSTORE = 7;
+ // Don't change this, not all parts of the program use this constant
+ public static final String EXTRA_PROFILEUUID = "de.blinkt.openvpn.profileUUID";
@@ -90,6 +92,17 @@ public class VpnProfile implements Serializable{
public String mCustomConfigOptions="";
public String mVerb="1";
public String mCipher="";
+ public static final String INLINE_TAG = "[[INLINE]]";
+
+
+
+ public void clearDefaults() {
+ mServerName="unkown";
+ mUsePull=false;
+ mUseLzo=false;
+ mUseDefaultRoute=false;
+ mExpectTLSCert=false;
+ }
public static String openVpnEscape(String unescaped) {
@@ -294,11 +307,11 @@ public class VpnProfile implements Serializable{
//! Put inline data inline and other data as normal escaped filename
private String insertFileData(String cfgentry, String filedata) {
- if(filedata.startsWith(FileSelect.INLINE_TAG)){
- String datawoheader = filedata.substring(FileSelect.INLINE_TAG.length());
+ if(filedata.startsWith(VpnProfile.INLINE_TAG)){
+ String datawoheader = filedata.substring(VpnProfile.INLINE_TAG.length());
return String.format("<%s>\n%s\n</%s>\n",cfgentry,datawoheader,cfgentry);
} else {
- return String.format("%s %s",cfgentry,openVpnEscape(filedata));
+ return String.format("%s %s\n",cfgentry,openVpnEscape(filedata));
}
}