package info.kghost.android.openvpn;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.Arrays;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
class OpenvpnInstaller {
public interface Callback {
public void done(Result result);
}
public class Result {
private boolean installed;
private String text;
public Result(boolean installed, String text) {
setInstalled(installed);
setText(text);
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public boolean isInstalled() {
return installed;
}
public void setInstalled(boolean installed) {
this.installed = installed;
}
}
private class InstallTask extends AsyncTask<Object, String, Result> {
private final Context c;
private final File path;
private final Callback cb;
private ProgressDialog dialog;
public InstallTask(Context context, Callback callback) {
c = context;
cb = callback;
path = new File(c.getCacheDir(), "openvpn");
}
private Result tryInstall() {
publishProgress(c.getString(R.string.openvpn_installer_installing));
try {
InputStream in = c.getAssets().open("openvpn");
FileOutputStream out = new FileOutputStream(path);
IOUtils.copy(in, out);
out.close();
in.close();
if (!path.setExecutable(true, true)) {
throw new IOException("Can't set executable flag");
}
return check(false);
} catch (IOException e) {
return new Result(false, e.getLocalizedMessage());
}
}
private Result check(boolean tryInstall) {
try {
byte[] embeded = DigestUtils.md5(c.getAssets().open("openvpn"));
byte[] installed;
try {
installed = DigestUtils.md5(new FileInputStream(path));
} catch (FileNotFoundException e) {
if (tryInstall)
return tryInstall();
else
throw e;
}
if (!Arrays.equals(embeded, installed)) {
if (tryInstall)
return tryInstall();
else
throw new RuntimeException(
"OpenVpn binary not installed");
}
if (!path.setExecutable(true, true)) {
throw new IOException("Can't set executable flag");
}
Process process;
try {
process = new ProcessBuilder()
.command(path.getAbsolutePath(), "--version")
.redirectErrorStream(true).start();
} catch (IOException e) {
if (tryInstall
&& e.getCause().getMessage()
.equals("No such file or directory")) {
return tryInstall();
} else {
throw e;
}
}
StringWriter writer = new StringWriter();
IOUtils.copy(process.getInputStream(), writer, "UTF-8");
String output = writer.toString();
process.waitFor();
return new Result(process.exitValue() == 1, output);
} catch (InterruptedException e) {
return new Result(false, e.getLocalizedMessage());
} catch (IOException e) {
return new Result(false, e.getLocalizedMessage());
}
}
@Override
protected Result doInBackground(Object... params) {
return check(true);
}
@Override
protected void onPreExecute() {
super.onPreExecute();
dialog = ProgressDialog.show(c,
c.getString(R.string.openvpn_installer_title),
c.getString(R.string.openvpn_installer_checking), true);
}
@Override
protected void onPostExecute(Result result) {
super.onPostExecute(result);
if (dialog.isShowing())
dialog.dismiss();
cb.done(result);
}
@Override
protected void onProgressUpdate(String... values) {
dialog.setMessage(values[0]);
super.onProgressUpdate(values);
}
@Override
protected void onCancelled() {
if (dialog.isShowing())
dialog.dismiss();
super.onCancelled();
}
}
private InstallTask task;
public void install(Context context, Callback callback) {
task = new InstallTask(context, callback);
task.execute(null, null);
}
public void cancel() {
task.cancel(true);
task = null;
}
}