static void HandleNimigemActivate(Uri uri) { var preformattedLines = new List <GeminiLine>(); var exitedPreformatted = false; var enteredPreformat = false; var foundNimigemEdit = false; var currentLine = _lineView.SelectedItem; var activatedLine = (GeminiLine)_lineView.Source.ToList()[currentLine]; //check if it is hinted as a null payload link if (activatedLine.Line.StartsWith('\u2205'.ToString())) { //send null payload try { SubmitNimigem(uri, Encoding.UTF8.GetBytes(""), "text/plain"); } catch (Exception e) { Dialogs.MsgBoxOK("Nimigem error", "Nimigem error: " + e.Message); } return; } //search back in the page for the linked text area //gather the previous nimigem lines and let the user edit the text while (currentLine >= 0) { var gemLine = (GeminiLine)_lineView.Source.ToList()[currentLine]; if (gemLine.LineType == "```+") { enteredPreformat = true; foundNimigemEdit = true; //strictly speaking this will ignore all nimigem areas that are empty... } if (enteredPreformat & gemLine.LineType != "```+") { exitedPreformatted = true; } if (!exitedPreformatted && enteredPreformat && gemLine.LineType == "```+") { //we found a line in the first preceeding preformatted area preformattedLines.Add(gemLine); } currentLine--; } var sb = new StringBuilder(); preformattedLines.Reverse(); for (int n = 0; n < preformattedLines.Count; n++) { var editLine = preformattedLines[n]; //nimigem spec requires any required preformatted markers inside //editable preformatted areas to be escaped with zero width space if (editLine.Line.StartsWith('\u200b'.ToString() + "```")) { sb.Append(editLine.Line.Substring(1)); //trim leading zero width space used to escape preformatted markers } else { sb.Append(editLine.Line); } //append newline to all except the last one if (n < preformattedLines.Count - 1) { sb.Append("\n"); } } if (foundNimigemEdit) { var userEdit = Dialogs.MultilineInputBox("Nimigem edit", "Edit the text to be sent to: " + uri.AbsoluteUri, sb.ToString()); if (userEdit.ButtonPressed == TextDialogResponse.Buttons.Ok) { try { //send as plain text, utf8 SubmitNimigem(uri, Encoding.UTF8.GetBytes(userEdit.Text), "text/plain"); } catch (Exception e) { Dialogs.MsgBoxOK("Nimigem error", "Nimigem error: \n" + e.Message); } } } else { //No associated preceding Nimigem editable preformatted area was found. //so send a file //show a dialog to choose a file var openDialog = new Terminal.Gui.OpenDialog("Nimigem upload", "Choose a file to send to the Nimigem server"); Application.Run(openDialog); if (openDialog.FilePaths.Count > 0) { var selectedPath = openDialog.FilePaths[0]; var bytes = File.ReadAllBytes(selectedPath); var extension = Path.GetExtension(selectedPath); // since text/gemini is not widely known but might be more common for users of a gemini client // we test for it, otherwise we use the MimeTypes library to infer it var mediaType = (extension == ".gmi" || extension == ".gemini") ? "text/gemini" : MimeTypes.GetMimeType(selectedPath); try { SubmitNimigem(uri, bytes, mediaType); //send to the server } catch (Exception e) { Dialogs.MsgBoxOK("Nimigem error", "Nimigem error: \n" + e.Message); } } } }
static void LoadGeminiLink(Uri uri) { string result; bool retrieved = false; GeminiResponse resp; resp = new GeminiResponse(); try { resp = (GeminiResponse)Gemini.Fetch(uri); retrieved = true; } catch (Exception e) { //the native gui.cs Messagebox does not resize to show enough content //so we use our own that is better Dialogs.MsgBoxOK("Gemini error", uri.AbsoluteUri + "\n\n" + e.Message); } if (retrieved) { if (resp.codeMajor == '2') { //examine the first component of the media type up to any semi colon switch (resp.mime.Split(';')[0].Trim()) { case "text/gemini": case "text/plain": case "text/html": { string body = Encoding.UTF8.GetString(resp.bytes.ToArray()); result = (body); if (!resp.mime.StartsWith("text/gemini")) { //display as preformatted text result = "```\n" + result + "\n```\n"; } break; } default: // report the mime type only for now result = ("Some " + resp.mime + " content was received, but cannot currently be displayed."); break; } //render the content and add to history SetAsCurrent(resp.uri); //remember the final URI, since it may have been redirected. if (_history.Count > 0) { _history.Peek().top = _lineView.TopItem; _history.Peek().selected = _lineView.SelectedItem; //remember the line offset of the current page } _history.Push(new CachedPage(resp.uri, result, 0, 0)); RenderGemini(resp.uri.AbsoluteUri, result, _lineView); } else if (resp.codeMajor == '1') { //input requested from server var userResponse = Dialogs.SingleLineInputBox("Input request from: " + uri.Authority, resp.meta, ""); if ((userResponse.ButtonPressed == TextDialogResponse.Buttons.Ok) && (userResponse.Text != "")) { var ub = new UriBuilder(uri); ub.Query = userResponse.Text; LoadGeminiLink(ub.Uri); } } else if ((resp.codeMajor == '5') && (resp.codeMinor == '1')) { //not found Dialogs.MsgBoxOK("Not found", "The resource was not found on the server: \n\n" + resp.uri.AbsoluteUri); } else { Dialogs.MsgBoxOK("Gemini server response", uri.AbsoluteUri + "\n\n" + "Status: " + resp.codeMajor + resp.codeMinor + ": " + resp.meta); } } }