From 9d8846e105904b31478ed19d3a34c0d62708abcf Mon Sep 17 00:00:00 2001 From: pacien Date: Tue, 7 Aug 2018 01:08:22 +0200 Subject: Revert "Rename source directory" This reverts commit dbba24e --- .../org/pacien/tincapp/activities/BaseActivity.kt | 114 ---------- .../pacien/tincapp/activities/ConfigureActivity.kt | 145 ------------- .../org/pacien/tincapp/activities/StartActivity.kt | 201 ------------------ .../pacien/tincapp/activities/StatusActivity.kt | 196 ----------------- .../pacien/tincapp/activities/ViewLogActivity.kt | 164 -------------- .../kotlin/org/pacien/tincapp/commands/Command.kt | 46 ---- .../kotlin/org/pacien/tincapp/commands/Executor.kt | 85 -------- .../kotlin/org/pacien/tincapp/commands/Tinc.kt | 72 ------- .../kotlin/org/pacien/tincapp/commands/TincApp.kt | 74 ------- .../kotlin/org/pacien/tincapp/commands/Tincd.kt | 37 ---- .../main/kotlin/org/pacien/tincapp/context/App.kt | 85 -------- .../kotlin/org/pacien/tincapp/context/AppInfo.kt | 47 ---- .../kotlin/org/pacien/tincapp/context/AppLogger.kt | 63 ------ .../tincapp/context/AppNotificationManager.kt | 84 -------- .../kotlin/org/pacien/tincapp/context/AppPaths.kt | 71 ------- .../org/pacien/tincapp/context/CrashRecorder.kt | 48 ----- .../kotlin/org/pacien/tincapp/data/CidrAddress.kt | 39 ---- .../org/pacien/tincapp/data/TincConfiguration.kt | 41 ---- .../tincapp/data/VpnInterfaceConfiguration.kt | 92 -------- .../org/pacien/tincapp/extensions/Android.kt | 41 ---- .../tincapp/extensions/ApacheConfiguration.kt | 33 --- .../kotlin/org/pacien/tincapp/extensions/Java.kt | 38 ---- .../pacien/tincapp/extensions/VpnServiceBuilder.kt | 80 ------- .../kotlin/org/pacien/tincapp/intent/Actions.kt | 39 ---- .../org/pacien/tincapp/intent/BroadcastMapper.kt | 38 ---- .../org/pacien/tincapp/service/TincVpnService.kt | 236 --------------------- .../kotlin/org/pacien/tincapp/utils/PemUtils.kt | 94 -------- .../org/pacien/tincapp/utils/ProgressModal.kt | 49 ----- .../kotlin/org/pacien/tincapp/utils/TincKeyring.kt | 44 ---- 29 files changed, 2396 deletions(-) delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/activities/BaseActivity.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/activities/ConfigureActivity.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/activities/StartActivity.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/activities/StatusActivity.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/activities/ViewLogActivity.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/commands/Command.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/commands/Executor.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/commands/Tinc.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/commands/TincApp.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/commands/Tincd.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/context/App.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/context/AppInfo.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/context/AppLogger.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/context/AppNotificationManager.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/context/AppPaths.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/context/CrashRecorder.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/data/CidrAddress.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/data/TincConfiguration.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/data/VpnInterfaceConfiguration.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/extensions/Android.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/extensions/ApacheConfiguration.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/extensions/Java.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/extensions/VpnServiceBuilder.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/intent/Actions.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/intent/BroadcastMapper.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/service/TincVpnService.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/utils/PemUtils.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/utils/ProgressModal.kt delete mode 100644 app/src/main/kotlin/org/pacien/tincapp/utils/TincKeyring.kt (limited to 'app/src/main/kotlin/org') diff --git a/app/src/main/kotlin/org/pacien/tincapp/activities/BaseActivity.kt b/app/src/main/kotlin/org/pacien/tincapp/activities/BaseActivity.kt deleted file mode 100644 index 4dc2381..0000000 --- a/app/src/main/kotlin/org/pacien/tincapp/activities/BaseActivity.kt +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon - * Copyright (C) 2017-2018 Pacien TRAN-GIRARD - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.pacien.tincapp.activities - -import android.os.Bundle -import android.support.annotation.StringRes -import android.support.design.widget.Snackbar -import android.support.v7.app.AlertDialog -import android.support.v7.app.AppCompatActivity -import android.view.Menu -import android.view.MenuItem -import kotlinx.android.synthetic.main.base.* -import org.pacien.tincapp.R -import org.pacien.tincapp.context.App -import org.pacien.tincapp.context.AppInfo -import org.pacien.tincapp.context.AppPaths -import org.pacien.tincapp.context.CrashRecorder -import org.pacien.tincapp.utils.ProgressModal - -/** - * @author pacien - */ -abstract class BaseActivity : AppCompatActivity() { - private var active = false - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.base) - } - - override fun onCreateOptionsMenu(m: Menu): Boolean { - menuInflater.inflate(R.menu.menu_base, m) - return true - } - - override fun onStart() { - super.onStart() - active = true - } - - override fun onResume() { - super.onResume() - active = true - } - - override fun onPause() { - active = false - super.onPause() - } - - override fun onStop() { - active = false - super.onStop() - } - - fun aboutDialog(@Suppress("UNUSED_PARAMETER") i: MenuItem) { - AlertDialog.Builder(this) - .setTitle(resources.getString(R.string.app_name)) - .setMessage(resources.getString(R.string.app_short_desc) + "\n\n" + - resources.getString(R.string.app_copyright) + " " + - resources.getString(R.string.app_license) + "\n\n" + - AppInfo.all()) - .setNeutralButton(R.string.action_open_project_website) { _, _ -> App.openURL(resources.getString(R.string.app_website_url)) } - .setPositiveButton(R.string.action_close) { _, _ -> Unit } - .show() - } - - fun runOnUiThread(action: () -> Unit) { - if (active) super.runOnUiThread(action) - } - - fun handleRecentCrash() { - if (!CrashRecorder.hasPreviouslyCrashed()) return - CrashRecorder.dismissPreviousCrash() - - AlertDialog.Builder(this) - .setTitle(R.string.title_app_crash) - .setMessage(listOf( - resources.getString(R.string.message_app_crash), - resources.getString(R.string.message_crash_logged, AppPaths.appLogFile().absolutePath) - ).joinToString("\n\n")) - .setNeutralButton(R.string.action_send_report) { _, _ -> - App.sendMail( - resources.getString(R.string.app_dev_email), - listOf(R.string.app_name, R.string.title_app_crash).joinToString(" / ", transform = resources::getString), - AppPaths.appLogFile().let { if (it.exists()) it.readText() else "" }) - } - .setPositiveButton(R.string.action_close) { _, _ -> Unit } - .show() - } - - protected fun notify(@StringRes msg: Int) = Snackbar.make(activity_base, msg, Snackbar.LENGTH_LONG).show() - protected fun notify(msg: String) = Snackbar.make(activity_base, msg, Snackbar.LENGTH_LONG).show() - protected fun showProgressDialog(@StringRes msg: Int): AlertDialog = ProgressModal.show(this, getString(msg)) - protected fun showErrorDialog(msg: String): AlertDialog = AlertDialog.Builder(this) - .setTitle(R.string.title_error).setMessage(msg) - .setPositiveButton(R.string.action_close) { _, _ -> Unit }.show() -} diff --git a/app/src/main/kotlin/org/pacien/tincapp/activities/ConfigureActivity.kt b/app/src/main/kotlin/org/pacien/tincapp/activities/ConfigureActivity.kt deleted file mode 100644 index 2aab304..0000000 --- a/app/src/main/kotlin/org/pacien/tincapp/activities/ConfigureActivity.kt +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon - * Copyright (C) 2017-2018 Pacien TRAN-GIRARD - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.pacien.tincapp.activities - -import android.content.Intent -import android.os.Bundle -import android.support.annotation.StringRes -import android.support.v7.app.AlertDialog -import android.view.View -import com.google.zxing.integration.android.IntentIntegrator -import com.google.zxing.integration.android.IntentResult -import java8.util.concurrent.CompletableFuture -import kotlinx.android.synthetic.main.base.* -import kotlinx.android.synthetic.main.dialog_encrypt_decrypt_keys.view.* -import kotlinx.android.synthetic.main.dialog_network_generate.view.* -import kotlinx.android.synthetic.main.dialog_network_join.view.* -import kotlinx.android.synthetic.main.page_configure.* -import org.pacien.tincapp.R -import org.pacien.tincapp.commands.Tinc -import org.pacien.tincapp.commands.TincApp -import org.pacien.tincapp.context.AppPaths -import org.pacien.tincapp.extensions.Java.exceptionallyAccept -import java.util.regex.Pattern - -/** - * @author pacien - */ -class ConfigureActivity : BaseActivity() { - companion object { - private val NETWORK_NAME_PATTERN = Pattern.compile("^[^\\x00/]*$") - } - - private var joinDialog: View? = null - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - - IntentIntegrator.parseActivityResult(requestCode, resultCode, data) - ?.let(IntentResult::getContents) - ?.let(String::trim) - ?.let { joinDialog?.invitation_url?.setText(it) } - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - supportActionBar!!.setDisplayHomeAsUpEnabled(true) - layoutInflater.inflate(R.layout.page_configure, main_content) - writeContent() - } - - fun scanCode(@Suppress("UNUSED_PARAMETER") v: View) { - IntentIntegrator(this).initiateScan() - } - - fun openGenerateConfDialog(@Suppress("UNUSED_PARAMETER") v: View) { - val genDialog = layoutInflater.inflate(R.layout.dialog_network_generate, main_content, false) - AlertDialog.Builder(this).setTitle(R.string.title_new_network).setView(genDialog) - .setPositiveButton(R.string.action_create) { _, _ -> - generateConf( - genDialog.new_net_name.text.toString(), - genDialog.new_node_name.text.toString(), - genDialog.new_passphrase.text.toString()) - }.setNegativeButton(R.string.action_cancel) { _, _ -> Unit }.show() - } - - fun openJoinNetworkDialog(@Suppress("UNUSED_PARAMETER") v: View) { - joinDialog = layoutInflater.inflate(R.layout.dialog_network_join, main_content, false) - AlertDialog.Builder(this).setTitle(R.string.title_join_network).setView(joinDialog) - .setPositiveButton(R.string.action_join) { _, _ -> - joinNetwork( - joinDialog!!.net_name.text.toString(), - joinDialog!!.invitation_url.text.toString(), - joinDialog!!.join_passphrase.text.toString()) - }.setNegativeButton(R.string.action_cancel) { _, _ -> Unit }.show() - } - - fun openEncryptDecryptPrivateKeyDialog(@Suppress("UNUSED_PARAMETER") v: View) { - val encryptDecryptDialog = layoutInflater.inflate(R.layout.dialog_encrypt_decrypt_keys, main_content, false) - AlertDialog.Builder(this).setTitle(R.string.title_private_keys_encryption).setView(encryptDecryptDialog) - .setPositiveButton(R.string.action_apply) { _, _ -> - encryptDecryptPrivateKeys( - encryptDecryptDialog!!.enc_dec_net_name.text.toString(), - encryptDecryptDialog.enc_dec_current_passphrase.text.toString(), - encryptDecryptDialog.enc_dec_new_passphrase.text.toString()) - }.setNegativeButton(R.string.action_cancel) { _, _ -> Unit }.show() - } - - private fun writeContent() { - text_configuration_directory.text = AppPaths.confDir().absolutePath - text_log_directory.text = AppPaths.cacheDir().absolutePath - text_tinc_binary.text = AppPaths.tinc().absolutePath - } - - private fun generateConf(netName: String, nodeName: String, passphrase: String? = null) = execAction( - R.string.message_generating_configuration, - validateNetName(netName) - .thenCompose { Tinc.init(netName, nodeName) } - .thenCompose { TincApp.removeScripts(netName) } - .thenCompose { TincApp.generateIfaceCfgTemplate(netName) } - .thenCompose { TincApp.setPassphrase(netName, newPassphrase = passphrase) }) - - private fun joinNetwork(netName: String, url: String, passphrase: String? = null) = execAction( - R.string.message_joining_network, - validateNetName(netName) - .thenCompose { Tinc.join(netName, url) } - .thenCompose { TincApp.removeScripts(netName) } - .thenCompose { TincApp.generateIfaceCfg(netName) } - .thenCompose { TincApp.setPassphrase(netName, newPassphrase = passphrase) }) - - private fun encryptDecryptPrivateKeys(netName: String, currentPassphrase: String, newPassphrase: String) = execAction( - R.string.message_encrypting_decrypting_private_keys, - validateNetName(netName) - .thenCompose { TincApp.setPassphrase(netName, currentPassphrase, newPassphrase) }) - - private fun execAction(@StringRes label: Int, action: CompletableFuture) { - showProgressDialog(label).let { progressDialog -> - action - .whenComplete { _, _ -> progressDialog.dismiss() } - .thenAccept { notify(R.string.message_network_configuration_written) } - .exceptionallyAccept { runOnUiThread { showErrorDialog(it.cause!!.localizedMessage) } } - } - } - - private fun validateNetName(netName: String): CompletableFuture = - if (NETWORK_NAME_PATTERN.matcher(netName).matches()) - CompletableFuture.completedFuture(Unit) - else - CompletableFuture.failedFuture(IllegalArgumentException(resources.getString(R.string.message_invalid_network_name))) -} diff --git a/app/src/main/kotlin/org/pacien/tincapp/activities/StartActivity.kt b/app/src/main/kotlin/org/pacien/tincapp/activities/StartActivity.kt deleted file mode 100644 index 50e002f..0000000 --- a/app/src/main/kotlin/org/pacien/tincapp/activities/StartActivity.kt +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon - * Copyright (C) 2017-2018 Pacien TRAN-GIRARD - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.pacien.tincapp.activities - -import android.app.Activity -import android.content.Intent -import android.net.VpnService -import android.os.Bundle -import android.support.v4.widget.SwipeRefreshLayout -import android.support.v7.app.AlertDialog -import android.view.Menu -import android.view.MenuItem -import android.view.View -import android.widget.AdapterView -import android.widget.ArrayAdapter -import android.widget.TextView -import kotlinx.android.synthetic.main.base.* -import kotlinx.android.synthetic.main.dialog_decrypt_keys.view.* -import kotlinx.android.synthetic.main.fragment_list_view.* -import kotlinx.android.synthetic.main.fragment_network_list_header.* -import org.pacien.tincapp.R -import org.pacien.tincapp.context.AppPaths -import org.pacien.tincapp.extensions.Android.setElements -import org.pacien.tincapp.intent.Actions -import org.pacien.tincapp.intent.BroadcastMapper -import org.pacien.tincapp.service.TincVpnService -import org.pacien.tincapp.utils.TincKeyring - -/** - * @author pacien - */ -class StartActivity : BaseActivity() { - companion object { - private const val PERMISSION_REQUEST = 0 - } - - private val networkList = object : AdapterView.OnItemClickListener, SwipeRefreshLayout.OnRefreshListener { - private var networkListAdapter: ArrayAdapter? = null - - fun init() { - networkListAdapter = ArrayAdapter(this@StartActivity, R.layout.fragment_list_item) - layoutInflater.inflate(R.layout.fragment_list_view, main_content) - list_wrapper.setOnRefreshListener(this) - list.addHeaderView(layoutInflater.inflate(R.layout.fragment_network_list_header, list, false), null, false) - list.addFooterView(View(this@StartActivity), null, false) - list.adapter = networkListAdapter - list.onItemClickListener = this - } - - fun destroy() { - networkListAdapter = null - } - - override fun onRefresh() { - val networks = AppPaths.confDir().list()?.sorted() ?: emptyList() - runOnUiThread { - networkListAdapter?.setElements(networks) - setPlaceholderVisibility() - list_wrapper.isRefreshing = false - } - } - - override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { - connectionStarter.tryStart(netName = (view as TextView).text.toString(), displayStatus = true) - } - - private fun setPlaceholderVisibility() = if (networkListAdapter?.isEmpty != false) { - network_list_placeholder.text = getListPlaceholderText() - network_list_placeholder.visibility = View.VISIBLE - } else { - network_list_placeholder.visibility = View.GONE - } - - private fun getListPlaceholderText() = if (!AppPaths.storageAvailable()) { - getText(R.string.message_storage_unavailable) - } else { - getText(R.string.message_no_network_configuration_found) - } - } - - private val connectionStarter = object { - private var netName: String? = null - private var passphrase: String? = null - private var displayStatus = false - - fun displayStatus() = displayStatus - - fun tryStart(netName: String? = null, passphrase: String? = null, displayStatus: Boolean? = null) { - if (netName != null) this.netName = netName - this.passphrase = passphrase - if (displayStatus != null) this.displayStatus = displayStatus - - val permissionRequestIntent = VpnService.prepare(this@StartActivity) - if (permissionRequestIntent != null) - return startActivityForResult(permissionRequestIntent, PERMISSION_REQUEST) - - if (TincKeyring.needsPassphrase(this.netName!!) && this.passphrase == null) - return askForPassphrase() - - startVpn(this.netName!!, this.passphrase) - } - - private fun askForPassphrase() { - layoutInflater.inflate(R.layout.dialog_decrypt_keys, main_content, false).let { dialog -> - AlertDialog.Builder(this@StartActivity) - .setTitle(R.string.title_unlock_private_keys).setView(dialog) - .setPositiveButton(R.string.action_unlock) { _, _ -> tryStart(passphrase = dialog.passphrase.text.toString()) } - .setNegativeButton(R.string.action_cancel) { _, _ -> Unit } - .show() - } - } - - private fun startVpn(netName: String, passphrase: String? = null) { - connectDialog = showProgressDialog(R.string.message_starting_vpn) - TincVpnService.connect(netName, passphrase) - } - } - - private val broadcastMapper = BroadcastMapper(mapOf( - Actions.EVENT_CONNECTED to this::onVpnStart, - Actions.EVENT_ABORTED to this::onVpnStartError)) - - private var connectDialog: AlertDialog? = null - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - networkList.init() - - if (intent.action == Actions.ACTION_CONNECT && intent.data?.schemeSpecificPart != null) - connectionStarter.tryStart(intent.data.schemeSpecificPart, intent.data.fragment, false) - } - - override fun onCreateOptionsMenu(m: Menu): Boolean { - menuInflater.inflate(R.menu.menu_start, m) - return super.onCreateOptionsMenu(m) - } - - override fun onDestroy() { - networkList.destroy() - connectDialog?.dismiss() - super.onDestroy() - } - - override fun onStart() { - super.onStart() - networkList.onRefresh() - } - - override fun onResume() { - super.onResume() - if (TincVpnService.isConnected()) openStatusActivity(false) - broadcastMapper.register() - handleRecentCrash() - } - - override fun onPause() { - broadcastMapper.unregister() - super.onPause() - } - - override fun onActivityResult(request: Int, result: Int, data: Intent?): Unit = when (request) { - PERMISSION_REQUEST -> if (result == Activity.RESULT_OK) connectionStarter.tryStart() else Unit - else -> throw IllegalArgumentException("Result for unknown request received.") - } - - fun openConfigureActivity(@Suppress("UNUSED_PARAMETER") i: MenuItem) = - startActivity(Intent(this, ConfigureActivity::class.java)) - - private fun onVpnStart() { - connectDialog?.dismiss() - if (connectionStarter.displayStatus()) openStatusActivity() - finish() - } - - private fun onVpnStartError() { - connectDialog?.dismiss() - } - - private fun openStatusActivity(transition: Boolean = true) = - startActivity( - Intent(this, StatusActivity::class.java) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) - .apply { if (!transition) addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION) }) -} diff --git a/app/src/main/kotlin/org/pacien/tincapp/activities/StatusActivity.kt b/app/src/main/kotlin/org/pacien/tincapp/activities/StatusActivity.kt deleted file mode 100644 index 68e008e..0000000 --- a/app/src/main/kotlin/org/pacien/tincapp/activities/StatusActivity.kt +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon - * Copyright (C) 2017-2018 Pacien TRAN-GIRARD - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.pacien.tincapp.activities - -import android.content.Intent -import android.os.Bundle -import android.support.v4.widget.SwipeRefreshLayout -import android.support.v7.app.AlertDialog -import android.view.Menu -import android.view.MenuItem -import android.view.View -import android.widget.AdapterView -import android.widget.ArrayAdapter -import android.widget.TextView -import java8.util.concurrent.CompletableFuture -import kotlinx.android.synthetic.main.base.* -import kotlinx.android.synthetic.main.dialog_node_details.view.* -import kotlinx.android.synthetic.main.fragment_list_view.* -import kotlinx.android.synthetic.main.fragment_network_status_header.* -import org.pacien.tincapp.R -import org.pacien.tincapp.commands.Executor -import org.pacien.tincapp.commands.Tinc -import org.pacien.tincapp.data.VpnInterfaceConfiguration -import org.pacien.tincapp.extensions.Android.setElements -import org.pacien.tincapp.extensions.Android.setText -import org.pacien.tincapp.intent.Actions -import org.pacien.tincapp.intent.BroadcastMapper -import org.pacien.tincapp.service.TincVpnService -import java.util.* -import kotlin.concurrent.timerTask - -/** - * @author pacien - */ -class StatusActivity : BaseActivity(), AdapterView.OnItemClickListener, SwipeRefreshLayout.OnRefreshListener { - private val broadcastMapper = BroadcastMapper(mapOf(Actions.EVENT_DISCONNECTED to this::onVpnShutdown)) - private var shutdownDialog: AlertDialog? = null - private var nodeListAdapter: ArrayAdapter? = null - private var refreshTimer: Timer? = null - private var listNetworksAfterExit = true - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - nodeListAdapter = ArrayAdapter(this, R.layout.fragment_list_item) - - layoutInflater.inflate(R.layout.fragment_list_view, main_content) - list_wrapper.setOnRefreshListener(this) - list.addHeaderView(layoutInflater.inflate(R.layout.fragment_network_status_header, list, false), null, false) - list.addFooterView(View(this), null, false) - list.onItemClickListener = this - list.adapter = nodeListAdapter - - if (intent.action == Actions.ACTION_DISCONNECT) { - listNetworksAfterExit = false - stopVpn() - } else { - listNetworksAfterExit = true - } - } - - override fun onCreateOptionsMenu(m: Menu): Boolean { - menuInflater.inflate(R.menu.menu_status, m) - return super.onCreateOptionsMenu(m) - } - - override fun onDestroy() { - super.onDestroy() - nodeListAdapter = null - refreshTimer = null - } - - override fun onStart() { - super.onStart() - refreshTimer = Timer(true) - refreshTimer?.schedule(timerTask { updateView() }, NOW, REFRESH_RATE) - writeNetworkInfo(TincVpnService.getCurrentInterfaceCfg() ?: VpnInterfaceConfiguration()) - } - - override fun onStop() { - refreshTimer?.cancel() - super.onStop() - } - - override fun onResume() { - super.onResume() - broadcastMapper.register() - updateView() - handleRecentCrash() - } - - override fun onPause() { - broadcastMapper.unregister() - super.onPause() - } - - override fun onRefresh() { - refreshTimer?.schedule(timerTask { updateView() }, NOW) - } - - override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) = when (view) { - is TextView -> showNodeInfo(view.text.toString()) - else -> Unit - } - - private fun onVpnShutdown() { - shutdownDialog?.dismiss() - if (listNetworksAfterExit) openStartActivity() - finish() - } - - fun stopVpn(@Suppress("UNUSED_PARAMETER") i: MenuItem? = null) { - refreshTimer?.cancel() - list_wrapper.isRefreshing = false - shutdownDialog = showProgressDialog(R.string.message_disconnecting_vpn) - TincVpnService.disconnect() - } - - fun openLogViewer(@Suppress("UNUSED_PARAMETER") i: MenuItem) = - startActivity(Intent(this, ViewLogActivity::class.java)) - - private fun writeNetworkInfo(cfg: VpnInterfaceConfiguration) { - text_network_name.text = TincVpnService.getCurrentNetName() ?: getString(R.string.value_none) - text_network_ip_addresses.setText(cfg.addresses.map { it.toSlashSeparated() }) - text_network_routes.setText(cfg.routes.map { it.toSlashSeparated() }) - text_network_dns_servers.setText(cfg.dnsServers) - text_network_search_domains.setText(cfg.searchDomains) - text_network_allow_bypass.text = getString(if (cfg.allowBypass) R.string.value_yes else R.string.value_no) - block_network_allowed_applications.visibility = if (cfg.allowedApplications.isNotEmpty()) View.VISIBLE else View.GONE - text_network_allowed_applications.setText(cfg.allowedApplications) - block_network_disallowed_applications.visibility = if (cfg.disallowedApplications.isNotEmpty()) View.VISIBLE else View.GONE - text_network_disallowed_applications.setText(cfg.disallowedApplications) - } - - private fun writeNodeList(nodeList: List) { - nodeListAdapter?.setElements(nodeList) - node_list_placeholder.visibility = View.GONE - list_wrapper.isRefreshing = false - } - - private fun updateNodeList() { - getNodeNames().thenAccept { nodeList -> runOnUiThread { writeNodeList(nodeList) } } - } - - private fun showNodeInfo(nodeName: String) { - val dialogTextView = layoutInflater.inflate(R.layout.dialog_node_details, main_content, false) - - runOnUiThread { - AlertDialog.Builder(this) - .setTitle(R.string.title_node_info) - .setView(dialogTextView) - .setPositiveButton(R.string.action_close) { _, _ -> Unit } - .show() - } - - TincVpnService.getCurrentNetName()?.let { netName -> - Tinc.info(netName, nodeName).thenAccept { nodeInfo -> - runOnUiThread { dialogTextView.dialog_node_details.text = nodeInfo } - } - } - } - - private fun updateView() = when { - TincVpnService.isConnected() -> updateNodeList() - else -> openStartActivity() - } - - private fun openStartActivity() { - startActivity(Intent(this, StartActivity::class.java).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)) - finish() - } - - companion object { - private const val REFRESH_RATE = 5000L - private const val NOW = 0L - - fun getNodeNames(): CompletableFuture> = TincVpnService.getCurrentNetName()?.let { netName -> - Tinc.dumpNodes(netName).thenApply> { list -> list.map { it.substringBefore(' ') } } - } ?: Executor.supplyAsyncTask> { emptyList() } - } -} diff --git a/app/src/main/kotlin/org/pacien/tincapp/activities/ViewLogActivity.kt b/app/src/main/kotlin/org/pacien/tincapp/activities/ViewLogActivity.kt deleted file mode 100644 index f3f7e24..0000000 --- a/app/src/main/kotlin/org/pacien/tincapp/activities/ViewLogActivity.kt +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon - * Copyright (C) 2017-2018 Pacien TRAN-GIRARD - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.pacien.tincapp.activities - -import android.content.Intent -import android.os.Bundle -import android.view.Menu -import android.view.MenuItem -import android.view.View -import android.widget.ScrollView -import kotlinx.android.synthetic.main.base.* -import kotlinx.android.synthetic.main.page_viewlog.* -import org.pacien.tincapp.R -import org.pacien.tincapp.commands.Executor -import org.pacien.tincapp.commands.Tinc -import org.pacien.tincapp.service.TincVpnService -import java.util.* -import kotlin.concurrent.timer - -/** - * @author pacien - */ -class ViewLogActivity : BaseActivity() { - companion object { - private const val LOG_LINES = 250 - private const val LOG_LEVEL = 5 - private const val NEW_LINE = "\n" - private const val SPACED_NEW_LINE = "\n\n" - private const val UPDATE_INTERVAL = 250L // ms - private const val MIME_TYPE = "text/plain" - } - - private val log = LinkedList() - private var logUpdateTimer: Timer? = null - private var logger: Process? = null - private var toggleButton: MenuItem? = null - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - supportActionBar!!.setDisplayHomeAsUpEnabled(true) - layoutInflater.inflate(R.layout.page_viewlog, main_content) - toggleLogging(true) - } - - override fun onCreateOptionsMenu(m: Menu): Boolean { - menuInflater.inflate(R.menu.menu_viewlog, m) - toggleButton = m.findItem(R.id.log_viewer_action_toggle) - return super.onCreateOptionsMenu(m) - } - - override fun onSupportNavigateUp(): Boolean { - finish() - return true - } - - override fun onDestroy() { - toggleLogging(false) - super.onDestroy() - } - - fun share(@Suppress("UNUSED_PARAMETER") menuItem: MenuItem) { - synchronized(this) { - val logFragment = log.joinToString(NEW_LINE) - val shareIntent = Intent(Intent.ACTION_SEND) - .setType(MIME_TYPE) - .putExtra(Intent.EXTRA_TEXT, logFragment) - - startActivity(Intent.createChooser(shareIntent, resources.getString(R.string.menu_share_log))) - } - } - - fun toggleLogging(@Suppress("UNUSED_PARAMETER") menuItem: MenuItem) = toggleLogging(logger == null) - - private fun toggleLogging(enable: Boolean) { - if (enable) { - disableUserScroll() - toggleButton?.setIcon(R.drawable.ic_pause_circle_outline_primary_24dp) - startLogging() - } else { - enableUserScroll() - toggleButton?.setIcon(R.drawable.ic_pause_circle_filled_primary_24dp) - stopLogging() - } - } - - private fun startLogging(level: Int = LOG_LEVEL) { - appendLog(resources.getString(R.string.message_log_level_set, level)) - - TincVpnService.getCurrentNetName()?.let { netName -> - Tinc.log(netName, level).let { process -> - logger = process - Executor.runAsyncTask { captureLog(process) } - } - logUpdateTimer = timer(period = UPDATE_INTERVAL, action = { printLog() }) - } ?: run { - appendLog(resources.getString(R.string.message_no_daemon)) - toggleLogging(false) - } - } - - private fun stopLogging() { - logger?.destroy() - logger = null - logUpdateTimer?.cancel() - logUpdateTimer?.purge() - logUpdateTimer = null - appendLog(resources.getString(R.string.message_log_paused)) - printLog() - } - - private fun captureLog(logger: Process) { - logger.inputStream?.use { inputStream -> - inputStream.bufferedReader().useLines { lines -> - lines.forEach { appendLog(it) } - } - } - } - - private fun appendLog(line: String) = synchronized(this) { - if (log.size >= LOG_LINES) log.removeFirst() - log.addLast(line) - } - - private fun printLog() = synchronized(this) { - log.joinToString(SPACED_NEW_LINE).let { - logview_text.post { - logview_text.text = it - logview_frame.post { logview_frame.fullScroll(View.FOCUS_DOWN) } - } - } - } - - private fun enableUserScroll() { - logview_text.setTextIsSelectable(true) - logview_frame.setState(true) - } - - private fun disableUserScroll() { - logview_text.setTextIsSelectable(false) - logview_frame.setState(false) - } - - private fun ScrollView.setState(enabled: Boolean) { - if (enabled) setOnTouchListener(null) else setOnTouchListener { _, _ -> true } - logview_frame.isSmoothScrollingEnabled = enabled - logview_frame.isVerticalScrollBarEnabled = enabled - } -} diff --git a/app/src/main/kotlin/org/pacien/tincapp/commands/Command.kt b/app/src/main/kotlin/org/pacien/tincapp/commands/Command.kt deleted file mode 100644 index 132cda9..0000000 --- a/app/src/main/kotlin/org/pacien/tincapp/commands/Command.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon - * Copyright (C) 2017-2018 Pacien TRAN-GIRARD - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.pacien.tincapp.commands - -import java.util.* - -/** - * @author pacien - */ -internal class Command(private val cmd: String) { - private data class Option(val key: String, val value: String?) { - fun toCommandLineOption(): String = if (value != null) "--$key=$value" else "--$key" - } - - private val opts: MutableList