diff --git a/app/src/main/java/oppen/tva/io/GeminiDatasource.kt b/app/src/main/java/oppen/tva/io/GeminiDatasource.kt index ca17d5d..19c1341 100644 --- a/app/src/main/java/oppen/tva/io/GeminiDatasource.kt +++ b/app/src/main/java/oppen/tva/io/GeminiDatasource.kt @@ -3,6 +3,7 @@ package oppen.tva.io import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import java.io.* +import java.net.ConnectException import java.net.URI import java.security.SecureRandom import javax.net.ssl.* @@ -84,10 +85,20 @@ class GeminiDatasource: Datasource{ sslContext.init(null, DummyTrustManager.get(), SecureRandom()) val factory: SSLSocketFactory = sslContext.socketFactory - val socket: SSLSocket = factory.createSocket(uri.host, port) as SSLSocket - socket.enabledProtocols = arrayOf("TLSv1.2") - socket.startHandshake() + var socket: SSLSocket? = null + try { + socket = factory.createSocket(uri.host, port) as SSLSocket + socket.enabledProtocols = arrayOf("TLSv1.2") + socket.startHandshake() + }catch(ce: ConnectException){ + onUpdate(TvaState.ResponseError(GeminiResponse.Header(-1, ce.message ?: ce.toString()))) + return + }catch(she: SSLHandshakeException){ + onUpdate(TvaState.ResponseError(GeminiResponse.Header(-1, she.message ?: she.toString()))) + return + } + // OUT >>>>>>>>>>>>>>>>>>>>>>>>>> val outputStreamWriter = OutputStreamWriter(socket.outputStream) @@ -128,26 +139,26 @@ class GeminiDatasource: Datasource{ } } - private fun getGemtext(socket: SSLSocket, uri: URI, header: GeminiResponse.Header, onUpdate: (state: TvaState) -> Unit){ + private fun getGemtext(socket: SSLSocket?, uri: URI, header: GeminiResponse.Header, onUpdate: (state: TvaState) -> Unit){ val lines = mutableListOf() - socket.inputStream.reader().use { inputStreamReader -> + socket?.inputStream?.reader().use { inputStreamReader -> BufferedReader(inputStreamReader).use { reader -> lines.addAll(reader.readLines()) } } - socket.close() + socket?.close() val processed = GemtextHelper.findCodeBlocks(lines) RuntimeCache.put(uri, header, processed) onUpdate(TvaState.ResponseGemtext(uri, header, processed)) } - private fun getString(socket: SSLSocket, uri: URI, header: GeminiResponse.Header, onUpdate: (state: TvaState) -> Unit){ - val content = socket.inputStream.bufferedReader().use { reader -> reader.readText() } + private fun getString(socket: SSLSocket?, uri: URI, header: GeminiResponse.Header, onUpdate: (state: TvaState) -> Unit){ + val content = socket?.inputStream?.bufferedReader().use { reader -> reader?.readText() } - socket.close() + socket?.close() } } \ No newline at end of file diff --git a/app/src/main/java/oppen/tva/io/GeminiResponse.kt b/app/src/main/java/oppen/tva/io/GeminiResponse.kt index 769219b..a221fe5 100644 --- a/app/src/main/java/oppen/tva/io/GeminiResponse.kt +++ b/app/src/main/java/oppen/tva/io/GeminiResponse.kt @@ -11,22 +11,42 @@ object GeminiResponse { const val UNKNOWN = -1 fun parseHeader(header: String): Header{ - val segments = header.trim().split(" ") - val meta = if(segments.size > 1){ - segments[1] + var meta = "" + if(header.startsWith("2")){ + val segments = header.trim().split(" ") + meta = when { + segments.size > 1 -> segments[1] + else -> "text/gemini; charset=utf-8" + } }else{ - "text/gemini; charset=utf-8" + meta = when { + header.contains(" ") -> header.substring(meta.indexOf(" ") + 1) + else -> header + } } + return when { - segments.first().startsWith("1") -> Header(INPUT, meta) - segments.first().startsWith("2") -> Header(SUCCESS, meta) - segments.first().startsWith("3") -> Header(REDIRECT, meta) - segments.first().startsWith("4") -> Header(TEMPORARY_FAILURE, meta) - segments.first().startsWith("5") -> Header(PERMANENT_FAILURE, meta) - segments.first().startsWith("6") -> Header(CLIENT_CERTIFICATE_REQUIRED, meta) + header.startsWith("1") -> Header(INPUT, meta) + header.startsWith("2") -> Header(SUCCESS, meta) + header.startsWith("3") -> Header(REDIRECT, meta) + header.startsWith("4") -> Header(TEMPORARY_FAILURE, meta) + header.startsWith("5") -> Header(PERMANENT_FAILURE, meta) + header.startsWith("6") -> Header(CLIENT_CERTIFICATE_REQUIRED, meta) else -> Header(UNKNOWN, meta) } } + fun getCodeString(code: Int): String{ + return when(code){ + 1 -> "Input" + 2 -> "Success" + 3 -> "Redirect" + 4 -> "Temporary Failure" + 5 -> "Permanent Failure" + 6 -> "Client Certificate Required" + else -> "Unknown: $code" + } + } + class Header(val code: Int, val meta: String) } \ No newline at end of file diff --git a/app/src/main/java/oppen/tva/ui/TvaActivity.kt b/app/src/main/java/oppen/tva/ui/TvaActivity.kt index ca09748..a85eaac 100644 --- a/app/src/main/java/oppen/tva/ui/TvaActivity.kt +++ b/app/src/main/java/oppen/tva/ui/TvaActivity.kt @@ -8,12 +8,14 @@ import android.net.Uri import android.os.Bundle import android.view.inputmethod.EditorInfo import androidx.activity.viewModels +import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.databinding.DataBindingUtil import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.snackbar.Snackbar import oppen.tva.R import oppen.tva.databinding.ActivityTvaBinding +import oppen.tva.io.GeminiResponse import oppen.tva.io.TvaState import oppen.tva.io.history.CacheInterface import oppen.tva.ui.overflow.OverflowPopup @@ -56,7 +58,7 @@ class TvaActivity : AppCompatActivity() { is TvaState.AppQuery -> runOnUiThread{ showAlert("App backdoor/query not implemented yet") } is TvaState.Requesting -> loadingView(true) is TvaState.NotGeminiRequest -> externalProtocol(state) - is TvaState.ResponseError -> showAlert("${state.header.code}: ${state.header.meta}") + is TvaState.ResponseError -> showAlert("${GeminiResponse.getCodeString(state.header.code)}: ${state.header.meta}") is TvaState.ResponseGemtext -> renderGemtext(state) is TvaState.ResponseText -> runOnUiThread{ showAlert("Plain text display not implemented") } is TvaState.TabChange -> binding.tabCount.text = "${state.count}" @@ -124,7 +126,14 @@ class TvaActivity : AppCompatActivity() { private fun showAlert(message: String) = runOnUiThread{ loadingView(false) - Snackbar.make(binding.root, message, Snackbar.LENGTH_SHORT).show() + + if(message.length > 40){ + AlertDialog.Builder(this) + .setMessage(message) + .show() + }else { + Snackbar.make(binding.root, message, Snackbar.LENGTH_SHORT).show() + } } private fun externalProtocol(state: TvaState.NotGeminiRequest) = runOnUiThread {