summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2022-01-29 18:00:01 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2022-01-29 18:00:01 +0200
commit07804493ac17ff430302c7940f44b7525c0620e8 (patch)
tree885db4fd4576ef65df77d4d47a3ae354efdba01e
parent8d46b523f2948992343a9491a12dcec73f109c87 (diff)
Hierarchical navigation with Gopher and Titan
With Gopher, ensure that the item type changes to 1, and with Titan, change to normal Gemini.
-rw-r--r--res/about/version.gmi2
-rw-r--r--src/gmutil.c21
-rw-r--r--src/gmutil.h2
-rw-r--r--src/gopher.c10
-rw-r--r--src/gopher.h2
-rw-r--r--src/ui/documentwidget.c28
6 files changed, 57 insertions, 8 deletions
diff --git a/res/about/version.gmi b/res/about/version.gmi
index a0cbe637..df532ab3 100644
--- a/res/about/version.gmi
+++ b/res/about/version.gmi
@@ -9,6 +9,8 @@
9## 1.10.3 9## 1.10.3
10* Added a man page. 10* Added a man page.
11* "/index.gmi" is considered equal to "/" when navigating to parent directory. 11* "/index.gmi" is considered equal to "/" when navigating to parent directory.
12* 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.
13* 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.
12* Fixed crash when a media player is active and a new download is started. 14* Fixed crash when a media player is active and a new download is started.
13* Fixed crash when a line contains nothing but an ANSI escape sequence. 15* Fixed crash when a line contains nothing but an ANSI escape sequence.
14* Fixed a possible crash when saving state of subscribed feeds. 16* Fixed a possible crash when saving state of subscribed feeds.
diff --git a/src/gmutil.c b/src/gmutil.c
index 98e4d4d6..b984950e 100644
--- a/src/gmutil.c
+++ b/src/gmutil.c
@@ -131,6 +131,16 @@ static iRangecc prevPathSeg_(const char *end, const char *start) {
131 return seg; 131 return seg;
132} 132}
133 133
134void stripUrlPort_String(iString *d) {
135 iUrl parts;
136 init_Url(&parts, d);
137 if (!isEmpty_Range(&parts.port)) {
138 /* Always preceded by a colon. */
139 remove_Block(&d->chars, parts.port.start - 1 - constBegin_String(d),
140 size_Range(&parts.port) + 1);
141 }
142}
143
134void stripDefaultUrlPort_String(iString *d) { 144void stripDefaultUrlPort_String(iString *d) {
135 iUrl parts; 145 iUrl parts;
136 init_Url(&parts, d); 146 init_Url(&parts, d);
@@ -681,6 +691,17 @@ const iString *withSpacesEncoded_String(const iString *d) {
681 return d; 691 return d;
682} 692}
683 693
694const iString *withScheme_String(const iString *d, const char *scheme) {
695 iUrl parts;
696 init_Url(&parts, d);
697 if (!equalCase_Rangecc(parts.scheme, scheme)) {
698 iString *repl = collectNewCStr_String(scheme);
699 appendRange_String(repl, (iRangecc){ parts.scheme.end, constEnd_String(d) });
700 return repl;
701 }
702 return d;
703}
704
684const iString *canonicalUrl_String(const iString *d) { 705const iString *canonicalUrl_String(const iString *d) {
685 /* The "canonical" form, used for internal storage and comparisons, is: 706 /* The "canonical" form, used for internal storage and comparisons, is:
686 - all non-reserved characters decoded (i.e., it's an IRI) 707 - all non-reserved characters decoded (i.e., it's an IRI)
diff --git a/src/gmutil.h b/src/gmutil.h
index 15bb7b2e..1594afc4 100644
--- a/src/gmutil.h
+++ b/src/gmutil.h
@@ -127,6 +127,7 @@ iBool isKnownScheme_Rangecc (iRangecc scheme); /* any URI scheme */
127iBool isKnownUrlScheme_Rangecc(iRangecc scheme); /* URL schemes only */ 127iBool isKnownUrlScheme_Rangecc(iRangecc scheme); /* URL schemes only */
128void punyEncodeDomain_Rangecc(iRangecc domain, iString *encoded_out); 128void punyEncodeDomain_Rangecc(iRangecc domain, iString *encoded_out);
129void punyEncodeUrlHost_String(iString *absoluteUrl); 129void punyEncodeUrlHost_String(iString *absoluteUrl);
130void stripUrlPort_String (iString *);
130void stripDefaultUrlPort_String(iString *); 131void stripDefaultUrlPort_String(iString *);
131const iString * urlFragmentStripped_String(const iString *); 132const iString * urlFragmentStripped_String(const iString *);
132const iString * urlQueryStripped_String (const iString *); 133const iString * urlQueryStripped_String (const iString *);
@@ -138,6 +139,7 @@ const char * makeFileUrl_CStr (const char *localFilePath);
138iString * localFilePathFromUrl_String(const iString *); 139iString * localFilePathFromUrl_String(const iString *);
139void urlEncodeSpaces_String (iString *); 140void urlEncodeSpaces_String (iString *);
140const iString * withSpacesEncoded_String(const iString *); 141const iString * withSpacesEncoded_String(const iString *);
142const iString * withScheme_String (const iString *, const char *scheme); /* replace URI scheme */
141const iString * canonicalUrl_String (const iString *); 143const iString * canonicalUrl_String (const iString *);
142 144
143const char * mediaType_Path (const iString *path); 145const char * mediaType_Path (const iString *path);
diff --git a/src/gopher.c b/src/gopher.c
index 008a7743..0e34fe6a 100644
--- a/src/gopher.c
+++ b/src/gopher.c
@@ -299,3 +299,13 @@ iBool processResponse_Gopher(iGopher *d, const iBlock *data) {
299 } 299 }
300 return changed; 300 return changed;
301} 301}
302
303void setUrlItemType_Gopher(iString *url, char itemType) {
304 iUrl parts;
305 init_Url(&parts, url);
306 if (equalCase_Rangecc(parts.scheme, "gopher")) {
307 if (parts.path.start && size_Range(&parts.path) >= 2) {
308 ((char *) parts.path.start)[1] = itemType;
309 }
310 }
311}
diff --git a/src/gopher.h b/src/gopher.h
index 3ad7e374..3cad0c21 100644
--- a/src/gopher.h
+++ b/src/gopher.h
@@ -44,3 +44,5 @@ iDeclareTypeConstruction(Gopher)
44void open_Gopher (iGopher *, const iString *url); 44void open_Gopher (iGopher *, const iString *url);
45iBool processResponse_Gopher (iGopher *, const iBlock *data); 45iBool processResponse_Gopher (iGopher *, const iBlock *data);
46void cancel_Gopher (iGopher *); 46void cancel_Gopher (iGopher *);
47
48void setUrlItemType_Gopher (iString *url, char itemType);
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 2e15cdce..86513368 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -36,6 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
36#include "gmdocument.h" 36#include "gmdocument.h"
37#include "gmrequest.h" 37#include "gmrequest.h"
38#include "gmutil.h" 38#include "gmutil.h"
39#include "gopher.h"
39#include "history.h" 40#include "history.h"
40#include "indicatorwidget.h" 41#include "indicatorwidget.h"
41#include "inputwidget.h" 42#include "inputwidget.h"
@@ -4315,20 +4316,31 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
4315 } 4316 }
4316 iString *parentUrl = collectNewRange_String((iRangecc){ constBegin_String(d->mod.url), 4317 iString *parentUrl = collectNewRange_String((iRangecc){ constBegin_String(d->mod.url),
4317 parts.path.end }); 4318 parts.path.end });
4318 if (equalCase_Rangecc(parts.scheme, "gopher")) { 4319 /* Always go to a gophermap. */
4319 /* Always go to a gophermap. */ 4320 setUrlItemType_Gopher(parentUrl, '1');
4320 iZap(parts); 4321 /* Hierarchical navigation doesn't make sense with Titan. */
4321 init_Url(&parts, parentUrl); 4322 if (startsWith_String(parentUrl, "titan://")) {
4322 if (parts.path.start && size_Range(&parts.path) >= 2) { 4323 /* We have no way of knowing if the corresponding URL is valid for Gemini,
4323 ((char *) parts.path.start)[1] = '1'; 4324 but let's try anyway. */
4324 } 4325 set_String(parentUrl, withScheme_String(parentUrl, "gemini"));
4326 stripUrlPort_String(parentUrl);
4325 } 4327 }
4326 postCommandf_Root(w->root, "open url:%s", cstr_String(parentUrl)); 4328 postCommandf_Root(w->root, "open url:%s", cstr_String(parentUrl));
4327 } 4329 }
4328 return iTrue; 4330 return iTrue;
4329 } 4331 }
4330 else if (equal_Command(cmd, "navigate.root") && document_App() == d) { 4332 else if (equal_Command(cmd, "navigate.root") && document_App() == d) {
4331 postCommandf_Root(w->root, "open url:%s/", cstr_Rangecc(urlRoot_String(d->mod.url))); 4333 iString *rootUrl = collectNewRange_String(urlRoot_String(d->mod.url));
4334 /* Always go to a gophermap. */
4335 setUrlItemType_Gopher(rootUrl, '1');
4336 /* Hierarchical navigation doesn't make sense with Titan. */
4337 if (startsWith_String(rootUrl, "titan://")) {
4338 /* We have no way of knowing if the corresponding URL is valid for Gemini,
4339 but let's try anyway. */
4340 set_String(rootUrl, withScheme_String(rootUrl, "gemini"));
4341 stripUrlPort_String(rootUrl);
4342 }
4343 postCommandf_Root(w->root, "open url:%s/", cstr_String(rootUrl));
4332 return iTrue; 4344 return iTrue;
4333 } 4345 }
4334 else if (equalWidget_Command(cmd, w, "scroll.moved")) { 4346 else if (equalWidget_Command(cmd, w, "scroll.moved")) {