[1mdiff --git a/res/about/version.gmi b/res/about/version.gmi[m
[1mindex a0cbe637..df532ab3 100644[m
[1m--- a/res/about/version.gmi[m
[1m+++ b/res/about/version.gmi[m
[36m@@ -9,6 +9,8 @@[m
[32m+[m[32m* Gopher: Fixed navigating to root, e.g., when clicking on the page top banner. Set item type to 1 to show a gophermap and not the plain source.[m
[32m+[m[32m* Titan: When navigating to parent/root, switch URL scheme to "gemini". This action occurs on a Titan response page, so initiating a new upload with the parent/root URL is probably not appropriate.[m
[1mdiff --git a/src/gmutil.c b/src/gmutil.c[m
[1mindex 98e4d4d6..b984950e 100644[m
[1m--- a/src/gmutil.c[m
[1m+++ b/src/gmutil.c[m
[36m@@ -131,6 +131,16 @@[m [mstatic iRangecc prevPathSeg_(const char *end, const char *start) {[m
return seg;[m
}[m
[m
[32m+[m[32mvoid stripUrlPort_String(iString *d) {[m
[32m+[m[32m iUrl parts;[m
[32m+[m[32m init_Url(&parts, d);[m
[32m+[m[32m if (!isEmpty_Range(&parts.port)) {[m
[32m+[m[32m /* Always preceded by a colon. */[m
[32m+[m[32m remove_Block(&d->chars, parts.port.start - 1 - constBegin_String(d),[m
[32m+[m[32m size_Range(&parts.port) + 1);[m
[32m+[m[32m }[m
[32m+[m[32m}[m
[32m+[m
void stripDefaultUrlPort_String(iString *d) {[m
iUrl parts;[m
init_Url(&parts, d);[m
[36m@@ -681,6 +691,17 @@[m [mconst iString *withSpacesEncoded_String(const iString *d) {[m
return d;[m
}[m
[m
[32m+[m[32mconst iString *withScheme_String(const iString *d, const char *scheme) {[m
[32m+[m[32m iUrl parts;[m
[32m+[m[32m init_Url(&parts, d);[m
[32m+[m[32m if (!equalCase_Rangecc(parts.scheme, scheme)) {[m
[32m+[m[32m iString *repl = collectNewCStr_String(scheme);[m
[32m+[m[32m appendRange_String(repl, (iRangecc){ parts.scheme.end, constEnd_String(d) });[m
[32m+[m[32m return repl;[m
[32m+[m[32m }[m
[32m+[m[32m return d;[m
[32m+[m[32m}[m
[32m+[m
const iString *canonicalUrl_String(const iString *d) {[m
/* The "canonical" form, used for internal storage and comparisons, is:[m
- all non-reserved characters decoded (i.e., it's an IRI)[m
[1mdiff --git a/src/gmutil.h b/src/gmutil.h[m
[1mindex 15bb7b2e..1594afc4 100644[m
[1m--- a/src/gmutil.h[m
[1m+++ b/src/gmutil.h[m
[36m@@ -127,6 +127,7 @@[m [miBool isKnownScheme_Rangecc (iRangecc scheme); /* any URI scheme */[m
iBool isKnownUrlScheme_Rangecc(iRangecc scheme); /* URL schemes only */[m
void punyEncodeDomain_Rangecc(iRangecc domain, iString *encoded_out);[m
void punyEncodeUrlHost_String(iString *absoluteUrl);[m
[32m+[m[32mvoid stripUrlPort_String (iString *);[m
void stripDefaultUrlPort_String(iString *);[m
const iString * urlFragmentStripped_String(const iString *);[m
const iString * urlQueryStripped_String (const iString *);[m
[36m@@ -138,6 +139,7 @@[m [mconst char * makeFileUrl_CStr (const char *localFilePath);[m
iString * localFilePathFromUrl_String(const iString *);[m
void urlEncodeSpaces_String (iString *);[m
const iString * withSpacesEncoded_String(const iString *);[m
[32m+[m[32mconst iString * withScheme_String (const iString *, const char scheme); / replace URI scheme */[m
const iString * canonicalUrl_String (const iString *);[m
[m
const char * mediaType_Path (const iString *path);[m
[1mdiff --git a/src/gopher.c b/src/gopher.c[m
[1mindex 008a7743..0e34fe6a 100644[m
[1m--- a/src/gopher.c[m
[1m+++ b/src/gopher.c[m
[36m@@ -299,3 +299,13 @@[m [miBool processResponse_Gopher(iGopher *d, const iBlock *data) {[m
}[m
return changed;[m
}[m
[32m+[m
[32m+[m[32mvoid setUrlItemType_Gopher(iString *url, char itemType) {[m
[32m+[m[32m iUrl parts;[m
[32m+[m[32m init_Url(&parts, url);[m
[32m+[m[32m if (equalCase_Rangecc(parts.scheme, "gopher")) {[m
[32m+[m[32m if (parts.path.start && size_Range(&parts.path) >= 2) {[m
[32m+[m[32m ((char *) parts.path.start)[1] = itemType;[m
[32m+[m[32m }[m
[32m+[m[32m }[m[41m [m
[32m+[m[32m}[m
[1mdiff --git a/src/gopher.h b/src/gopher.h[m
[1mindex 3ad7e374..3cad0c21 100644[m
[1m--- a/src/gopher.h[m
[1m+++ b/src/gopher.h[m
[36m@@ -44,3 +44,5 @@[m [miDeclareTypeConstruction(Gopher)[m
void open_Gopher (iGopher *, const iString *url);[m
iBool processResponse_Gopher (iGopher *, const iBlock *data);[m
void cancel_Gopher (iGopher *);[m
[32m+[m
[32m+[m[32mvoid setUrlItemType_Gopher (iString *url, char itemType);[m
[1mdiff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c[m
[1mindex 2e15cdce..86513368 100644[m
[1m--- a/src/ui/documentwidget.c[m
[1m+++ b/src/ui/documentwidget.c[m
[36m@@ -36,6 +36,7 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m
#include "gmdocument.h"[m
#include "gmrequest.h"[m
#include "gmutil.h"[m
[32m+[m[32m#include "gopher.h"[m
#include "history.h"[m
#include "indicatorwidget.h"[m
#include "inputwidget.h"[m
[36m@@ -4315,20 +4316,31 @@[m [mstatic iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)[m
}[m
iString *parentUrl = collectNewRange_String((iRangecc){ constBegin_String(d->mod.url),[m
parts.path.end });[m
[31m- if (equalCase_Rangecc(parts.scheme, "gopher")) {[m
[31m- /* Always go to a gophermap. */[m
[31m- iZap(parts);[m
[31m- init_Url(&parts, parentUrl);[m
[31m- if (parts.path.start && size_Range(&parts.path) >= 2) {[m
[31m- ((char *) parts.path.start)[1] = '1';[m
[31m- }[m
[32m+[m[32m /* Always go to a gophermap. */[m
[32m+[m[32m setUrlItemType_Gopher(parentUrl, '1');[m
[32m+[m[32m /* Hierarchical navigation doesn't make sense with Titan. */[m
[32m+[m[32m if (startsWith_String(parentUrl, "titan://")) {[m
[32m+[m[32m /* We have no way of knowing if the corresponding URL is valid for Gemini,[m
[32m+[m[32m but let's try anyway. */[m[41m [m
[32m+[m[32m set_String(parentUrl, withScheme_String(parentUrl, "gemini"));[m
[32m+[m[32m stripUrlPort_String(parentUrl);[m
}[m
postCommandf_Root(w->root, "open url:%s", cstr_String(parentUrl));[m
}[m
return iTrue;[m
}[m
else if (equal_Command(cmd, "navigate.root") && document_App() == d) {[m
[31m- postCommandf_Root(w->root, "open url:%s/", cstr_Rangecc(urlRoot_String(d->mod.url)));[m
[32m+[m[32m iString *rootUrl = collectNewRange_String(urlRoot_String(d->mod.url));[m
[32m+[m[32m /* Always go to a gophermap. */[m
[32m+[m[32m setUrlItemType_Gopher(rootUrl, '1');[m
[32m+[m[32m /* Hierarchical navigation doesn't make sense with Titan. */[m
[32m+[m[32m if (startsWith_String(rootUrl, "titan://")) {[m
[32m+[m[32m /* We have no way of knowing if the corresponding URL is valid for Gemini,[m
[32m+[m[32m but let's try anyway. */[m[41m [m
[32m+[m[32m set_String(rootUrl, withScheme_String(rootUrl, "gemini"));[m
[32m+[m[32m stripUrlPort_String(rootUrl);[m
[32m+[m[32m }[m[41m [m
[32m+[m[32m postCommandf_Root(w->root, "open url:%s/", cstr_String(rootUrl));[m
return iTrue;[m
}[m
else if (equalWidget_Command(cmd, w, "scroll.moved")) {[m
text/plain
This content has been proxied by September (ba2dc).