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; } }
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; }
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); }
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; }
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); } } }
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; }
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); } } }