Esempio n. 1
0
        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);
                }
            }
        }
Esempio n. 2
0
        public void NavigateGeminiScheme(string fullQuery, System.Windows.Navigation.NavigatingCancelEventArgs e, SiteIdentity siteIdentity, bool requireSecure = true)
        {
            var geminiUri = e.Uri.OriginalString;

            var sessionPath = Session.Instance.SessionPath;
            var appDir      = AppDomain.CurrentDomain.BaseDirectory;

            var settings = new UserSettings();

            var hash = HashService.GetMd5Hash(fullQuery);

            //uses .txt as extension so content loaded as text/plain not interpreted by the browser
            //if user requests a view-source.
            var rawFile  = sessionPath + "\\" + hash + ".txt";
            var gmiFile  = sessionPath + "\\" + hash + ".gmi";
            var htmlFile = sessionPath + "\\" + hash + ".htm";

            //delete txt file as GemGet seems to sometimes overwrite not create afresh
            File.Delete(rawFile);
            File.Delete(gmiFile);

            //delete any existing html file to encourage webbrowser to reload it
            File.Delete(htmlFile);

            var uri = new Uri(fullQuery);
            //use a proxy for any other scheme that is not gemini
            var proxy           = ""; //use none
            var connectInsecure = false;

            X509Certificate2 certificate;

            certificate = Session.Instance.CertificatesManager.GetCertificate(uri.Host);   //may be null if none assigned or available



            if (uri.Scheme != "gemini")
            {
                proxy = settings.HttpSchemeProxy;
            }

            try
            {
                GeminiResponse geminiResponse;
                try
                {
                    geminiResponse = (GeminiResponse)Gemini.Fetch(uri, certificate, proxy, connectInsecure, settings.MaxDownloadSizeMb * 1024, settings.MaxDownloadTimeSeconds);
                }
                catch (Exception err)
                {
                    //warn, but continue if there are server validation errors
                    //in these early days of Gemini we dont forbid visiting a site with an expired cert or mismatched host name
                    //but we do give a warning each time
                    if (err.Message == "The remote certificate was rejected by the provided RemoteCertificateValidationCallback.")
                    {
                        mMainWindow.ToastNotify("Note: the certificate from: " + e.Uri.Authority + " is expired or invalid.", ToastMessageStyles.Warning);

                        //try again insecure this time
                        geminiResponse = (GeminiResponse)Gemini.Fetch(uri, certificate, proxy, true, settings.MaxDownloadSizeMb * 1024, settings.MaxDownloadTimeSeconds);
                    }
                    else
                    {
                        //reraise
                        throw;
                    }
                }

                if (geminiResponse.codeMajor == '1')
                {
                    //needs input, then refetch

                    mMainWindow.ToggleContainerControlsForBrowser(true);

                    NavigateGeminiWithInput(e, geminiResponse);
                }

                else if (geminiResponse.codeMajor == '2')
                {
                    //success
                    File.WriteAllBytes(rawFile, geminiResponse.bytes.ToArray());


                    if (File.Exists(rawFile))
                    {
                        if (geminiResponse.meta.Contains("text/gemini"))
                        {
                            File.Copy(rawFile, gmiFile);
                        }
                        else if (geminiResponse.meta.Contains("text/html"))
                        {
                            //is an html file served over gemini - probably not common, but not unheard of
                            var htmltoGmiResult = ConverterService.HtmlToGmi(rawFile, gmiFile);

                            if (htmltoGmiResult.Item1 != 0)
                            {
                                mMainWindow.ToastNotify("Could not convert HTML to GMI: " + fullQuery, ToastMessageStyles.Error);
                                mMainWindow.ToggleContainerControlsForBrowser(true);
                                e.Cancel = true;
                                return;
                            }
                        }
                        else if (geminiResponse.meta.Contains("text/"))
                        {
                            //convert plain text to a gemini version (wraps it in a preformatted section)
                            var textToGmiResult = ConverterService.TextToGmi(rawFile, gmiFile);

                            if (textToGmiResult.Item1 != 0)
                            {
                                mMainWindow.ToastNotify("Could not render text as GMI: " + fullQuery, ToastMessageStyles.Error);
                                mMainWindow.ToggleContainerControlsForBrowser(true);
                                e.Cancel = true;
                                return;
                            }
                        }
                        else
                        {
                            //a download
                            //its an image - rename the raw file and just show it
                            var pathFragment = (new UriBuilder(fullQuery)).Path;
                            var ext          = Path.GetExtension(pathFragment);

                            var binFile = rawFile + (ext == "" ? ".tmp" : ext);
                            File.Copy(rawFile, binFile, true); //rename overwriting

                            if (geminiResponse.meta.Contains("image/"))
                            {
                                mMainWindow.ShowImage(fullQuery, binFile, e);
                            }
                            else
                            {
                                SaveFileDialog saveFileDialog = new SaveFileDialog();

                                saveFileDialog.FileName = Path.GetFileName(pathFragment);

                                if (saveFileDialog.ShowDialog() == true)
                                {
                                    try
                                    {
                                        //save the file
                                        var savePath = saveFileDialog.FileName;

                                        File.Copy(binFile, savePath, true); //rename overwriting

                                        mMainWindow.ToastNotify("File saved to " + savePath, ToastMessageStyles.Success);
                                    }
                                    catch (SystemException err)
                                    {
                                        mMainWindow.ToastNotify("Could not save the file due to: " + err.Message, ToastMessageStyles.Error);
                                    }
                                }

                                mMainWindow.ToggleContainerControlsForBrowser(true);
                                e.Cancel = true;
                            }

                            return;
                        }

                        if (geminiResponse.uri.ToString() != fullQuery)
                        {
                            string redirectUri = fullQuery;

                            if (geminiResponse.uri.ToString().Contains("://"))
                            {
                                //a full url
                                //normalise the URi (e.g. remove default port if specified)
                                redirectUri = UriTester.NormaliseUri(new Uri(geminiResponse.uri.ToString())).ToString();
                            }
                            else
                            {
                                //a relative one
                                var baseUri   = new Uri(fullQuery);
                                var targetUri = new Uri(baseUri, geminiResponse.uri.ToString());
                                redirectUri = UriTester.NormaliseUri(targetUri).ToString();
                            }

                            var finalUri = new Uri(redirectUri);

                            if (e.Uri.Scheme == "gemini" && finalUri.Scheme != "gemini")
                            {
                                //cross-scheme redirect, not supported
                                mMainWindow.ToastNotify("Cross scheme redirect from Gemini not supported: " + redirectUri, ToastMessageStyles.Warning);
                                mMainWindow.ToggleContainerControlsForBrowser(true);
                                e.Cancel = true;
                                return;
                            }
                            else
                            {
                                //others e.g. http->https redirect are fine
                            }

                            //redirected to a full gemini url
                            geminiUri = redirectUri;

                            //regenerate the hashes using the redirected target url
                            hash = HashService.GetMd5Hash(geminiUri);

                            var gmiFileNew  = sessionPath + "\\" + hash + ".txt";
                            var htmlFileNew = sessionPath + "\\" + hash + ".htm";

                            //move the source file
                            try
                            {
                                if (File.Exists(gmiFileNew))
                                {
                                    File.Delete(gmiFileNew);
                                }
                                File.Move(gmiFile, gmiFileNew);
                            }
                            catch (Exception err)
                            {
                                mMainWindow.ToastNotify(err.ToString(), ToastMessageStyles.Error);
                            }

                            //update locations of gmi and html file
                            gmiFile  = gmiFileNew;
                            htmlFile = htmlFileNew;
                        }
                        else
                        {
                            geminiUri = fullQuery;
                        }

                        var userThemesFolder = ResourceFinder.LocalOrDevFolder(appDir, @"GmiConverters\themes", @"..\..\..\GmiConverters\themes");

                        var userThemeBase = Path.Combine(userThemesFolder, settings.Theme);

                        mMainWindow.ShowUrl(geminiUri, gmiFile, htmlFile, userThemeBase, siteIdentity, e);
                    }
                }

                // codemajor = 3 is redirect - should eventually end in success or raise an error

                else if (geminiResponse.codeMajor == '4')
                {
                    mMainWindow.ToastNotify("Temporary failure (status 4X)\n\n" + e.Uri.ToString(), ToastMessageStyles.Warning);
                }
                else if (geminiResponse.codeMajor == '5')
                {
                    if (geminiResponse.codeMinor == '1')
                    {
                        mMainWindow.ToastNotify("Page not found\n\n" + e.Uri.ToString(), ToastMessageStyles.Warning);
                    }
                    else
                    {
                        mMainWindow.ToastNotify("Permanent failure (status 5X)\n\n" + geminiResponse.meta + "\n\n" + e.Uri.ToString(), ToastMessageStyles.Warning);
                    }
                }
                else if (geminiResponse.codeMajor == '6')
                {
                    mMainWindow.ToastNotify("Certificate requried. Choose one and try again.\n\n" + e.Uri.ToString(), ToastMessageStyles.Warning);
                }

                else
                {
                    mMainWindow.ToastNotify("Unexpected output from server " +
                                            "(status " + geminiResponse.codeMajor + "." + geminiResponse.codeMinor + ") " +
                                            geminiResponse.meta + "\n\n"
                                            + e.Uri.ToString(), ToastMessageStyles.Warning);
                }
            }
            catch (Exception err)
            {
                //generic handler for other runtime errors
                mMainWindow.ToastNotify("Error getting gemini content for " + e.Uri.ToString() + "\n\n" + err.Message, ToastMessageStyles.Warning);
            }


            //make the window responsive again
            mMainWindow.ToggleContainerControlsForBrowser(true);

            //no further navigation right now
            e.Cancel = true;
        }
Esempio n. 3
0
        static void LoadLink(Uri uri)
        {
            string result;

            //special treatment for about: scheme
            if (uri.Scheme == "about")
            {
                result = ReadAboutSchemeFile(uri);
                RenderGemini(uri.AbsoluteUri, result, _lineView);
                _history.Push(new CachedPage(uri, result, 0, 0));
                SetAsCurrent(uri);
                return;
            }



            bool           retrieved = false;
            GeminiResponse resp;

            resp = new GeminiResponse();

            try
            {
                resp      = (GeminiResponse)Gemini.Fetch(uri);
                retrieved = true;
            }
            catch (Exception e)
            {
                //seems to be a bug that the native Messagebox does not resize to show enough content
                MsgBoxOK("Retrieval error", 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 userText = InputBox("Input request from: " + uri.Authority, resp.meta, "");

                    if (userText != "")
                    {
                        var ub = new UriBuilder(uri);
                        ub.Query = userText;

                        LoadLink(ub.Uri);
                    }
                }
                else
                {
                    MsgBoxOK("Gemini error", "Status: " + resp.codeMajor + resp.codeMinor + ": " + resp.meta);
                }
            }
        }