//launch url in system browser
 public void LaunchExternalUri(string uri)
 {
     Process.Start(new ProcessStartInfo(uri)
     {
         UseShellExecute = true
     });
     mMainWindow.ToastNotify("Launching in system browser: " + uri);
 }
Esempio n. 2
0
        public void AddBookmark(string url, string title)
        {
            var settings = new Settings();

            foreach (var line in BookmarkLines())
            {
                var linkParts = ParseGeminiLink(line);
                if (linkParts[0] == url)
                {
                    //already exists
                    mMainWindow.ToastNotify("That URL is already in the bookmarks, skipping.\n" + url, ToastMessageStyles.Warning);
                    return;
                }
            }

            //a new one
            settings.Bookmarks += "\r\n" + "=> " + url + "  " + mWebBrowser.GetTitle();
            settings.Save();
            RefreshBookmarkMenu();
            mMainWindow.ToastNotify("Bookmark added: " + (title + " " + url).Trim(), ToastMessageStyles.Success);
        }
Esempio n. 3
0
        public void NavigateAboutScheme(System.Windows.Navigation.NavigatingCancelEventArgs e, SiteIdentity siteIdentity)
        {
            var sessionPath = Session.Instance.SessionPath;
            var appDir      = System.AppDomain.CurrentDomain.BaseDirectory;

            string fullQuery;

            //just load the help file
            //no further action
            mMainWindow.ToggleContainerControlsForBrowser(true);

            var sourceFileName = e.Uri.PathAndQuery.Substring(1);      //trim off leading /

            //this expects uri has a "geminaut" domain so gmitohtml converter can proceed for now
            //I think it requires a domain for parsing...
            fullQuery = e.Uri.OriginalString;

            string hash;

            hash = HashService.GetMd5Hash(fullQuery);


            var hashFile       = Path.Combine(sessionPath, hash + ".txt");
            var htmlCreateFile = Path.Combine(sessionPath, hash + ".htm");

            var finder     = new ResourceFinder();
            var helpFolder = finder.LocalOrDevFolder(appDir, @"Docs", @"..\..\Docs");
            var helpFile   = Path.Combine(helpFolder, sourceFileName);

            //use a specific theme so about pages look different to user theme
            var templateBaseName = Path.Combine(helpFolder, "help-theme");



            if (File.Exists(helpFile))
            {
                File.Copy(helpFile, hashFile, true);
                mMainWindow.ShowUrl(fullQuery, hashFile, htmlCreateFile, templateBaseName, siteIdentity, e);
            }
            else
            {
                mMainWindow.ToastNotify("No content was found for: " + fullQuery, ToastMessageStyles.Warning);
                e.Cancel = true;
            }
        }
Esempio n. 4
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. 5
0
        public bool NavigateGeminiScheme(string fullQuery, Uri uri, SiteIdentity siteIdentity, bool requireSecure = true)
        {
            bool navigated = true;

            var geminiUri = uri.OriginalString;

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

            //use local or dev binary for gemget
            var gemGet = ResourceFinder.LocalOrDevFile(appDir, "Gemget", "..\\..\\..\\..\\Gemget", "gemget-windows-386.exe");

            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    settings = new Settings();
            string command  = "";

            var secureFlag = requireSecure ? "" : " -i ";

            if (uri.Scheme == "gemini")
            {
                //pass options to gemget for download
                command = string.Format(
                    "\"{0}\" {1} --header --no-progress-bar -m \"{2}\"Mb -t {3} -o \"{4}\" \"{5}\"",
                    gemGet,
                    secureFlag,
                    settings.MaxDownloadSizeMb,
                    settings.MaxDownloadTimeSeconds,
                    rawFile,
                    fullQuery);
            }
            else
            {
                //pass options to gemget for download using the assigned http proxy, such as
                //duckling-proxy https://github.com/LukeEmmet/duckling-proxy
                //this should obviously be a trusted server since it is in the middle of the
                //request
                command = string.Format(
                    "\"{0}\" {1} --header --no-progress-bar -m \"{2}\"Mb -t {3} -o \"{4}\"  -p \"{5}\" \"{6}\"",
                    gemGet,
                    secureFlag,
                    settings.MaxDownloadSizeMb,
                    settings.MaxDownloadTimeSeconds,
                    rawFile,
                    settings.HttpSchemeProxy,
                    fullQuery);
            }

            var result = ExecuteProcess.ExecuteCommand(command, true, true);

            var geminiResponse = new Response.GeminiResponse(fullQuery);

            geminiResponse.ParseGemGet(result.Item2);   //parse stdout
            geminiResponse.ParseGemGet(result.Item3);   //parse stderr

            //ToastNotify(geminiResponse.Status + " " + geminiResponse.Meta);

            //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 (result.Item1 == 1 && requireSecure)
            {
                var tryInsecure   = false;
                var securityError = "";
                if (geminiResponse.Errors[0].Contains("server cert is expired"))
                {
                    tryInsecure   = true;
                    securityError = "Server certificate is expired";
                }
                else if (geminiResponse.Errors[0].Contains("hostname does not verify"))
                {
                    tryInsecure   = true;
                    securityError = "Host name does not verify";
                }
                if (tryInsecure)
                {
                    //give a warning and try again with insecure
                    mMainWindow.ToastNotify("Note: " + securityError + " for: " + uri.Authority, ToastMessageStyles.Warning);
                    NavigateGeminiScheme(fullQuery, uri, siteIdentity, false);
                    return(true);
                }
            }

            if (geminiResponse.AbandonedTimeout || geminiResponse.AbandonedSize)
            {
                var abandonMessage = string.Format(
                    "Download was abandoned as it exceeded the max size ({0}) or time ({1} s). See GemiNaut settings for details.\n\n{2}",
                    settings.MaxDownloadSizeMb,
                    settings.MaxDownloadTimeSeconds,
                    fullQuery);

                mMainWindow.ToastNotify(abandonMessage, ToastMessageStyles.Warning);
                mMainWindow.ToggleContainerControlsForBrowser(true);
                return(false);
            }

            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);
                        return(false);
                    }
                }
                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);
                        return(false);
                    }
                }
                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);
                    }
                    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);
                        return(false);
                    }

                    return(true);
                }

                if (geminiResponse.Redirected)
                {
                    string redirectUri = fullQuery;

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

                    var finalUri = new Uri(redirectUri);

                    if (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);
                        return(false);
                    }
                    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);
            }
            else if (geminiResponse.Status == 10 || geminiResponse.Status == 11)
            {
                //needs input

                mMainWindow.ToggleContainerControlsForBrowser(true);

                navigated = NavigateGeminiWithInput(uri, geminiResponse.Meta);
            }
            else if (geminiResponse.Status == 50 || geminiResponse.Status == 51)
            {
                mMainWindow.ToastNotify("Page not found (status 51)\n\n" + uri.ToString(), ToastMessageStyles.Warning);
            }
            else
            {
                //some othe error - show to the user for info
                mMainWindow.ToastNotify(string.Format(
                                            "Cannot retrieve the content (exit code {0}): \n\n{1} \n\n{2}",
                                            result.Item1,
                                            string.Join("\n\n", geminiResponse.Info),
                                            string.Join("\n\n", geminiResponse.Errors)
                                            ),
                                        ToastMessageStyles.Error);
            }

            mMainWindow.ToggleContainerControlsForBrowser(true);

            //no further navigation right now
            return(navigated);
        }
Esempio n. 6
0
        public void NavigateNimigemScheme(string fullQuery, System.Windows.Navigation.NavigatingCancelEventArgs e, string payload, bool requireSecure = true)
        {
            var NimigemUri = e.Uri.OriginalString;

            //at present we only support UTF8 plain text payloads
            byte[] nimigemBody = Encoding.UTF8.GetBytes(payload);
            var    mime        = "text/plain; charset=utf-8";

            var settings = new UserSettings();

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

            var connectInsecure = false;

            if (uri.Host == "localhost")
            {
                //to support local testing servers, dont require secure connection on localhost
                //**FIX ME, or have an option
                connectInsecure = true;
            }

            X509Certificate2 certificate;

            certificate = Session.Instance.CertificatesManager.GetCertificate(uri.Host);

            try
            {
                NimigemResponse nimigemResponse;
                try
                {
                    nimigemResponse = (NimigemResponse)Nimigem.Fetch(uri, nimigemBody, mime, 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 Nimigem 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: " + err.Message + " for: " + e.Uri.Authority, ToastMessageStyles.Warning);

                        //try again insecure this time
                        nimigemResponse = (NimigemResponse)Nimigem.Fetch(uri, nimigemBody, mime, certificate, proxy, connectInsecure, settings.MaxDownloadSizeMb * 1024, settings.MaxDownloadTimeSeconds);
                    }

                    else
                    {
                        //reraise
                        throw;
                    }
                }

                if (nimigemResponse.codeMajor == '1')
                {
                    //invalid in nimigem
                    HandleInvalidResponse(nimigemResponse);
                }

                else if (nimigemResponse.codeMajor == '2')
                {
                    //success
                    if (nimigemResponse.codeMinor == '5')
                    {
                        //valid submission - get the new target to retrieve
                        mMainWindow.ToastNotify(String.Format("Submit successful: retrieving result: {0}", nimigemResponse.meta));

                        var successUri = new Uri(nimigemResponse.meta);

                        //must be a response redirect to gemini URL
                        if (successUri.Scheme != "gemini")
                        {
                            HandleInvalidResponse(nimigemResponse);
                        }


                        var geminiTarget  = new GeminiNavigator(mMainWindow, mMainWindow.BrowserControl);
                        var normalisedUri = UriTester.NormaliseUri(successUri);

                        var siteIdentity = new SiteIdentity(normalisedUri, Session.Instance);

                        geminiTarget.NavigateGeminiScheme(successUri.OriginalString, e, siteIdentity);
                    }
                    else
                    {
                        //no other 2X responses are valid
                        HandleInvalidResponse(nimigemResponse);
                    }
                }

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

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

                else
                {
                    mMainWindow.ToastNotify("Unexpected output from server " +
                                            "(status " + nimigemResponse.codeMajor + "." + nimigemResponse.codeMinor + ") " +
                                            nimigemResponse.meta + "\n\n"
                                            + e.Uri.ToString(), ToastMessageStyles.Warning);
                }
            }
            catch (Exception err)
            {
                //generic handler for other runtime errors
                mMainWindow.ToastNotify("Error getting Nimigem 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. 7
0
        public void NavigateGopherScheme(string fullQuery, System.Windows.Navigation.NavigatingCancelEventArgs e, SiteIdentity siteIdentity)
        {
            var sessionPath = Session.Instance.SessionPath;
            var appDir      = System.AppDomain.CurrentDomain.BaseDirectory;

            //check if it is a query selector without a parameter
            if (!e.Uri.OriginalString.Contains("%09") && e.Uri.PathAndQuery.StartsWith("/7/"))
            {
                NavigateGopherWithInput(e);

                mMainWindow.ToggleContainerControlsForBrowser(true);

                //no further navigation right now
                e.Cancel = true;

                return;
            }


            var proc   = new ExecuteProcess();
            var finder = new ResourceFinder();

            //use local or dev binary for gemget
            var gopherClient = finder.LocalOrDevFile(appDir, "GopherGet", "..\\..\\..\\GopherGet", "gopher-get.exe");

            string hash;

            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 gopherFile = 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(gopherFile);

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

            //save to the file
            var command = string.Format("\"{0}\" \"{1}\" \"{2}\"", gopherClient, fullQuery, gopherFile);


            var result = proc.ExecuteCommand(command, true, true);

            var exitCode = result.Item1;
            var stdOut   = result.Item2;

            if (exitCode != 0)
            {
                mMainWindow.ToastNotify(result.Item3, ToastMessageStyles.Error);
                mMainWindow.ToggleContainerControlsForBrowser(true);    //reenable browser
                e.Cancel = true;
                return;
            }


            if (File.Exists(gopherFile))
            {
                string parseFile;

                if (stdOut.Contains("DIR") || stdOut.Contains("QRY"))
                {
                    //convert gophermap to text/gemini

                    //ToastNotify("Converting gophermap to " + gmiFile);
                    result    = ConverterService.GophertoGmi(gopherFile, gmiFile, fullQuery, GopherParseTypes.Map);
                    parseFile = gmiFile;
                }
                else if (stdOut.Contains("TXT"))
                {
                    result    = ConverterService.GophertoGmi(gopherFile, gmiFile, fullQuery, GopherParseTypes.Text);
                    parseFile = gmiFile;
                }
                else
                {
                    //a download

                    //copy to a file having its source extension
                    var pathFragment = (new UriBuilder(fullQuery)).Path;
                    var ext          = Path.GetExtension(pathFragment);

                    var binFile = gopherFile + (ext ?? "");

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

                    if (stdOut.Contains("IMG") || stdOut.Contains("GIF"))
                    {
                        //show the image
                        mMainWindow.ShowImage(fullQuery, binFile, e);
                    }
                    else
                    {
                        //show a save as dialog
                        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 (!File.Exists(gmiFile))
                {
                    mMainWindow.ToastNotify("Did not create expected GMI file for " + fullQuery + " in " + gmiFile, ToastMessageStyles.Error);
                    mMainWindow.ToggleContainerControlsForBrowser(true);
                    e.Cancel = true;
                }
                else
                {
                    var settings         = new Settings();
                    var userThemesFolder = finder.LocalOrDevFolder(appDir, @"GmiConverters\themes", @"..\..\GmiConverters\themes");

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

                    mMainWindow.ShowUrl(fullQuery, parseFile, htmlFile, userThemeBase, siteIdentity, e);
                }
            }
        }
Esempio n. 8
0
        public void NavigateHttpScheme(string fullQuery, NavigatingCancelEventArgs e, SiteIdentity siteIdentity, string linkId)
        {
            var httpUri = e.Uri.OriginalString;

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

            var hash = HashService.GetMd5Hash(fullQuery);

            var settings = new UserSettings();

            //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";

            var reRender = false;       //if just re-rendering the same content in a different mode, dont re-fetch

            var httpResponse = new Response.HttpResponse(fullQuery);

            Tuple <int, string, string> result;

            if (IsModeSwitch(linkId) && File.Exists(rawFile))
            {
                //use the existing content
                reRender = true;
                result   = new Tuple <int, string, string>(0, "", "");

                //set default mode to this mode
                settings.WebRenderMode = linkId;
                settings.Save();
            }
            else
            {
                File.Delete(rawFile);

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

                //use local or dev binary for gemget
                var httpGet = ResourceFinder.LocalOrDevFile(appDir, "HttpGet", "..\\..\\..\\..\\HttpGet", "http-get.exe");

                //pass options to gemget for download
                var command = string.Format(
                    "\"{0}\" --header -o \"{1}\" \"{2}\"",
                    httpGet,
                    rawFile,
                    fullQuery);

                result = ExecuteProcess.ExecuteCommand(command, true, true);

                if (result.Item1 != 0)
                {
                    mMainWindow.ToastNotify("Could not access web resource: " + fullQuery + "\n" + result.Item3, ToastMessageStyles.Warning);
                    mMainWindow.ToggleContainerControlsForBrowser(true);
                    e.Cancel = true;
                    return;
                }

                httpResponse.ParseGemGet(result.Item2);   //parse stdout
                httpResponse.ParseGemGet(result.Item3);   //parse stderr

                if (httpResponse.StatusCode == 404)
                {
                    {
                        mMainWindow.ToastNotify("Resource not found:\n" + fullQuery, ToastMessageStyles.Warning);
                        mMainWindow.ToggleContainerControlsForBrowser(true);
                        e.Cancel = true;
                        return;
                    }
                    //ToastNotify(httpResponse.Status + " " + httpResponse.Meta);
                }
                else if (httpResponse.StatusCode != 200)
                {
                    //some other error
                    mMainWindow.ToastNotify("Could not get resource: "
                                            + httpResponse.Status + "\n"
                                            + fullQuery, ToastMessageStyles.Warning);
                    mMainWindow.ToggleContainerControlsForBrowser(true);
                    e.Cancel = true;
                    return;
                }
            }

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

            if (File.Exists(rawFile))
            {
                if (httpResponse.ContentType.Contains("text/html") || reRender)
                {
                    //use local or dev binary for goose
                    var gooseConvert = ResourceFinder.LocalOrDevFile(appDir, "Goose", "..\\..\\..\\..\\Goose", "goose-cli.exe");
                    var gooseOut     = sessionPath + "\\" + hash + ".goose";

                    var gooseCommand = "";

                    var htmlPath = "";

                    if (settings.WebRenderMode == "web-switch-plain")
                    {
                        //pass options to goose to get plain text
                        gooseCommand = string.Format(
                            "\"{0}\" -t -i \"{1}\" -o \"{2}\"",
                            gooseConvert,
                            rawFile,
                            gooseOut);

                        result = ExecuteProcess.ExecuteCommand(gooseCommand, true, true);

                        //just use plain text
                        File.Copy(gooseOut, gmiFile, true);
                    }
                    else
                    {
                        if (settings.WebRenderMode == "web-switch-simplified")
                        {
                            //pass options to goose to get main content as html
                            gooseCommand = string.Format(
                                "\"{0}\" -i \"{1}\" -o \"{2}\"",
                                gooseConvert,
                                rawFile,
                                gooseOut);

                            //get main html of the page
                            result = ExecuteProcess.ExecuteCommand(gooseCommand, true, true);

                            htmlPath = gooseOut;
                        }
                        else
                        {
                            //no filtering to extract main content
                            htmlPath = rawFile;
                        }

                        //convert to gmi
                        var htmlToGmiResult = ConverterService.HtmlToGmi(htmlPath, gmiFile);

                        if (htmlToGmiResult.Item1 != 0)
                        {
                            mMainWindow.ToastNotify("Could not render HTML as GMI: " + fullQuery, ToastMessageStyles.Error);
                            mMainWindow.ToggleContainerControlsForBrowser(true);
                            e.Cancel = true;
                            return;
                        }
                    }
                }
                else if (httpResponse.ContentType.Contains("text/"))
                {
                    //convert plain text to a http 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 (httpResponse.ContentType.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 (httpResponse.Redirected)
                {
                    string redirectUri = fullQuery;

                    redirectUri = httpResponse.FinalUrl;
                    //redirected to a full http url
                    httpUri = redirectUri;

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

                    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
                {
                    httpUri = fullQuery;
                }

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

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

                mMainWindow.ShowUrl(httpUri, gmiFile, htmlFile, userThemeBase, siteIdentity, e);
            }
            else if (httpResponse.StatusCode == 404)
            {
                mMainWindow.ToastNotify("Page not found (status 51)\n\n" + e.Uri.ToString(), ToastMessageStyles.Warning);
            }
            else
            {
                //some othe error - show to the user for info
                mMainWindow.ToastNotify(string.Format(
                                            "Cannot retrieve the content (exit code {0}): \n\n{1} \n\n{2}",
                                            result.Item1,
                                            string.Join("\n\n", httpResponse.Info),
                                            string.Join("\n\n", httpResponse.Errors)
                                            ),
                                        ToastMessageStyles.Error);
            }

            mMainWindow.ToggleContainerControlsForBrowser(true);

            //no further navigation right now
            e.Cancel = true;
        }
Esempio n. 9
0
        public void NavigateGopherScheme(string fullQuery, System.Windows.Navigation.NavigatingCancelEventArgs e, SiteIdentity siteIdentity)
        {
            var sessionPath = Session.Instance.SessionPath;
            var appDir      = AppDomain.CurrentDomain.BaseDirectory;

            //check if it is a query selector without a parameter
            if (!e.Uri.OriginalString.Contains("%09") && e.Uri.PathAndQuery.StartsWith("/7/"))
            {
                NavigateGopherWithInput(e);

                mMainWindow.ToggleContainerControlsForBrowser(true);

                //no further navigation right now
                e.Cancel = true;

                return;
            }

            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 gopherFile = 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(gopherFile);

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

            //get the content from Gopher using SmolNetSharp
            IResponse response;

            try
            {
                response = Gopher.Fetch(new Uri(fullQuery), settings.MaxDownloadSizeMb * 1024, settings.MaxDownloadTimeSeconds);

                File.WriteAllBytes(gopherFile, response.bytes.ToArray());
            }
            catch (Exception err)
            {
                mMainWindow.ToastNotify(err.Message, ToastMessageStyles.Error);
                mMainWindow.ToggleContainerControlsForBrowser(true);    //reenable browser
                e.Cancel = true;
                return;
            }

            var mime = response.mime;
            Tuple <int, string, string> result;

            if (File.Exists(gopherFile))
            {
                string parseFile;

                if (mime == "application/gopher-menu")
                {
                    //convert gophermap to text/gemini

                    //ToastNotify("Converting gophermap to " + gmiFile);
                    result    = ConverterService.GophertoGmi(gopherFile, gmiFile, fullQuery, GopherParseTypes.Map);
                    parseFile = gmiFile;
                }
                else if (mime == "text/plain")
                {
                    result    = ConverterService.GophertoGmi(gopherFile, gmiFile, fullQuery, GopherParseTypes.Text);
                    parseFile = gmiFile;
                }
                else
                {
                    //a download

                    //copy to a file having its source extension
                    var pathFragment = (new UriBuilder(fullQuery)).Path;
                    var ext          = Path.GetExtension(pathFragment);

                    var binFile = gopherFile + (ext ?? "");

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

                    if (mime == "image/png" || mime == "image/gif" || mime == "image/jpeg")
                    {
                        //show the image
                        mMainWindow.ShowImage(fullQuery, binFile, e);
                    }
                    else
                    {
                        //show a save as dialog
                        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 (!File.Exists(gmiFile) || result.Item1 != 0)
                {
                    mMainWindow.ToastNotify("Did not create expected GMI file for " + fullQuery + " in " + gmiFile, ToastMessageStyles.Error);
                    mMainWindow.ToggleContainerControlsForBrowser(true);
                    e.Cancel = true;
                }
                else
                {
                    var userThemesFolder = ResourceFinder.LocalOrDevFolder(appDir, @"GmiConverters\themes", @"..\..\..\GmiConverters\themes");

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

                    mMainWindow.ShowUrl(fullQuery, parseFile, htmlFile, userThemeBase, siteIdentity, e);
                }
            }
        }