From 49653f7c3811a29afc92b3def7430e962a39fe0b Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Wed, 11 Dec 2013 10:18:06 +0100 Subject: Move activities and views into packages --HG-- rename : src/de/blinkt/openvpn/ConfigConverter.java => src/de/blinkt/openvpn/activities/ConfigConverter.java rename : src/de/blinkt/openvpn/app/CreateShortcuts.java => src/de/blinkt/openvpn/activities/CreateShortcuts.java rename : src/de/blinkt/openvpn/DisconnectVPN.java => src/de/blinkt/openvpn/activities/DisconnectVPN.java rename : src/de/blinkt/openvpn/FileSelect.java => src/de/blinkt/openvpn/activities/FileSelect.java rename : src/de/blinkt/openvpn/LogWindow.java => src/de/blinkt/openvpn/activities/LogWindow.java rename : src/de/blinkt/openvpn/MainActivity.java => src/de/blinkt/openvpn/activities/MainActivity.java rename : src/de/blinkt/openvpn/FileSelectLayout.java => src/de/blinkt/openvpn/views/FileSelectLayout.java rename : src/de/blinkt/openvpn/RemoteCNPreference.java => src/de/blinkt/openvpn/views/RemoteCNPreference.java rename : src/de/blinkt/openvpn/fragments/SeekBarTicks.java => src/de/blinkt/openvpn/views/SeekBarTicks.java extra : rebase_source : fccff1bc269dbc0ae33b96a4947b8a6e2924efeb --- src/de/blinkt/openvpn/ConfigConverter.java | 457 -------------------- src/de/blinkt/openvpn/DisconnectVPN.java | 80 ---- src/de/blinkt/openvpn/FileSelect.java | 214 ---------- src/de/blinkt/openvpn/FileSelectLayout.java | 102 ----- src/de/blinkt/openvpn/LaunchVPN.java | 7 +- src/de/blinkt/openvpn/LogDetailActionProvider.java | 61 --- src/de/blinkt/openvpn/LogWindow.java | 30 -- src/de/blinkt/openvpn/MainActivity.java | 101 ----- src/de/blinkt/openvpn/RemoteCNPreference.java | 138 ------- .../blinkt/openvpn/activities/ConfigConverter.java | 460 +++++++++++++++++++++ .../blinkt/openvpn/activities/CreateShortcuts.java | 154 +++++++ .../blinkt/openvpn/activities/DisconnectVPN.java | 82 ++++ src/de/blinkt/openvpn/activities/FileSelect.java | 217 ++++++++++ src/de/blinkt/openvpn/activities/LogWindow.java | 32 ++ src/de/blinkt/openvpn/activities/MainActivity.java | 103 +++++ src/de/blinkt/openvpn/app/CreateShortcuts.java | 154 ------- src/de/blinkt/openvpn/core/OpenVpnService.java | 5 +- .../openvpn/fragments/FileSelectionFragment.java | 2 +- src/de/blinkt/openvpn/fragments/InlineFileTab.java | 2 +- src/de/blinkt/openvpn/fragments/LogFragment.java | 2 + src/de/blinkt/openvpn/fragments/SeekBarTicks.java | 69 ---- .../openvpn/fragments/Settings_Authentication.java | 5 +- .../blinkt/openvpn/fragments/Settings_Basic.java | 6 +- .../blinkt/openvpn/fragments/VPNProfileList.java | 5 +- src/de/blinkt/openvpn/views/FileSelectLayout.java | 105 +++++ .../blinkt/openvpn/views/RemoteCNPreference.java | 141 +++++++ src/de/blinkt/openvpn/views/SeekBarTicks.java | 69 ++++ 27 files changed, 1377 insertions(+), 1426 deletions(-) delete mode 100644 src/de/blinkt/openvpn/ConfigConverter.java delete mode 100644 src/de/blinkt/openvpn/DisconnectVPN.java delete mode 100644 src/de/blinkt/openvpn/FileSelect.java delete mode 100644 src/de/blinkt/openvpn/FileSelectLayout.java delete mode 100644 src/de/blinkt/openvpn/LogDetailActionProvider.java delete mode 100644 src/de/blinkt/openvpn/LogWindow.java delete mode 100644 src/de/blinkt/openvpn/MainActivity.java delete mode 100644 src/de/blinkt/openvpn/RemoteCNPreference.java create mode 100644 src/de/blinkt/openvpn/activities/ConfigConverter.java create mode 100644 src/de/blinkt/openvpn/activities/CreateShortcuts.java create mode 100644 src/de/blinkt/openvpn/activities/DisconnectVPN.java create mode 100644 src/de/blinkt/openvpn/activities/FileSelect.java create mode 100644 src/de/blinkt/openvpn/activities/LogWindow.java create mode 100644 src/de/blinkt/openvpn/activities/MainActivity.java delete mode 100644 src/de/blinkt/openvpn/app/CreateShortcuts.java delete mode 100644 src/de/blinkt/openvpn/fragments/SeekBarTicks.java create mode 100644 src/de/blinkt/openvpn/views/FileSelectLayout.java create mode 100644 src/de/blinkt/openvpn/views/RemoteCNPreference.java create mode 100644 src/de/blinkt/openvpn/views/SeekBarTicks.java (limited to 'src/de/blinkt/openvpn') diff --git a/src/de/blinkt/openvpn/ConfigConverter.java b/src/de/blinkt/openvpn/ConfigConverter.java deleted file mode 100644 index 11a3055a..00000000 --- a/src/de/blinkt/openvpn/ConfigConverter.java +++ /dev/null @@ -1,457 +0,0 @@ - -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 java.io.InputStreamReader; -import java.util.HashSet; -import java.util.List; -import java.util.Vector; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.AlertDialog.Builder; -import android.app.ListActivity; -import android.content.ActivityNotFoundException; -import android.content.Intent; -import android.os.Bundle; -import android.os.Environment; -import android.security.KeyChain; -import android.security.KeyChainAliasCallback; -import android.text.TextUtils; -import android.util.Base64; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.ArrayAdapter; -import android.widget.CheckBox; -import de.blinkt.openvpn.core.ConfigParser; -import de.blinkt.openvpn.core.ConfigParser.ConfigParseError; -import de.blinkt.openvpn.core.ProfileManager; - -public class ConfigConverter extends ListActivity { - - public static final String IMPORT_PROFILE = "de.blinkt.openvpn.IMPORT_PROFILE"; - - private VpnProfile mResult; - private ArrayAdapter mArrayAdapter; - - private List mPathsegments; - - private String mAliasName=null; - - private int RESULT_INSTALLPKCS12 = 7; - - private String mPossibleName=null; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.config_converter); - } - - - - @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"); - return true; - } - - Intent in = installPKCS12(); - - if(in != null) - startActivityForResult(in, RESULT_INSTALLPKCS12); - else - saveProfile(); - - return true; - } - - return super.onOptionsItemSelected(item); - - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if(requestCode==RESULT_INSTALLPKCS12) { - if(resultCode==Activity.RESULT_OK) { - showCertDialog(); - } - } - - super.onActivityResult(requestCode, resultCode, data); - } - - private void saveProfile() { - Intent result = new Intent(); - ProfileManager vpl = ProfileManager.getInstance(this); - - setUniqueProfileName(vpl); - vpl.addProfile(mResult); - vpl.saveProfile(this, mResult); - vpl.saveProfileList(this); - result.putExtra(VpnProfile.EXTRA_PROFILEUUID,mResult.getUUID().toString()); - setResult(Activity.RESULT_OK, result); - finish(); - } - - public void showCertDialog () { - try { - KeyChain.choosePrivateKeyAlias(this, - new KeyChainAliasCallback() { - - public void alias(String alias) { - // Credential alias selected. Remember the alias selection for future use. - mResult.mAlias=alias; - saveProfile(); - } - - - }, - new String[] {"RSA"}, // List of acceptable key types. null for any - null, // issuer, null for any - mResult.mServerName, // host name of server requesting the cert, null if unavailable - -1, // port of server requesting the cert, -1 if unavailable - mAliasName); // alias to preselect, null if unavailable - } catch (ActivityNotFoundException anf) { - Builder ab = new AlertDialog.Builder(this); - ab.setTitle(R.string.broken_image_cert_title); - ab.setMessage(R.string.broken_image_cert); - ab.setPositiveButton(android.R.string.ok, null); - ab.show(); - } - } - - - private Intent installPKCS12() { - - if(!((CheckBox)findViewById(R.id.importpkcs12)).isChecked()) { - setAuthTypeToEmbeddedPKCS12(); - return null; - - } - String pkcs12datastr = mResult.mPKCS12Filename; - if(pkcs12datastr!=null && pkcs12datastr.startsWith(VpnProfile.INLINE_TAG)) { - Intent inkeyintent = KeyChain.createInstallIntent(); - - pkcs12datastr= pkcs12datastr.substring(VpnProfile.INLINE_TAG.length()); - - - byte[] pkcs12data = Base64.decode(pkcs12datastr, Base64.DEFAULT); - - - inkeyintent.putExtra(KeyChain.EXTRA_PKCS12,pkcs12data ); - - if(mAliasName.equals("")) - mAliasName=null; - - if(mAliasName!=null){ - inkeyintent.putExtra(KeyChain.EXTRA_NAME, mAliasName); - } - return inkeyintent; - - } - return null; - } - - - - private void setAuthTypeToEmbeddedPKCS12() { - if(mResult.mPKCS12Filename!=null && mResult.mPKCS12Filename.startsWith(VpnProfile.INLINE_TAG)) { - if(mResult.mAuthenticationType==VpnProfile.TYPE_USERPASS_KEYSTORE) - mResult.mAuthenticationType=VpnProfile.TYPE_USERPASS_PKCS12; - - if(mResult.mAuthenticationType==VpnProfile.TYPE_KEYSTORE) - mResult.mAuthenticationType=VpnProfile.TYPE_PKCS12; - - } - } - - - - - - private void setUniqueProfileName(ProfileManager vpl) { - int i=0; - - String newname = mPossibleName; - - // Default to - if(mResult.mName!=null && !ConfigParser.CONVERTED_PROFILE.equals(mResult.mName)) - newname=mResult.mName; - - while(newname==null || vpl.getProfileByName(newname)!=null) { - i++; - if(i==1) - newname = getString(R.string.converted_profile); - else - newname = getString(R.string.converted_profile_i,i); - } - - mResult.mName=newname; - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.import_menu, menu); - return true; - } - - private String embedFile(String filename) { - return embedFile(filename, false); - } - - private String embedFile(String filename, boolean base64encode) - { - if(filename==null) - return null; - - // Already embedded, nothing to do - if(filename.startsWith(VpnProfile.INLINE_TAG)) - return filename; - - File possibleFile = findFile(filename); - if(possibleFile==null) - return filename; - else - return readFileContent(possibleFile,base64encode); - - } - - private File findFile(String filename) { - File foundfile =findFileRaw(filename); - - if (foundfile==null && filename!=null && !filename.equals("")) - log(R.string.import_could_not_open,filename); - - return foundfile; - } - - - - private File findFileRaw(String filename) - { - if(filename == null || filename.equals("")) - return null; - - // Try diffent path relative to /mnt/sdcard - File sdcard = Environment.getExternalStorageDirectory(); - File root = new File("/"); - - HashSet dirlist = new HashSet(); - - for(int i=mPathsegments.size()-1;i >=0 ;i--){ - String path = ""; - for (int j = 0;j<=i;j++) { - path += "/" + mPathsegments.get(j); - } - // Do a little hackish dance for the Android File Importer - // /document/primary:ovpn/openvpn-imt.conf - - if (path.indexOf(':')!=-1) { - String possibleDir = path.substring(path.indexOf(':')+1,path.length()); - possibleDir.substring(0,possibleDir.lastIndexOf('/')); - dirlist.add(new File(sdcard,possibleDir)); - - - } - dirlist.add(new File(path)); - } - dirlist.add(sdcard); - dirlist.add(root); - - - 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 - return possibleFile; - - } - } - return null; - } - - String readFileContent(File possibleFile, boolean base64encode) { - byte [] filedata; - try { - filedata = readBytesFromFile(possibleFile); - } catch (IOException e) { - log(e.getLocalizedMessage()); - return null; - } - - String data; - if(base64encode) { - data = Base64.encodeToString(filedata, Base64.DEFAULT); - } else { - data = new String(filedata); - - } - return VpnProfile.INLINE_TAG + data; - - } - - - private byte[] readBytesFromFile(File file) throws IOException { - InputStream input = new FileInputStream(file); - - long len= file.length(); - if (len > VpnProfile.MAX_EMBED_FILE_SIZE) - throw new IOException("File size of file to import too large."); - - // Create the byte array to hold the data - byte[] bytes = new byte[(int) len]; - - // Read in the bytes - int offset = 0; - int bytesRead = 0; - while (offset < bytes.length - && (bytesRead=input.read(bytes, offset, bytes.length-offset)) >= 0) { - offset += bytesRead; - } - - input.close(); - return bytes; - } - - void embedFiles() { - // This where I would like to have a c++ style - // void embedFile(std::string & option) - - if (mResult.mPKCS12Filename!=null) { - File pkcs12file = findFileRaw(mResult.mPKCS12Filename); - if(pkcs12file!=null) { - mAliasName = pkcs12file.getName().replace(".p12", ""); - } else { - mAliasName = "Imported PKCS12"; - } - } - - - mResult.mCaFilename = embedFile(mResult.mCaFilename); - mResult.mClientCertFilename = embedFile(mResult.mClientCertFilename); - mResult.mClientKeyFilename = embedFile(mResult.mClientKeyFilename); - mResult.mTLSAuthFilename = embedFile(mResult.mTLSAuthFilename); - mResult.mPKCS12Filename = embedFile(mResult.mPKCS12Filename,true); - - - if(mResult.mUsername == null && mResult.mPassword != null ){ - String data =embedFile(mResult.mPassword); - ConfigParser.useEmbbedUserAuth(mResult, data); - } - } - - - @Override - protected void onStart() { - super.onStart(); - - mArrayAdapter = new ArrayAdapter(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.import_experimental); - log(R.string.importing_config,data.toString()); - try { - if(data.getScheme().equals("file") || - data.getLastPathSegment().endsWith(".ovpn") || - data.getLastPathSegment().endsWith(".conf")) - { - mPossibleName = data.getLastPathSegment(); - if (mPossibleName.lastIndexOf('/')!=-1) - mPossibleName = mPossibleName.substring(mPossibleName.lastIndexOf('/')+1); - - if(mPossibleName!=null){ - mPossibleName =mPossibleName.replace(".ovpn", ""); - mPossibleName =mPossibleName.replace(".conf", ""); - } - } - InputStream is = getContentResolver().openInputStream(data); - mPathsegments = data.getPathSegments(); - - doImport(is); - } catch (FileNotFoundException e) { - log(R.string.import_content_resolve_error); - } - } - } - } - - private void log(String logmessage) { - mArrayAdapter.add(logmessage); - } - - private void doImport(InputStream is) { - ConfigParser cp = new ConfigParser(); - try { - InputStreamReader isr = new InputStreamReader(is); - - cp.parseConfig(isr); - 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); - String copt = mResult.mCustomConfigOptions; - if(copt.startsWith("#")) { - int until = copt.indexOf('\n'); - copt = copt.substring(until+1); - } - - log(copt); - } - - if(mResult.mAuthenticationType==VpnProfile.TYPE_KEYSTORE || - mResult.mAuthenticationType == VpnProfile.TYPE_USERPASS_KEYSTORE) { - findViewById(R.id.importpkcs12).setVisibility(View.VISIBLE); - } - - } - - private void log(int ressourceId, Object... formatArgs) { - log(getString(ressourceId,formatArgs)); - } -} diff --git a/src/de/blinkt/openvpn/DisconnectVPN.java b/src/de/blinkt/openvpn/DisconnectVPN.java deleted file mode 100644 index 0f9e83aa..00000000 --- a/src/de/blinkt/openvpn/DisconnectVPN.java +++ /dev/null @@ -1,80 +0,0 @@ -package de.blinkt.openvpn; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.*; -import android.os.IBinder; -import de.blinkt.openvpn.core.OpenVpnService; -import de.blinkt.openvpn.core.ProfileManager; - -/** - * Created by arne on 13.10.13. - */ -public class DisconnectVPN extends Activity implements DialogInterface.OnClickListener{ - protected OpenVpnService mService; - - private ServiceConnection mConnection = new ServiceConnection() { - - - @Override - public void onServiceConnected(ComponentName className, - IBinder service) { - // We've bound to LocalService, cast the IBinder and get LocalService instance - OpenVpnService.LocalBinder binder = (OpenVpnService.LocalBinder) service; - mService = binder.getService(); - } - - @Override - public void onServiceDisconnected(ComponentName arg0) { - mService =null; - } - - }; - - @Override - protected void onResume() { - super.onResume(); - Intent intent = new Intent(this, OpenVpnService.class); - intent.setAction(OpenVpnService.START_SERVICE); - bindService(intent, mConnection, Context.BIND_AUTO_CREATE); - showDisconnectDialog(); - } - - @Override - protected void onStop() { - super.onStop(); - unbindService(mConnection); - } - - // if (getIntent() !=null && OpenVpnService.DISCONNECT_VPN.equals(getIntent().getAction())) - - // setIntent(null); - - /* - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - setIntent(intent); - } - */ - - private void showDisconnectDialog() { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.title_cancel); - builder.setMessage(R.string.cancel_connection_query); - builder.setNegativeButton(android.R.string.no, this); - builder.setPositiveButton(android.R.string.yes,this); - - builder.show(); - } - - @Override - public void onClick(DialogInterface dialog, int which) { - if (which == DialogInterface.BUTTON_POSITIVE) { - ProfileManager.setConntectedVpnProfileDisconnected(this); - if (mService != null && mService.getManagement() != null) - mService.getManagement().stopVPN(); - } - finish(); - } -} diff --git a/src/de/blinkt/openvpn/FileSelect.java b/src/de/blinkt/openvpn/FileSelect.java deleted file mode 100644 index 8389a2ab..00000000 --- a/src/de/blinkt/openvpn/FileSelect.java +++ /dev/null @@ -1,214 +0,0 @@ -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.ActionBar; -import android.app.ActionBar.Tab; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.AlertDialog.Builder; -import android.app.Fragment; -import android.app.FragmentTransaction; -import android.content.Intent; -import android.os.Bundle; -import android.os.Environment; -import android.util.Base64; -import de.blinkt.openvpn.fragments.FileSelectionFragment; -import de.blinkt.openvpn.fragments.InlineFileTab; - -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 WINDOW_TITLE = "WINDOW_TILE"; - public static final String NO_INLINE_SELECTION = "de.blinkt.openvpn.NO_INLINE_SELECTION"; - public static final String SHOW_CLEAR_BUTTON = "de.blinkt.openvpn.SHOW_CLEAR_BUTTON"; - public static final String DO_BASE64_ENCODE = "de.blinkt.openvpn.BASE64ENCODE"; - - private FileSelectionFragment mFSFragment; - private InlineFileTab mInlineFragment; - private String mData; - private Tab inlineFileTab; - private Tab fileExplorerTab; - private boolean mNoInline; - private boolean mShowClear; - private boolean mBase64Encode; - - - public void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - setContentView(R.layout.file_dialog); - - mData = getIntent().getStringExtra(START_DATA); - if(mData==null) - mData=Environment.getExternalStorageDirectory().getPath(); - - String title = getIntent().getStringExtra(WINDOW_TITLE); - int titleId = getIntent().getIntExtra(WINDOW_TITLE, 0); - if(titleId!=0) - title =getString(titleId); - if(title!=null) - setTitle(title); - - mNoInline = getIntent().getBooleanExtra(NO_INLINE_SELECTION, false); - mShowClear = getIntent().getBooleanExtra(SHOW_CLEAR_BUTTON, false); - mBase64Encode = getIntent().getBooleanExtra(DO_BASE64_ENCODE, false); - - ActionBar bar = getActionBar(); - bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); - fileExplorerTab = bar.newTab().setText(R.string.file_explorer_tab); - inlineFileTab = bar.newTab().setText(R.string.inline_file_tab); - - mFSFragment = new FileSelectionFragment(); - fileExplorerTab.setTabListener(new MyTabsListener(this, mFSFragment)); - bar.addTab(fileExplorerTab); - - if(!mNoInline) { - mInlineFragment = new InlineFileTab(); - inlineFileTab.setTabListener(new MyTabsListener(this, mInlineFragment)); - bar.addTab(inlineFileTab); - } else { - mFSFragment.setNoInLine(); - } - - - } - - public boolean showClear() { - if(mData == null || mData.equals("")) - return false; - else - return mShowClear; - } - - protected class MyTabsListener implements ActionBar.TabListener - { - private Fragment mFragment; - private boolean mAdded=false; - - public MyTabsListener( Activity activity, Fragment fragment){ - this.mFragment = fragment; - } - - public void onTabSelected(Tab tab, FragmentTransaction ft) { - // Check if the fragment is already initialized - if (!mAdded) { - // If not, instantiate and add it to the activity - ft.add(android.R.id.content, mFragment); - mAdded =true; - } else { - // If it exists, simply attach it in order to show it - ft.attach(mFragment); - } - } - - @Override - public void onTabUnselected(Tab tab, FragmentTransaction ft) { - ft.detach(mFragment); - } - - @Override - public void onTabReselected(Tab tab, FragmentTransaction ft) { - - } - } - - public void importFile(String path) { - File ifile = new File(path); - Exception fe = null; - try { - - String data = ""; - - byte[] filedata = readBytesFromFile(ifile) ; - if(mBase64Encode) - data += Base64.encodeToString(filedata, Base64.DEFAULT); - else - data += new String(filedata); - - mData =data; - - /* - mInlineFragment.setData(data); - getActionBar().selectTab(inlineFileTab); */ - saveInlineData(data); - } catch (FileNotFoundException e) { - fe = e; - } catch (IOException e) { - fe =e; - } - if(fe!=null) { - Builder ab = new AlertDialog.Builder(this); - ab.setTitle(R.string.error_importing_file); - ab.setMessage(getString(R.string.import_error_message) + "\n" + fe.getLocalizedMessage()); - ab.setPositiveButton(android.R.string.ok, null); - ab.show(); - } - } - - private byte[] readBytesFromFile(File file) throws IOException { - InputStream input = new FileInputStream(file); - - long len= file.length(); - if (len > VpnProfile.MAX_EMBED_FILE_SIZE) - throw new IOException("selected file size too big to embed into profile"); - - // Create the byte array to hold the data - byte[] bytes = new byte[(int) len]; - - // Read in the bytes - int offset = 0; - int bytesRead = 0; - while (offset < bytes.length - && (bytesRead=input.read(bytes, offset, bytes.length-offset)) >= 0) { - offset += bytesRead; - } - - input.close(); - return bytes; - } - - - public void setFile(String path) { - Intent intent = new Intent(); - intent.putExtra(RESULT_DATA, path); - setResult(Activity.RESULT_OK,intent); - finish(); - } - - public String getSelectPath() { - if(!mData.startsWith(VpnProfile.INLINE_TAG)) - return mData; - else - return Environment.getExternalStorageDirectory().getPath(); - } - - public CharSequence getInlineData() { - if(mData.startsWith(VpnProfile.INLINE_TAG)) - return mData.substring(VpnProfile.INLINE_TAG.length()); - else - return ""; - } - - public void clearData() { - Intent intent = new Intent(); - intent.putExtra(RESULT_DATA, (String)null); - setResult(Activity.RESULT_OK,intent); - finish(); - - } - - public void saveInlineData(String string) { - Intent intent = new Intent(); - - intent.putExtra(RESULT_DATA,VpnProfile.INLINE_TAG + string); - setResult(Activity.RESULT_OK,intent); - finish(); - - } -} diff --git a/src/de/blinkt/openvpn/FileSelectLayout.java b/src/de/blinkt/openvpn/FileSelectLayout.java deleted file mode 100644 index ce2f5b20..00000000 --- a/src/de/blinkt/openvpn/FileSelectLayout.java +++ /dev/null @@ -1,102 +0,0 @@ -package de.blinkt.openvpn; - -import de.blinkt.openvpn.core.X509Utils; -import android.app.Fragment; -import android.content.Context; -import android.content.Intent; -import android.content.res.TypedArray; -import android.util.AttributeSet; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; -import android.widget.LinearLayout; -import android.widget.TextView; - - -public class FileSelectLayout extends LinearLayout implements OnClickListener { - - private final boolean mIsCertificate; - private TextView mDataView; - private String mData; - private Fragment mFragment; - private int mTaskId; - private Button mSelectButton; - private boolean mBase64Encode; - private String mTitle; - private boolean mShowClear; - private TextView mDataDetails; - - public FileSelectLayout( Context context, AttributeSet attrset) { - super(context,attrset); - inflate(getContext(), R.layout.file_select, this); - - TypedArray ta = context.obtainStyledAttributes(attrset, R.styleable.FileSelectLayout); - - mTitle = ta.getString(R.styleable.FileSelectLayout_title); - mIsCertificate = ta.getBoolean(R.styleable.FileSelectLayout_certificate,true); - - TextView tview = (TextView) findViewById(R.id.file_title); - tview.setText(mTitle); - - mDataView = (TextView) findViewById(R.id.file_selected_item); - mDataDetails = (TextView) findViewById(R.id.file_selected_description); - mSelectButton = (Button) findViewById(R.id.file_select_button); - mSelectButton.setOnClickListener(this); - - ta.recycle(); - } - - public void setFragment(Fragment fragment, int i) - { - mTaskId = i; - mFragment = fragment; - } - - public void getCertificateFileDialog() { - Intent startFC = new Intent(getContext(),FileSelect.class); - startFC.putExtra(FileSelect.START_DATA, mData); - startFC.putExtra(FileSelect.WINDOW_TITLE,mTitle); - if(mBase64Encode) - startFC.putExtra(FileSelect.DO_BASE64_ENCODE, true); - if(mShowClear) - startFC.putExtra(FileSelect.SHOW_CLEAR_BUTTON, true); - mFragment.startActivityForResult(startFC,mTaskId); - } - - - public String getData() { - return mData; - } - - public void setData(String data, Context c) { - mData = data; - if(data==null) { - mDataView.setText(mFragment.getString(R.string.no_data)); - mDataDetails.setText(""); - }else { - if(mData.startsWith(VpnProfile.INLINE_TAG)) - mDataView.setText(R.string.inline_file_data); - else - mDataView.setText(data); - if(mIsCertificate) - mDataDetails.setText(X509Utils.getCertificateFriendlyName(c,data)); - } - - } - - @Override - public void onClick(View v) { - if(v == mSelectButton) { - getCertificateFileDialog(); - } - } - - public void setBase64Encode() { - mBase64Encode =true; - } - - public void setShowClear() { - mShowClear=true; - } - -} diff --git a/src/de/blinkt/openvpn/LaunchVPN.java b/src/de/blinkt/openvpn/LaunchVPN.java index 92849dd0..10dd3e99 100644 --- a/src/de/blinkt/openvpn/LaunchVPN.java +++ b/src/de/blinkt/openvpn/LaunchVPN.java @@ -1,12 +1,9 @@ package de.blinkt.openvpn; import java.io.IOException; -import java.util.Collection; -import java.util.Vector; import android.app.Activity; import android.app.AlertDialog; -import android.app.ListActivity; import android.content.ActivityNotFoundException; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; @@ -14,14 +11,14 @@ import android.content.Intent; import android.content.SharedPreferences; import android.net.VpnService; import android.os.Bundle; -import android.os.Parcelable; import android.preference.PreferenceManager; import android.text.InputType; import android.text.TextUtils; import android.text.method.PasswordTransformationMethod; import android.view.View; import android.widget.*; -import android.widget.AdapterView.OnItemClickListener; + +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; diff --git a/src/de/blinkt/openvpn/LogDetailActionProvider.java b/src/de/blinkt/openvpn/LogDetailActionProvider.java deleted file mode 100644 index 697d5b3a..00000000 --- a/src/de/blinkt/openvpn/LogDetailActionProvider.java +++ /dev/null @@ -1,61 +0,0 @@ -package de.blinkt.openvpn; - -import android.annotation.TargetApi; -import android.app.ActionBar; -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.view.*; -import android.widget.SpinnerAdapter; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -/** - * Created by arne on 22.09.13. - */ -public class LogDetailActionProvider extends ActionProvider { - /** - * Creates a new instance. ActionProvider classes should always implement a - * constructor that takes a single Context parameter for inflating from menu XML. - * - * @param context Context for accessing resources. - */ - public LogDetailActionProvider(Context context) { - super(context); - } - - @Override - public View onCreateActionView() { - return null; - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - @Override - public View onCreateActionView(MenuItem forItem) { - return super.onCreateActionView(forItem); - } - - @Override - public boolean hasSubMenu() { - return true; - } - - @Override - public void onPrepareSubMenu(SubMenu subMenu) { - subMenu.add(1, Menu.NONE, Menu.NONE, "one"); - subMenu.add(1, Menu.NONE, Menu.NONE, "two"); - subMenu.add(1, Menu.NONE, Menu.NONE, "three"); - subMenu.add(1, Menu.NONE, Menu.NONE, "four"); - - subMenu.add(2, Menu.NONE, Menu.NONE, "no"); - subMenu.add(2, Menu.NONE, Menu.NONE, "short"); - subMenu.add(2, Menu.NONE, Menu.NONE, "long"); - - - } - - @Override - public boolean onPerformDefaultAction() { - return super.onPerformDefaultAction(); - } -} \ No newline at end of file diff --git a/src/de/blinkt/openvpn/LogWindow.java b/src/de/blinkt/openvpn/LogWindow.java deleted file mode 100644 index 3a15b00d..00000000 --- a/src/de/blinkt/openvpn/LogWindow.java +++ /dev/null @@ -1,30 +0,0 @@ -package de.blinkt.openvpn; - -import android.app.Activity; -import android.os.Bundle; -import android.view.MenuItem; -import de.blinkt.openvpn.fragments.LogFragment; - -/** - * Created by arne on 13.10.13. - */ -public class LogWindow extends Activity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.log_window); - getActionBar().setDisplayHomeAsUpEnabled(true); - - if (savedInstanceState == null) { - getFragmentManager().beginTransaction() - .add(R.id.container, new LogFragment()) - .commit(); - } - - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - return super.onOptionsItemSelected(item); - } -} diff --git a/src/de/blinkt/openvpn/MainActivity.java b/src/de/blinkt/openvpn/MainActivity.java deleted file mode 100644 index e1d417ca..00000000 --- a/src/de/blinkt/openvpn/MainActivity.java +++ /dev/null @@ -1,101 +0,0 @@ -package de.blinkt.openvpn; - -import android.app.ActionBar; -import android.app.ActionBar.Tab; -import android.app.Activity; -import android.app.Fragment; -import android.app.FragmentTransaction; -import android.content.Intent; -import de.blinkt.openvpn.fragments.*; - - -public class MainActivity extends Activity { - - protected void onCreate(android.os.Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - ActionBar bar = getActionBar(); - bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); - - Tab vpnListTab = bar.newTab().setText(R.string.vpn_list_title); - Tab generalTab = bar.newTab().setText(R.string.generalsettings); - Tab faqtab = bar.newTab().setText(R.string.faq); - Tab abouttab = bar.newTab().setText(R.string.about); - - vpnListTab.setTabListener(new TabListener("profiles", VPNProfileList.class)); - generalTab.setTabListener(new TabListener("settings", GeneralSettings.class)); - faqtab.setTabListener(new TabListener("faq", FaqFragment.class)); - abouttab.setTabListener(new TabListener("about", AboutFragment.class)); - - bar.addTab(vpnListTab); - bar.addTab(generalTab); - bar.addTab(faqtab); - bar.addTab(abouttab); - - if (false) { - Tab logtab = bar.newTab().setText("Log"); - logtab.setTabListener(new TabListener("log", LogFragment.class)); - bar.addTab(logtab); - } - - if(SendDumpFragment.getLastestDump(this)!=null) { - Tab sendDump = bar.newTab().setText(R.string.crashdump); - sendDump.setTabListener(new TabListener("crashdump",SendDumpFragment.class)); - bar.addTab(sendDump); - } - - } - - protected class TabListener implements ActionBar.TabListener - { - private Fragment mFragment; - private String mTag; - private Class mClass; - - public TabListener(String tag, Class clz) { - mTag = tag; - mClass = clz; - - // Check to see if we already have a fragment for this tab, probably - // from a previously saved state. If so, deactivate it, because our - // initial state is that a tab isn't shown. - mFragment = getFragmentManager().findFragmentByTag(mTag); - if (mFragment != null && !mFragment.isDetached()) { - FragmentTransaction ft = getFragmentManager().beginTransaction(); - ft.detach(mFragment); - ft.commit(); - } - } - - public void onTabSelected(Tab tab, FragmentTransaction ft) { - if (mFragment == null) { - mFragment = Fragment.instantiate(MainActivity.this, mClass.getName()); - ft.add(android.R.id.content, mFragment, mTag); - } else { - ft.attach(mFragment); - } - } - - public void onTabUnselected(Tab tab, FragmentTransaction ft) { - if (mFragment != null) { - ft.detach(mFragment); - } - } - - - @Override - public void onTabReselected(Tab tab, FragmentTransaction ft) { - - } - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - - System.out.println(data); - - - } - - -} diff --git a/src/de/blinkt/openvpn/RemoteCNPreference.java b/src/de/blinkt/openvpn/RemoteCNPreference.java deleted file mode 100644 index c7164c0c..00000000 --- a/src/de/blinkt/openvpn/RemoteCNPreference.java +++ /dev/null @@ -1,138 +0,0 @@ -package de.blinkt.openvpn; - -import android.content.Context; -import android.preference.DialogPreference; -import android.util.AttributeSet; -import android.util.Pair; -import android.view.View; -import android.widget.ArrayAdapter; -import android.widget.EditText; -import android.widget.Spinner; -import android.widget.TextView; - -public class RemoteCNPreference extends DialogPreference { - - - private Spinner mSpinner; - private EditText mEditText; - private int mDNType; - private String mDn; - private TextView mRemoteTLSNote; - //private ScrollView mScrollView; - - public RemoteCNPreference(Context context, AttributeSet attrs) { - super(context, attrs); - setDialogLayoutResource(R.layout.tlsremote); - - } - - @Override - protected void onBindDialogView(View view) { - - super.onBindDialogView(view); - - mEditText = (EditText) view.findViewById(R.id.tlsremotecn); - mSpinner = (Spinner) view.findViewById(R.id.x509verifytype); - mRemoteTLSNote = (TextView) view.findViewById(R.id.tlsremotenote); - //mScrollView = (ScrollView) view.findViewById(R.id.tlsremotescroll); - if(mDn!=null) - mEditText.setText(mDn); - - populateSpinner(); - - } - - - - public String getCNText() { - return mDn; - } - - public int getAuthtype() { - return mDNType; - } - - public void setDN(String dn) { - mDn = dn; - if(mEditText!=null) - mEditText.setText(dn); - } - - public void setAuthType(int x509authtype) { - mDNType = x509authtype; - if (mSpinner!=null) - populateSpinner(); - } - - @Override - protected void onDialogClosed(boolean positiveResult) { - super.onDialogClosed(positiveResult); - - if (positiveResult) { - String dn = mEditText.getText().toString(); - int authtype = getAuthTypeFromSpinner(); - if (callChangeListener(new Pair(authtype, dn))) { - mDn = dn; - mDNType = authtype; - } - } - } - - private void populateSpinner() { - ArrayAdapter authtypes = new ArrayAdapter(getContext(), android.R.layout.simple_spinner_item); - authtypes.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - - authtypes.add(getContext().getString(R.string.complete_dn)); - authtypes.add(getContext().getString(R.string.rdn)); - authtypes.add(getContext().getString(R.string.rdn_prefix)); - if ((mDNType == VpnProfile.X509_VERIFY_TLSREMOTE || mDNType == VpnProfile.X509_VERIFY_TLSREMOTE_COMPAT_NOREMAPPING) - && !(mDn==null || "".equals(mDn))) { - authtypes.add(getContext().getString(R.string.tls_remote_deprecated)); - mRemoteTLSNote.setVisibility(View.VISIBLE); - } else { - mRemoteTLSNote.setVisibility(View.GONE); - } - mSpinner.setAdapter(authtypes); - mSpinner.setSelection(getSpinnerPositionFromAuthTYPE()); - } - - private int getSpinnerPositionFromAuthTYPE() { - switch (mDNType) { - case VpnProfile.X509_VERIFY_TLSREMOTE_DN: - return 0; - case VpnProfile.X509_VERIFY_TLSREMOTE_RDN: - return 1; - case VpnProfile.X509_VERIFY_TLSREMOTE_RDN_PREFIX: - return 2; - case VpnProfile.X509_VERIFY_TLSREMOTE_COMPAT_NOREMAPPING: - case VpnProfile.X509_VERIFY_TLSREMOTE: - if (mDn==null || "".equals(mDn)) - return 1; - else - return 3; - - - default: - return 0; - } - } - - private int getAuthTypeFromSpinner() { - int pos = mSpinner.getSelectedItemPosition(); - switch (pos) { - case 0: - return VpnProfile.X509_VERIFY_TLSREMOTE_DN; - case 1: - return VpnProfile.X509_VERIFY_TLSREMOTE_RDN; - case 2: - return VpnProfile.X509_VERIFY_TLSREMOTE_RDN_PREFIX; - case 3: - // This is the tls-remote entry, only visible if mDntype is a - // tls-remote type - return mDNType; - default: - return VpnProfile.X509_VERIFY_TLSREMOTE; - } - } - -} diff --git a/src/de/blinkt/openvpn/activities/ConfigConverter.java b/src/de/blinkt/openvpn/activities/ConfigConverter.java new file mode 100644 index 00000000..4fa66449 --- /dev/null +++ b/src/de/blinkt/openvpn/activities/ConfigConverter.java @@ -0,0 +1,460 @@ + +package de.blinkt.openvpn.activities; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.HashSet; +import java.util.List; +import java.util.Vector; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.AlertDialog.Builder; +import android.app.ListActivity; +import android.content.ActivityNotFoundException; +import android.content.Intent; +import android.os.Bundle; +import android.os.Environment; +import android.security.KeyChain; +import android.security.KeyChainAliasCallback; +import android.text.TextUtils; +import android.util.Base64; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.CheckBox; + +import de.blinkt.openvpn.R; +import de.blinkt.openvpn.VpnProfile; +import de.blinkt.openvpn.core.ConfigParser; +import de.blinkt.openvpn.core.ConfigParser.ConfigParseError; +import de.blinkt.openvpn.core.ProfileManager; + +public class ConfigConverter extends ListActivity { + + public static final String IMPORT_PROFILE = "de.blinkt.openvpn.IMPORT_PROFILE"; + + private VpnProfile mResult; + private ArrayAdapter mArrayAdapter; + + private List mPathsegments; + + private String mAliasName=null; + + private int RESULT_INSTALLPKCS12 = 7; + + private String mPossibleName=null; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.config_converter); + } + + + + @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"); + return true; + } + + Intent in = installPKCS12(); + + if(in != null) + startActivityForResult(in, RESULT_INSTALLPKCS12); + else + saveProfile(); + + return true; + } + + return super.onOptionsItemSelected(item); + + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if(requestCode==RESULT_INSTALLPKCS12) { + if(resultCode==Activity.RESULT_OK) { + showCertDialog(); + } + } + + super.onActivityResult(requestCode, resultCode, data); + } + + private void saveProfile() { + Intent result = new Intent(); + ProfileManager vpl = ProfileManager.getInstance(this); + + setUniqueProfileName(vpl); + vpl.addProfile(mResult); + vpl.saveProfile(this, mResult); + vpl.saveProfileList(this); + result.putExtra(VpnProfile.EXTRA_PROFILEUUID,mResult.getUUID().toString()); + setResult(Activity.RESULT_OK, result); + finish(); + } + + public void showCertDialog () { + try { + KeyChain.choosePrivateKeyAlias(this, + new KeyChainAliasCallback() { + + public void alias(String alias) { + // Credential alias selected. Remember the alias selection for future use. + mResult.mAlias=alias; + saveProfile(); + } + + + }, + new String[] {"RSA"}, // List of acceptable key types. null for any + null, // issuer, null for any + mResult.mServerName, // host name of server requesting the cert, null if unavailable + -1, // port of server requesting the cert, -1 if unavailable + mAliasName); // alias to preselect, null if unavailable + } catch (ActivityNotFoundException anf) { + Builder ab = new AlertDialog.Builder(this); + ab.setTitle(R.string.broken_image_cert_title); + ab.setMessage(R.string.broken_image_cert); + ab.setPositiveButton(android.R.string.ok, null); + ab.show(); + } + } + + + private Intent installPKCS12() { + + if(!((CheckBox)findViewById(R.id.importpkcs12)).isChecked()) { + setAuthTypeToEmbeddedPKCS12(); + return null; + + } + String pkcs12datastr = mResult.mPKCS12Filename; + if(pkcs12datastr!=null && pkcs12datastr.startsWith(VpnProfile.INLINE_TAG)) { + Intent inkeyintent = KeyChain.createInstallIntent(); + + pkcs12datastr= pkcs12datastr.substring(VpnProfile.INLINE_TAG.length()); + + + byte[] pkcs12data = Base64.decode(pkcs12datastr, Base64.DEFAULT); + + + inkeyintent.putExtra(KeyChain.EXTRA_PKCS12,pkcs12data ); + + if(mAliasName.equals("")) + mAliasName=null; + + if(mAliasName!=null){ + inkeyintent.putExtra(KeyChain.EXTRA_NAME, mAliasName); + } + return inkeyintent; + + } + return null; + } + + + + private void setAuthTypeToEmbeddedPKCS12() { + if(mResult.mPKCS12Filename!=null && mResult.mPKCS12Filename.startsWith(VpnProfile.INLINE_TAG)) { + if(mResult.mAuthenticationType==VpnProfile.TYPE_USERPASS_KEYSTORE) + mResult.mAuthenticationType=VpnProfile.TYPE_USERPASS_PKCS12; + + if(mResult.mAuthenticationType==VpnProfile.TYPE_KEYSTORE) + mResult.mAuthenticationType=VpnProfile.TYPE_PKCS12; + + } + } + + + + + + private void setUniqueProfileName(ProfileManager vpl) { + int i=0; + + String newname = mPossibleName; + + // Default to + if(mResult.mName!=null && !ConfigParser.CONVERTED_PROFILE.equals(mResult.mName)) + newname=mResult.mName; + + while(newname==null || vpl.getProfileByName(newname)!=null) { + i++; + if(i==1) + newname = getString(R.string.converted_profile); + else + newname = getString(R.string.converted_profile_i,i); + } + + mResult.mName=newname; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.import_menu, menu); + return true; + } + + private String embedFile(String filename) { + return embedFile(filename, false); + } + + private String embedFile(String filename, boolean base64encode) + { + if(filename==null) + return null; + + // Already embedded, nothing to do + if(filename.startsWith(VpnProfile.INLINE_TAG)) + return filename; + + File possibleFile = findFile(filename); + if(possibleFile==null) + return filename; + else + return readFileContent(possibleFile,base64encode); + + } + + private File findFile(String filename) { + File foundfile =findFileRaw(filename); + + if (foundfile==null && filename!=null && !filename.equals("")) + log(R.string.import_could_not_open,filename); + + return foundfile; + } + + + + private File findFileRaw(String filename) + { + if(filename == null || filename.equals("")) + return null; + + // Try diffent path relative to /mnt/sdcard + File sdcard = Environment.getExternalStorageDirectory(); + File root = new File("/"); + + HashSet dirlist = new HashSet(); + + for(int i=mPathsegments.size()-1;i >=0 ;i--){ + String path = ""; + for (int j = 0;j<=i;j++) { + path += "/" + mPathsegments.get(j); + } + // Do a little hackish dance for the Android File Importer + // /document/primary:ovpn/openvpn-imt.conf + + if (path.indexOf(':')!=-1) { + String possibleDir = path.substring(path.indexOf(':')+1,path.length()); + possibleDir.substring(0,possibleDir.lastIndexOf('/')); + dirlist.add(new File(sdcard,possibleDir)); + + + } + dirlist.add(new File(path)); + } + dirlist.add(sdcard); + dirlist.add(root); + + + 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 + return possibleFile; + + } + } + return null; + } + + String readFileContent(File possibleFile, boolean base64encode) { + byte [] filedata; + try { + filedata = readBytesFromFile(possibleFile); + } catch (IOException e) { + log(e.getLocalizedMessage()); + return null; + } + + String data; + if(base64encode) { + data = Base64.encodeToString(filedata, Base64.DEFAULT); + } else { + data = new String(filedata); + + } + return VpnProfile.INLINE_TAG + data; + + } + + + private byte[] readBytesFromFile(File file) throws IOException { + InputStream input = new FileInputStream(file); + + long len= file.length(); + if (len > VpnProfile.MAX_EMBED_FILE_SIZE) + throw new IOException("File size of file to import too large."); + + // Create the byte array to hold the data + byte[] bytes = new byte[(int) len]; + + // Read in the bytes + int offset = 0; + int bytesRead = 0; + while (offset < bytes.length + && (bytesRead=input.read(bytes, offset, bytes.length-offset)) >= 0) { + offset += bytesRead; + } + + input.close(); + return bytes; + } + + void embedFiles() { + // This where I would like to have a c++ style + // void embedFile(std::string & option) + + if (mResult.mPKCS12Filename!=null) { + File pkcs12file = findFileRaw(mResult.mPKCS12Filename); + if(pkcs12file!=null) { + mAliasName = pkcs12file.getName().replace(".p12", ""); + } else { + mAliasName = "Imported PKCS12"; + } + } + + + mResult.mCaFilename = embedFile(mResult.mCaFilename); + mResult.mClientCertFilename = embedFile(mResult.mClientCertFilename); + mResult.mClientKeyFilename = embedFile(mResult.mClientKeyFilename); + mResult.mTLSAuthFilename = embedFile(mResult.mTLSAuthFilename); + mResult.mPKCS12Filename = embedFile(mResult.mPKCS12Filename,true); + + + if(mResult.mUsername == null && mResult.mPassword != null ){ + String data =embedFile(mResult.mPassword); + ConfigParser.useEmbbedUserAuth(mResult, data); + } + } + + + @Override + protected void onStart() { + super.onStart(); + + mArrayAdapter = new ArrayAdapter(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.import_experimental); + log(R.string.importing_config,data.toString()); + try { + if(data.getScheme().equals("file") || + data.getLastPathSegment().endsWith(".ovpn") || + data.getLastPathSegment().endsWith(".conf")) + { + mPossibleName = data.getLastPathSegment(); + if (mPossibleName.lastIndexOf('/')!=-1) + mPossibleName = mPossibleName.substring(mPossibleName.lastIndexOf('/')+1); + + if(mPossibleName!=null){ + mPossibleName =mPossibleName.replace(".ovpn", ""); + mPossibleName =mPossibleName.replace(".conf", ""); + } + } + InputStream is = getContentResolver().openInputStream(data); + mPathsegments = data.getPathSegments(); + + doImport(is); + } catch (FileNotFoundException e) { + log(R.string.import_content_resolve_error); + } + } + } + } + + private void log(String logmessage) { + mArrayAdapter.add(logmessage); + } + + private void doImport(InputStream is) { + ConfigParser cp = new ConfigParser(); + try { + InputStreamReader isr = new InputStreamReader(is); + + cp.parseConfig(isr); + 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); + String copt = mResult.mCustomConfigOptions; + if(copt.startsWith("#")) { + int until = copt.indexOf('\n'); + copt = copt.substring(until+1); + } + + log(copt); + } + + if(mResult.mAuthenticationType==VpnProfile.TYPE_KEYSTORE || + mResult.mAuthenticationType == VpnProfile.TYPE_USERPASS_KEYSTORE) { + findViewById(R.id.importpkcs12).setVisibility(View.VISIBLE); + } + + } + + private void log(int ressourceId, Object... formatArgs) { + log(getString(ressourceId,formatArgs)); + } +} diff --git a/src/de/blinkt/openvpn/activities/CreateShortcuts.java b/src/de/blinkt/openvpn/activities/CreateShortcuts.java new file mode 100644 index 00000000..53a829ff --- /dev/null +++ b/src/de/blinkt/openvpn/activities/CreateShortcuts.java @@ -0,0 +1,154 @@ +package de.blinkt.openvpn.activities; + +import android.app.ListActivity; +import android.content.Intent; +import android.os.Bundle; +import android.os.Parcelable; +import android.view.View; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ArrayAdapter; +import android.widget.ListView; +import android.widget.TextView; +import de.blinkt.openvpn.LaunchVPN; +import de.blinkt.openvpn.R; +import de.blinkt.openvpn.VpnProfile; +import de.blinkt.openvpn.core.ProfileManager; + +import java.util.Collection; +import java.util.Vector; + +/** + * This Activity actually handles two stages of a launcher shortcut's life cycle. + * + * 1. Your application offers to provide shortcuts to the launcher. When + * the user installs a shortcut, an activity within your application + * generates the actual shortcut and returns it to the launcher, where it + * is shown to the user as an icon. + * + * 2. Any time the user clicks on an installed shortcut, an intent is sent. + * Typically this would then be handled as necessary by an activity within + * your application. + * + * We handle stage 1 (creating a shortcut) by simply sending back the information (in the form + * of an {@link android.content.Intent} that the launcher will use to create the shortcut. + * + * You can also implement this in an interactive way, by having your activity actually present + * UI for the user to select the specific nature of the shortcut, such as a contact, picture, URL, + * media item, or action. + * + * We handle stage 2 (responding to a shortcut) in this sample by simply displaying the contents + * of the incoming {@link android.content.Intent}. + * + * In a real application, you would probably use the shortcut intent to display specific content + * or start a particular operation. + */ +public class CreateShortcuts extends ListActivity implements OnItemClickListener { + + + private static final int START_VPN_PROFILE= 70; + + + private ProfileManager mPM; + private VpnProfile mSelectedProfile; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + mPM =ProfileManager.getInstance(this); + + } + + @Override + protected void onStart() { + super.onStart(); + // Resolve the intent + + createListView(); + } + + private void createListView() { + ListView lv = getListView(); + //lv.setTextFilterEnabled(true); + + Collection vpnList = mPM.getProfiles(); + + Vector vpnNames=new Vector(); + for (VpnProfile vpnProfile : vpnList) { + vpnNames.add(vpnProfile.mName); + } + + + + ArrayAdapter adapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,vpnNames); + lv.setAdapter(adapter); + + lv.setOnItemClickListener(this); + } + + /** + * This function creates a shortcut and returns it to the caller. There are actually two + * intents that you will send back. + * + * The first intent serves as a container for the shortcut and is returned to the launcher by + * setResult(). This intent must contain three fields: + * + *
    + *
  • {@link android.content.Intent#EXTRA_SHORTCUT_INTENT} The shortcut intent.
  • + *
  • {@link android.content.Intent#EXTRA_SHORTCUT_NAME} The text that will be displayed with + * the shortcut.
  • + *
  • {@link android.content.Intent#EXTRA_SHORTCUT_ICON} The shortcut's icon, if provided as a + * bitmap, or {@link android.content.Intent#EXTRA_SHORTCUT_ICON_RESOURCE} if provided as + * a drawable resource.
  • + *
+ * + * If you use a simple drawable resource, note that you must wrapper it using + * {@link android.content.Intent.ShortcutIconResource}, as shown below. This is required so + * that the launcher can access resources that are stored in your application's .apk file. If + * you return a bitmap, such as a thumbnail, you can simply put the bitmap into the extras + * bundle using {@link android.content.Intent#EXTRA_SHORTCUT_ICON}. + * + * The shortcut intent can be any intent that you wish the launcher to send, when the user + * clicks on the shortcut. Typically this will be {@link android.content.Intent#ACTION_VIEW} + * with an appropriate Uri for your content, but any Intent will work here as long as it + * triggers the desired action within your Activity. + * @param profile + */ + private void setupShortcut(VpnProfile profile) { + // First, set up the shortcut intent. For this example, we simply create an intent that + // will bring us directly back to this activity. A more typical implementation would use a + // data Uri in order to display a more specific result, or a custom action in order to + // launch a specific operation. + + Intent shortcutIntent = new Intent(Intent.ACTION_MAIN); + shortcutIntent.setClass(this, LaunchVPN.class); + shortcutIntent.putExtra(LaunchVPN.EXTRA_KEY,profile.getUUID().toString()); + + // Then, set up the container intent (the response to the caller) + + Intent intent = new Intent(); + intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); + intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, profile.getName()); + Parcelable iconResource = Intent.ShortcutIconResource.fromContext( + this, R.drawable.icon); + intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource); + + // Now, return the result to the launcher + + setResult(RESULT_OK, intent); + } + + + @Override + public void onItemClick(AdapterView parent, View view, int position, + long id) { + String profileName = ((TextView) view).getText().toString(); + + VpnProfile profile = mPM.getProfileByName(profileName); + + setupShortcut(profile); + finish(); + } + +} diff --git a/src/de/blinkt/openvpn/activities/DisconnectVPN.java b/src/de/blinkt/openvpn/activities/DisconnectVPN.java new file mode 100644 index 00000000..c2d4c599 --- /dev/null +++ b/src/de/blinkt/openvpn/activities/DisconnectVPN.java @@ -0,0 +1,82 @@ +package de.blinkt.openvpn.activities; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.*; +import android.os.IBinder; + +import de.blinkt.openvpn.R; +import de.blinkt.openvpn.core.OpenVpnService; +import de.blinkt.openvpn.core.ProfileManager; + +/** + * Created by arne on 13.10.13. + */ +public class DisconnectVPN extends Activity implements DialogInterface.OnClickListener{ + protected OpenVpnService mService; + + private ServiceConnection mConnection = new ServiceConnection() { + + + @Override + public void onServiceConnected(ComponentName className, + IBinder service) { + // We've bound to LocalService, cast the IBinder and get LocalService instance + OpenVpnService.LocalBinder binder = (OpenVpnService.LocalBinder) service; + mService = binder.getService(); + } + + @Override + public void onServiceDisconnected(ComponentName arg0) { + mService =null; + } + + }; + + @Override + protected void onResume() { + super.onResume(); + Intent intent = new Intent(this, OpenVpnService.class); + intent.setAction(OpenVpnService.START_SERVICE); + bindService(intent, mConnection, Context.BIND_AUTO_CREATE); + showDisconnectDialog(); + } + + @Override + protected void onStop() { + super.onStop(); + unbindService(mConnection); + } + + // if (getIntent() !=null && OpenVpnService.DISCONNECT_VPN.equals(getIntent().getAction())) + + // setIntent(null); + + /* + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + setIntent(intent); + } + */ + + private void showDisconnectDialog() { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.title_cancel); + builder.setMessage(R.string.cancel_connection_query); + builder.setNegativeButton(android.R.string.no, this); + builder.setPositiveButton(android.R.string.yes,this); + + builder.show(); + } + + @Override + public void onClick(DialogInterface dialog, int which) { + if (which == DialogInterface.BUTTON_POSITIVE) { + ProfileManager.setConntectedVpnProfileDisconnected(this); + if (mService != null && mService.getManagement() != null) + mService.getManagement().stopVPN(); + } + finish(); + } +} diff --git a/src/de/blinkt/openvpn/activities/FileSelect.java b/src/de/blinkt/openvpn/activities/FileSelect.java new file mode 100644 index 00000000..405e0dbf --- /dev/null +++ b/src/de/blinkt/openvpn/activities/FileSelect.java @@ -0,0 +1,217 @@ +package de.blinkt.openvpn.activities; + + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; + +import android.app.ActionBar; +import android.app.ActionBar.Tab; +import android.app.Activity; +import android.app.AlertDialog; +import android.app.AlertDialog.Builder; +import android.app.Fragment; +import android.app.FragmentTransaction; +import android.content.Intent; +import android.os.Bundle; +import android.os.Environment; +import android.util.Base64; + +import de.blinkt.openvpn.R; +import de.blinkt.openvpn.VpnProfile; +import de.blinkt.openvpn.fragments.FileSelectionFragment; +import de.blinkt.openvpn.fragments.InlineFileTab; + +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 WINDOW_TITLE = "WINDOW_TILE"; + public static final String NO_INLINE_SELECTION = "de.blinkt.openvpn.NO_INLINE_SELECTION"; + public static final String SHOW_CLEAR_BUTTON = "de.blinkt.openvpn.SHOW_CLEAR_BUTTON"; + public static final String DO_BASE64_ENCODE = "de.blinkt.openvpn.BASE64ENCODE"; + + private FileSelectionFragment mFSFragment; + private InlineFileTab mInlineFragment; + private String mData; + private Tab inlineFileTab; + private Tab fileExplorerTab; + private boolean mNoInline; + private boolean mShowClear; + private boolean mBase64Encode; + + + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.file_dialog); + + mData = getIntent().getStringExtra(START_DATA); + if(mData==null) + mData=Environment.getExternalStorageDirectory().getPath(); + + String title = getIntent().getStringExtra(WINDOW_TITLE); + int titleId = getIntent().getIntExtra(WINDOW_TITLE, 0); + if(titleId!=0) + title =getString(titleId); + if(title!=null) + setTitle(title); + + mNoInline = getIntent().getBooleanExtra(NO_INLINE_SELECTION, false); + mShowClear = getIntent().getBooleanExtra(SHOW_CLEAR_BUTTON, false); + mBase64Encode = getIntent().getBooleanExtra(DO_BASE64_ENCODE, false); + + ActionBar bar = getActionBar(); + bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); + fileExplorerTab = bar.newTab().setText(R.string.file_explorer_tab); + inlineFileTab = bar.newTab().setText(R.string.inline_file_tab); + + mFSFragment = new FileSelectionFragment(); + fileExplorerTab.setTabListener(new MyTabsListener(this, mFSFragment)); + bar.addTab(fileExplorerTab); + + if(!mNoInline) { + mInlineFragment = new InlineFileTab(); + inlineFileTab.setTabListener(new MyTabsListener(this, mInlineFragment)); + bar.addTab(inlineFileTab); + } else { + mFSFragment.setNoInLine(); + } + + + } + + public boolean showClear() { + if(mData == null || mData.equals("")) + return false; + else + return mShowClear; + } + + protected class MyTabsListener implements ActionBar.TabListener + { + private Fragment mFragment; + private boolean mAdded=false; + + public MyTabsListener( Activity activity, Fragment fragment){ + this.mFragment = fragment; + } + + public void onTabSelected(Tab tab, FragmentTransaction ft) { + // Check if the fragment is already initialized + if (!mAdded) { + // If not, instantiate and add it to the activity + ft.add(android.R.id.content, mFragment); + mAdded =true; + } else { + // If it exists, simply attach it in order to show it + ft.attach(mFragment); + } + } + + @Override + public void onTabUnselected(Tab tab, FragmentTransaction ft) { + ft.detach(mFragment); + } + + @Override + public void onTabReselected(Tab tab, FragmentTransaction ft) { + + } + } + + public void importFile(String path) { + File ifile = new File(path); + Exception fe = null; + try { + + String data = ""; + + byte[] filedata = readBytesFromFile(ifile) ; + if(mBase64Encode) + data += Base64.encodeToString(filedata, Base64.DEFAULT); + else + data += new String(filedata); + + mData =data; + + /* + mInlineFragment.setData(data); + getActionBar().selectTab(inlineFileTab); */ + saveInlineData(data); + } catch (FileNotFoundException e) { + fe = e; + } catch (IOException e) { + fe =e; + } + if(fe!=null) { + Builder ab = new AlertDialog.Builder(this); + ab.setTitle(R.string.error_importing_file); + ab.setMessage(getString(R.string.import_error_message) + "\n" + fe.getLocalizedMessage()); + ab.setPositiveButton(android.R.string.ok, null); + ab.show(); + } + } + + private byte[] readBytesFromFile(File file) throws IOException { + InputStream input = new FileInputStream(file); + + long len= file.length(); + if (len > VpnProfile.MAX_EMBED_FILE_SIZE) + throw new IOException("selected file size too big to embed into profile"); + + // Create the byte array to hold the data + byte[] bytes = new byte[(int) len]; + + // Read in the bytes + int offset = 0; + int bytesRead = 0; + while (offset < bytes.length + && (bytesRead=input.read(bytes, offset, bytes.length-offset)) >= 0) { + offset += bytesRead; + } + + input.close(); + return bytes; + } + + + public void setFile(String path) { + Intent intent = new Intent(); + intent.putExtra(RESULT_DATA, path); + setResult(Activity.RESULT_OK,intent); + finish(); + } + + public String getSelectPath() { + if(!mData.startsWith(VpnProfile.INLINE_TAG)) + return mData; + else + return Environment.getExternalStorageDirectory().getPath(); + } + + public CharSequence getInlineData() { + if(mData.startsWith(VpnProfile.INLINE_TAG)) + return mData.substring(VpnProfile.INLINE_TAG.length()); + else + return ""; + } + + public void clearData() { + Intent intent = new Intent(); + intent.putExtra(RESULT_DATA, (String)null); + setResult(Activity.RESULT_OK,intent); + finish(); + + } + + public void saveInlineData(String string) { + Intent intent = new Intent(); + + intent.putExtra(RESULT_DATA,VpnProfile.INLINE_TAG + string); + setResult(Activity.RESULT_OK,intent); + finish(); + + } +} diff --git a/src/de/blinkt/openvpn/activities/LogWindow.java b/src/de/blinkt/openvpn/activities/LogWindow.java new file mode 100644 index 00000000..27197035 --- /dev/null +++ b/src/de/blinkt/openvpn/activities/LogWindow.java @@ -0,0 +1,32 @@ +package de.blinkt.openvpn.activities; + +import android.app.Activity; +import android.os.Bundle; +import android.view.MenuItem; + +import de.blinkt.openvpn.R; +import de.blinkt.openvpn.fragments.LogFragment; + +/** + * Created by arne on 13.10.13. + */ +public class LogWindow extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.log_window); + getActionBar().setDisplayHomeAsUpEnabled(true); + + if (savedInstanceState == null) { + getFragmentManager().beginTransaction() + .add(R.id.container, new LogFragment()) + .commit(); + } + + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + return super.onOptionsItemSelected(item); + } +} diff --git a/src/de/blinkt/openvpn/activities/MainActivity.java b/src/de/blinkt/openvpn/activities/MainActivity.java new file mode 100644 index 00000000..b32c80cc --- /dev/null +++ b/src/de/blinkt/openvpn/activities/MainActivity.java @@ -0,0 +1,103 @@ +package de.blinkt.openvpn.activities; + +import android.app.ActionBar; +import android.app.ActionBar.Tab; +import android.app.Activity; +import android.app.Fragment; +import android.app.FragmentTransaction; +import android.content.Intent; + +import de.blinkt.openvpn.R; +import de.blinkt.openvpn.fragments.*; + + +public class MainActivity extends Activity { + + protected void onCreate(android.os.Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ActionBar bar = getActionBar(); + bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); + + Tab vpnListTab = bar.newTab().setText(R.string.vpn_list_title); + Tab generalTab = bar.newTab().setText(R.string.generalsettings); + Tab faqtab = bar.newTab().setText(R.string.faq); + Tab abouttab = bar.newTab().setText(R.string.about); + + vpnListTab.setTabListener(new TabListener("profiles", VPNProfileList.class)); + generalTab.setTabListener(new TabListener("settings", GeneralSettings.class)); + faqtab.setTabListener(new TabListener("faq", FaqFragment.class)); + abouttab.setTabListener(new TabListener("about", AboutFragment.class)); + + bar.addTab(vpnListTab); + bar.addTab(generalTab); + bar.addTab(faqtab); + bar.addTab(abouttab); + + if (false) { + Tab logtab = bar.newTab().setText("Log"); + logtab.setTabListener(new TabListener("log", LogFragment.class)); + bar.addTab(logtab); + } + + if(SendDumpFragment.getLastestDump(this)!=null) { + Tab sendDump = bar.newTab().setText(R.string.crashdump); + sendDump.setTabListener(new TabListener("crashdump",SendDumpFragment.class)); + bar.addTab(sendDump); + } + + } + + protected class TabListener implements ActionBar.TabListener + { + private Fragment mFragment; + private String mTag; + private Class mClass; + + public TabListener(String tag, Class clz) { + mTag = tag; + mClass = clz; + + // Check to see if we already have a fragment for this tab, probably + // from a previously saved state. If so, deactivate it, because our + // initial state is that a tab isn't shown. + mFragment = getFragmentManager().findFragmentByTag(mTag); + if (mFragment != null && !mFragment.isDetached()) { + FragmentTransaction ft = getFragmentManager().beginTransaction(); + ft.detach(mFragment); + ft.commit(); + } + } + + public void onTabSelected(Tab tab, FragmentTransaction ft) { + if (mFragment == null) { + mFragment = Fragment.instantiate(MainActivity.this, mClass.getName()); + ft.add(android.R.id.content, mFragment, mTag); + } else { + ft.attach(mFragment); + } + } + + public void onTabUnselected(Tab tab, FragmentTransaction ft) { + if (mFragment != null) { + ft.detach(mFragment); + } + } + + + @Override + public void onTabReselected(Tab tab, FragmentTransaction ft) { + + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + System.out.println(data); + + + } + + +} diff --git a/src/de/blinkt/openvpn/app/CreateShortcuts.java b/src/de/blinkt/openvpn/app/CreateShortcuts.java deleted file mode 100644 index 69fa9a84..00000000 --- a/src/de/blinkt/openvpn/app/CreateShortcuts.java +++ /dev/null @@ -1,154 +0,0 @@ -package de.blinkt.openvpn.app; - -import android.app.ListActivity; -import android.content.Intent; -import android.os.Bundle; -import android.os.Parcelable; -import android.view.View; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.ArrayAdapter; -import android.widget.ListView; -import android.widget.TextView; -import de.blinkt.openvpn.LaunchVPN; -import de.blinkt.openvpn.R; -import de.blinkt.openvpn.VpnProfile; -import de.blinkt.openvpn.core.ProfileManager; - -import java.util.Collection; -import java.util.Vector; - -/** - * This Activity actually handles two stages of a launcher shortcut's life cycle. - * - * 1. Your application offers to provide shortcuts to the launcher. When - * the user installs a shortcut, an activity within your application - * generates the actual shortcut and returns it to the launcher, where it - * is shown to the user as an icon. - * - * 2. Any time the user clicks on an installed shortcut, an intent is sent. - * Typically this would then be handled as necessary by an activity within - * your application. - * - * We handle stage 1 (creating a shortcut) by simply sending back the information (in the form - * of an {@link android.content.Intent} that the launcher will use to create the shortcut. - * - * You can also implement this in an interactive way, by having your activity actually present - * UI for the user to select the specific nature of the shortcut, such as a contact, picture, URL, - * media item, or action. - * - * We handle stage 2 (responding to a shortcut) in this sample by simply displaying the contents - * of the incoming {@link android.content.Intent}. - * - * In a real application, you would probably use the shortcut intent to display specific content - * or start a particular operation. - */ -public class CreateShortcuts extends ListActivity implements OnItemClickListener { - - - private static final int START_VPN_PROFILE= 70; - - - private ProfileManager mPM; - private VpnProfile mSelectedProfile; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - mPM =ProfileManager.getInstance(this); - - } - - @Override - protected void onStart() { - super.onStart(); - // Resolve the intent - - createListView(); - } - - private void createListView() { - ListView lv = getListView(); - //lv.setTextFilterEnabled(true); - - Collection vpnList = mPM.getProfiles(); - - Vector vpnNames=new Vector(); - for (VpnProfile vpnProfile : vpnList) { - vpnNames.add(vpnProfile.mName); - } - - - - ArrayAdapter adapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,vpnNames); - lv.setAdapter(adapter); - - lv.setOnItemClickListener(this); - } - - /** - * This function creates a shortcut and returns it to the caller. There are actually two - * intents that you will send back. - * - * The first intent serves as a container for the shortcut and is returned to the launcher by - * setResult(). This intent must contain three fields: - * - *
    - *
  • {@link android.content.Intent#EXTRA_SHORTCUT_INTENT} The shortcut intent.
  • - *
  • {@link android.content.Intent#EXTRA_SHORTCUT_NAME} The text that will be displayed with - * the shortcut.
  • - *
  • {@link android.content.Intent#EXTRA_SHORTCUT_ICON} The shortcut's icon, if provided as a - * bitmap, or {@link android.content.Intent#EXTRA_SHORTCUT_ICON_RESOURCE} if provided as - * a drawable resource.
  • - *
- * - * If you use a simple drawable resource, note that you must wrapper it using - * {@link android.content.Intent.ShortcutIconResource}, as shown below. This is required so - * that the launcher can access resources that are stored in your application's .apk file. If - * you return a bitmap, such as a thumbnail, you can simply put the bitmap into the extras - * bundle using {@link android.content.Intent#EXTRA_SHORTCUT_ICON}. - * - * The shortcut intent can be any intent that you wish the launcher to send, when the user - * clicks on the shortcut. Typically this will be {@link android.content.Intent#ACTION_VIEW} - * with an appropriate Uri for your content, but any Intent will work here as long as it - * triggers the desired action within your Activity. - * @param profile - */ - private void setupShortcut(VpnProfile profile) { - // First, set up the shortcut intent. For this example, we simply create an intent that - // will bring us directly back to this activity. A more typical implementation would use a - // data Uri in order to display a more specific result, or a custom action in order to - // launch a specific operation. - - Intent shortcutIntent = new Intent(Intent.ACTION_MAIN); - shortcutIntent.setClass(this, LaunchVPN.class); - shortcutIntent.putExtra(LaunchVPN.EXTRA_KEY,profile.getUUID().toString()); - - // Then, set up the container intent (the response to the caller) - - Intent intent = new Intent(); - intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); - intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, profile.getName()); - Parcelable iconResource = Intent.ShortcutIconResource.fromContext( - this, R.drawable.icon); - intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource); - - // Now, return the result to the launcher - - setResult(RESULT_OK, intent); - } - - - @Override - public void onItemClick(AdapterView parent, View view, int position, - long id) { - String profileName = ((TextView) view).getText().toString(); - - VpnProfile profile = mPM.getProfileByName(profileName); - - setupShortcut(profile); - finish(); - } - -} diff --git a/src/de/blinkt/openvpn/core/OpenVpnService.java b/src/de/blinkt/openvpn/core/OpenVpnService.java index c0b24c3a..43bf702b 100644 --- a/src/de/blinkt/openvpn/core/OpenVpnService.java +++ b/src/de/blinkt/openvpn/core/OpenVpnService.java @@ -15,8 +15,8 @@ import android.os.*; import android.os.Handler.Callback; import android.preference.PreferenceManager; import android.text.TextUtils; -import de.blinkt.openvpn.DisconnectVPN; -import de.blinkt.openvpn.LogWindow; +import de.blinkt.openvpn.activities.DisconnectVPN; +import de.blinkt.openvpn.activities.LogWindow; import de.blinkt.openvpn.R; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.VpnStatus.ByteCountListener; @@ -25,7 +25,6 @@ import de.blinkt.openvpn.core.VpnStatus.StateListener; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.security.MessageDigest; import java.util.HashMap; import java.util.Locale; import java.util.Vector; diff --git a/src/de/blinkt/openvpn/fragments/FileSelectionFragment.java b/src/de/blinkt/openvpn/fragments/FileSelectionFragment.java index 03f6bb88..84e065a5 100644 --- a/src/de/blinkt/openvpn/fragments/FileSelectionFragment.java +++ b/src/de/blinkt/openvpn/fragments/FileSelectionFragment.java @@ -19,7 +19,7 @@ import android.widget.CheckBox; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.TextView; -import de.blinkt.openvpn.FileSelect; +import de.blinkt.openvpn.activities.FileSelect; import de.blinkt.openvpn.R; public class FileSelectionFragment extends ListFragment { diff --git a/src/de/blinkt/openvpn/fragments/InlineFileTab.java b/src/de/blinkt/openvpn/fragments/InlineFileTab.java index 6b19b75a..bd0b70b1 100644 --- a/src/de/blinkt/openvpn/fragments/InlineFileTab.java +++ b/src/de/blinkt/openvpn/fragments/InlineFileTab.java @@ -9,7 +9,7 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; -import de.blinkt.openvpn.FileSelect; +import de.blinkt.openvpn.activities.FileSelect; import de.blinkt.openvpn.R; public class InlineFileTab extends Fragment diff --git a/src/de/blinkt/openvpn/fragments/LogFragment.java b/src/de/blinkt/openvpn/fragments/LogFragment.java index 246d8f3d..9aaf15b7 100644 --- a/src/de/blinkt/openvpn/fragments/LogFragment.java +++ b/src/de/blinkt/openvpn/fragments/LogFragment.java @@ -19,6 +19,8 @@ import android.view.*; import android.widget.*; import android.widget.AdapterView.OnItemLongClickListener; import de.blinkt.openvpn.*; +import de.blinkt.openvpn.activities.DisconnectVPN; +import de.blinkt.openvpn.activities.MainActivity; import de.blinkt.openvpn.core.OpenVPNManagement; import de.blinkt.openvpn.core.VpnStatus; import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus; diff --git a/src/de/blinkt/openvpn/fragments/SeekBarTicks.java b/src/de/blinkt/openvpn/fragments/SeekBarTicks.java deleted file mode 100644 index ec68e7e4..00000000 --- a/src/de/blinkt/openvpn/fragments/SeekBarTicks.java +++ /dev/null @@ -1,69 +0,0 @@ -package de.blinkt.openvpn.fragments; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.util.TypedValue; -import android.view.ViewConfiguration; -import android.widget.SeekBar; - -public class SeekBarTicks extends SeekBar { - private Paint mTickPaint; - private float mTickHeight; - - private float tickHeightRatio = 0.6f; - - public SeekBarTicks(Context context, AttributeSet attrs) { - super (context, attrs); - - initTicks (context, attrs, android.R.attr.seekBarStyle); - } - - - public SeekBarTicks(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - initTicks (context, attrs, defStyle); - - /*mTickHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, - tickHeightDP, - ctx.getResources().getDisplayMetrics()); */ - } - - private void initTicks(Context context, AttributeSet attrs, int defStyle) { - TypedArray a = context.obtainStyledAttributes(attrs, - new int[] { android.R.attr.secondaryProgress }, defStyle, 0); - - - int tickColor = a.getColor(0, android.R.color.black); - mTickPaint = new Paint(); - mTickPaint.setColor( context.getResources().getColor(tickColor)); - a.recycle(); - } - - - @Override - protected synchronized void onDraw(Canvas canvas) { - drawTicks(canvas); - super.onDraw(canvas); - } - - private void drawTicks(Canvas canvas) { - - final int available = getWidth() - getPaddingLeft() - getPaddingRight(); - final int availableHeight = getHeight() - getPaddingBottom() - getPaddingTop(); - - int extrapadding = (int) ((availableHeight- (availableHeight * tickHeightRatio))/2); - - int tickSpacing = available / (getMax() ); - - for (int i = 1; i < getMax(); i++) { - final float x = getPaddingLeft() + i * tickSpacing; - - canvas.drawLine(x, getPaddingTop()+extrapadding, x, getHeight()-getPaddingBottom()-extrapadding, mTickPaint); - } - } -} diff --git a/src/de/blinkt/openvpn/fragments/Settings_Authentication.java b/src/de/blinkt/openvpn/fragments/Settings_Authentication.java index 9aed464d..5dfb73d9 100644 --- a/src/de/blinkt/openvpn/fragments/Settings_Authentication.java +++ b/src/de/blinkt/openvpn/fragments/Settings_Authentication.java @@ -3,7 +3,6 @@ package de.blinkt.openvpn.fragments; import android.app.Activity; import android.content.Intent; import android.os.Bundle; -import android.os.Environment; import android.preference.CheckBoxPreference; import android.preference.EditTextPreference; import android.preference.ListPreference; @@ -12,9 +11,9 @@ import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceClickListener; import android.preference.SwitchPreference; import android.util.Pair; -import de.blinkt.openvpn.FileSelect; +import de.blinkt.openvpn.activities.FileSelect; import de.blinkt.openvpn.R; -import de.blinkt.openvpn.RemoteCNPreference; +import de.blinkt.openvpn.views.RemoteCNPreference; import de.blinkt.openvpn.VpnProfile; diff --git a/src/de/blinkt/openvpn/fragments/Settings_Basic.java b/src/de/blinkt/openvpn/fragments/Settings_Basic.java index a559cda2..cd8730dd 100644 --- a/src/de/blinkt/openvpn/fragments/Settings_Basic.java +++ b/src/de/blinkt/openvpn/fragments/Settings_Basic.java @@ -1,6 +1,5 @@ package de.blinkt.openvpn.fragments; -import android.annotation.TargetApi; import android.app.Activity; import android.app.AlertDialog; import android.app.AlertDialog.Builder; @@ -25,15 +24,14 @@ import android.widget.EditText; import android.widget.Spinner; import android.widget.TextView; import android.widget.ToggleButton; -import de.blinkt.openvpn.FileSelect; -import de.blinkt.openvpn.FileSelectLayout; +import de.blinkt.openvpn.activities.FileSelect; +import de.blinkt.openvpn.views.FileSelectLayout; import de.blinkt.openvpn.R; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.R.id; import de.blinkt.openvpn.core.ProfileManager; import de.blinkt.openvpn.core.X509Utils; -import java.io.IOException; import java.security.cert.X509Certificate; public class Settings_Basic extends Fragment implements View.OnClickListener, OnItemSelectedListener, Callback { diff --git a/src/de/blinkt/openvpn/fragments/VPNProfileList.java b/src/de/blinkt/openvpn/fragments/VPNProfileList.java index 76b1b5d5..3c031595 100644 --- a/src/de/blinkt/openvpn/fragments/VPNProfileList.java +++ b/src/de/blinkt/openvpn/fragments/VPNProfileList.java @@ -11,7 +11,6 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.os.Parcelable; import android.text.Html; import android.text.Html.ImageGetter; import android.view.*; @@ -22,13 +21,13 @@ import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import de.blinkt.openvpn.*; +import de.blinkt.openvpn.activities.ConfigConverter; +import de.blinkt.openvpn.activities.FileSelect; import de.blinkt.openvpn.core.ProfileManager; import java.util.Collection; import java.util.Comparator; -import java.util.Set; import java.util.TreeSet; -import java.util.prefs.Preferences; public class VPNProfileList extends ListFragment { diff --git a/src/de/blinkt/openvpn/views/FileSelectLayout.java b/src/de/blinkt/openvpn/views/FileSelectLayout.java new file mode 100644 index 00000000..7ee96884 --- /dev/null +++ b/src/de/blinkt/openvpn/views/FileSelectLayout.java @@ -0,0 +1,105 @@ +package de.blinkt.openvpn.views; + +import de.blinkt.openvpn.R; +import de.blinkt.openvpn.VpnProfile; +import de.blinkt.openvpn.activities.FileSelect; +import de.blinkt.openvpn.core.X509Utils; +import android.app.Fragment; +import android.content.Context; +import android.content.Intent; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.TextView; + + +public class FileSelectLayout extends LinearLayout implements OnClickListener { + + private final boolean mIsCertificate; + private TextView mDataView; + private String mData; + private Fragment mFragment; + private int mTaskId; + private Button mSelectButton; + private boolean mBase64Encode; + private String mTitle; + private boolean mShowClear; + private TextView mDataDetails; + + public FileSelectLayout( Context context, AttributeSet attrset) { + super(context,attrset); + inflate(getContext(), R.layout.file_select, this); + + TypedArray ta = context.obtainStyledAttributes(attrset, R.styleable.FileSelectLayout); + + mTitle = ta.getString(R.styleable.FileSelectLayout_title); + mIsCertificate = ta.getBoolean(R.styleable.FileSelectLayout_certificate,true); + + TextView tview = (TextView) findViewById(R.id.file_title); + tview.setText(mTitle); + + mDataView = (TextView) findViewById(R.id.file_selected_item); + mDataDetails = (TextView) findViewById(R.id.file_selected_description); + mSelectButton = (Button) findViewById(R.id.file_select_button); + mSelectButton.setOnClickListener(this); + + ta.recycle(); + } + + public void setFragment(Fragment fragment, int i) + { + mTaskId = i; + mFragment = fragment; + } + + public void getCertificateFileDialog() { + Intent startFC = new Intent(getContext(),FileSelect.class); + startFC.putExtra(FileSelect.START_DATA, mData); + startFC.putExtra(FileSelect.WINDOW_TITLE,mTitle); + if(mBase64Encode) + startFC.putExtra(FileSelect.DO_BASE64_ENCODE, true); + if(mShowClear) + startFC.putExtra(FileSelect.SHOW_CLEAR_BUTTON, true); + mFragment.startActivityForResult(startFC,mTaskId); + } + + + public String getData() { + return mData; + } + + public void setData(String data, Context c) { + mData = data; + if(data==null) { + mDataView.setText(mFragment.getString(R.string.no_data)); + mDataDetails.setText(""); + }else { + if(mData.startsWith(VpnProfile.INLINE_TAG)) + mDataView.setText(R.string.inline_file_data); + else + mDataView.setText(data); + if(mIsCertificate) + mDataDetails.setText(X509Utils.getCertificateFriendlyName(c,data)); + } + + } + + @Override + public void onClick(View v) { + if(v == mSelectButton) { + getCertificateFileDialog(); + } + } + + public void setBase64Encode() { + mBase64Encode =true; + } + + public void setShowClear() { + mShowClear=true; + } + +} diff --git a/src/de/blinkt/openvpn/views/RemoteCNPreference.java b/src/de/blinkt/openvpn/views/RemoteCNPreference.java new file mode 100644 index 00000000..388f892b --- /dev/null +++ b/src/de/blinkt/openvpn/views/RemoteCNPreference.java @@ -0,0 +1,141 @@ +package de.blinkt.openvpn.views; + +import android.content.Context; +import android.preference.DialogPreference; +import android.util.AttributeSet; +import android.util.Pair; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.Spinner; +import android.widget.TextView; + +import de.blinkt.openvpn.R; +import de.blinkt.openvpn.VpnProfile; + +public class RemoteCNPreference extends DialogPreference { + + + private Spinner mSpinner; + private EditText mEditText; + private int mDNType; + private String mDn; + private TextView mRemoteTLSNote; + //private ScrollView mScrollView; + + public RemoteCNPreference(Context context, AttributeSet attrs) { + super(context, attrs); + setDialogLayoutResource(R.layout.tlsremote); + + } + + @Override + protected void onBindDialogView(View view) { + + super.onBindDialogView(view); + + mEditText = (EditText) view.findViewById(R.id.tlsremotecn); + mSpinner = (Spinner) view.findViewById(R.id.x509verifytype); + mRemoteTLSNote = (TextView) view.findViewById(R.id.tlsremotenote); + //mScrollView = (ScrollView) view.findViewById(R.id.tlsremotescroll); + if(mDn!=null) + mEditText.setText(mDn); + + populateSpinner(); + + } + + + + public String getCNText() { + return mDn; + } + + public int getAuthtype() { + return mDNType; + } + + public void setDN(String dn) { + mDn = dn; + if(mEditText!=null) + mEditText.setText(dn); + } + + public void setAuthType(int x509authtype) { + mDNType = x509authtype; + if (mSpinner!=null) + populateSpinner(); + } + + @Override + protected void onDialogClosed(boolean positiveResult) { + super.onDialogClosed(positiveResult); + + if (positiveResult) { + String dn = mEditText.getText().toString(); + int authtype = getAuthTypeFromSpinner(); + if (callChangeListener(new Pair(authtype, dn))) { + mDn = dn; + mDNType = authtype; + } + } + } + + private void populateSpinner() { + ArrayAdapter authtypes = new ArrayAdapter(getContext(), android.R.layout.simple_spinner_item); + authtypes.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + + authtypes.add(getContext().getString(R.string.complete_dn)); + authtypes.add(getContext().getString(R.string.rdn)); + authtypes.add(getContext().getString(R.string.rdn_prefix)); + if ((mDNType == VpnProfile.X509_VERIFY_TLSREMOTE || mDNType == VpnProfile.X509_VERIFY_TLSREMOTE_COMPAT_NOREMAPPING) + && !(mDn==null || "".equals(mDn))) { + authtypes.add(getContext().getString(R.string.tls_remote_deprecated)); + mRemoteTLSNote.setVisibility(View.VISIBLE); + } else { + mRemoteTLSNote.setVisibility(View.GONE); + } + mSpinner.setAdapter(authtypes); + mSpinner.setSelection(getSpinnerPositionFromAuthTYPE()); + } + + private int getSpinnerPositionFromAuthTYPE() { + switch (mDNType) { + case VpnProfile.X509_VERIFY_TLSREMOTE_DN: + return 0; + case VpnProfile.X509_VERIFY_TLSREMOTE_RDN: + return 1; + case VpnProfile.X509_VERIFY_TLSREMOTE_RDN_PREFIX: + return 2; + case VpnProfile.X509_VERIFY_TLSREMOTE_COMPAT_NOREMAPPING: + case VpnProfile.X509_VERIFY_TLSREMOTE: + if (mDn==null || "".equals(mDn)) + return 1; + else + return 3; + + + default: + return 0; + } + } + + private int getAuthTypeFromSpinner() { + int pos = mSpinner.getSelectedItemPosition(); + switch (pos) { + case 0: + return VpnProfile.X509_VERIFY_TLSREMOTE_DN; + case 1: + return VpnProfile.X509_VERIFY_TLSREMOTE_RDN; + case 2: + return VpnProfile.X509_VERIFY_TLSREMOTE_RDN_PREFIX; + case 3: + // This is the tls-remote entry, only visible if mDntype is a + // tls-remote type + return mDNType; + default: + return VpnProfile.X509_VERIFY_TLSREMOTE; + } + } + +} diff --git a/src/de/blinkt/openvpn/views/SeekBarTicks.java b/src/de/blinkt/openvpn/views/SeekBarTicks.java new file mode 100644 index 00000000..88e8e164 --- /dev/null +++ b/src/de/blinkt/openvpn/views/SeekBarTicks.java @@ -0,0 +1,69 @@ +package de.blinkt.openvpn.views; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.ViewConfiguration; +import android.widget.SeekBar; + +public class SeekBarTicks extends SeekBar { + private Paint mTickPaint; + private float mTickHeight; + + private float tickHeightRatio = 0.6f; + + public SeekBarTicks(Context context, AttributeSet attrs) { + super (context, attrs); + + initTicks (context, attrs, android.R.attr.seekBarStyle); + } + + + public SeekBarTicks(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + initTicks (context, attrs, defStyle); + + /*mTickHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, + tickHeightDP, + ctx.getResources().getDisplayMetrics()); */ + } + + private void initTicks(Context context, AttributeSet attrs, int defStyle) { + TypedArray a = context.obtainStyledAttributes(attrs, + new int[] { android.R.attr.secondaryProgress }, defStyle, 0); + + + int tickColor = a.getColor(0, android.R.color.black); + mTickPaint = new Paint(); + mTickPaint.setColor( context.getResources().getColor(tickColor)); + a.recycle(); + } + + + @Override + protected synchronized void onDraw(Canvas canvas) { + drawTicks(canvas); + super.onDraw(canvas); + } + + private void drawTicks(Canvas canvas) { + + final int available = getWidth() - getPaddingLeft() - getPaddingRight(); + final int availableHeight = getHeight() - getPaddingBottom() - getPaddingTop(); + + int extrapadding = (int) ((availableHeight- (availableHeight * tickHeightRatio))/2); + + int tickSpacing = available / (getMax() ); + + for (int i = 1; i < getMax(); i++) { + final float x = getPaddingLeft() + i * tickSpacing; + + canvas.drawLine(x, getPaddingTop()+extrapadding, x, getHeight()-getPaddingBottom()-extrapadding, mTickPaint); + } + } +} -- cgit v1.2.3