diff options
-rw-r--r-- | res/about/version.gmi | 3 | ||||
-rw-r--r-- | src/app.c | 16 | ||||
-rw-r--r-- | src/gmrequest.c | 6 | ||||
-rw-r--r-- | src/gmutil.c | 36 | ||||
-rw-r--r-- | src/gmutil.h | 2 | ||||
-rw-r--r-- | src/prefs.c | 1 | ||||
-rw-r--r-- | src/prefs.h | 1 | ||||
-rw-r--r-- | src/ui/sidebarwidget.c | 9 | ||||
-rw-r--r-- | src/ui/util.c | 4 |
9 files changed, 73 insertions, 5 deletions
diff --git a/res/about/version.gmi b/res/about/version.gmi index 50ade298..42475e13 100644 --- a/res/about/version.gmi +++ b/res/about/version.gmi | |||
@@ -8,6 +8,9 @@ | |||
8 | 8 | ||
9 | ## 0.13 | 9 | ## 0.13 |
10 | * Support for Internationalized Domain Names (IDN) in network requests. | 10 | * Support for Internationalized Domain Names (IDN) in network requests. |
11 | * IDNs show up in decoded form in the UI. | ||
12 | * Percent-encoded Unicode characters in URL paths are decoded for the UI, and encoded in outgoing requests. | ||
13 | * Added option to disable decoding of percent-encoded paths. | ||
11 | * Quick search via URL bar shows entries from subscribed feeds. | 14 | * Quick search via URL bar shows entries from subscribed feeds. |
12 | * Added keybindings for zooming. | 15 | * Added keybindings for zooming. |
13 | * Improved usability of page content searching (${CTRL+}F, Escape). | 16 | * Improved usability of page content searching (${CTRL+}F, Escape). |
@@ -188,6 +188,7 @@ static iString *serializePrefs_App_(const iApp *d) { | |||
188 | appendFormat_String(str, "zoom.set arg:%d\n", d->prefs.zoomPercent); | 188 | appendFormat_String(str, "zoom.set arg:%d\n", d->prefs.zoomPercent); |
189 | appendFormat_String(str, "smoothscroll arg:%d\n", d->prefs.smoothScrolling); | 189 | appendFormat_String(str, "smoothscroll arg:%d\n", d->prefs.smoothScrolling); |
190 | appendFormat_String(str, "imageloadscroll arg:%d\n", d->prefs.loadImageInsteadOfScrolling); | 190 | appendFormat_String(str, "imageloadscroll arg:%d\n", d->prefs.loadImageInsteadOfScrolling); |
191 | appendFormat_String(str, "decodeurls arg:%d\n", d->prefs.decodeUserVisibleURLs); | ||
191 | appendFormat_String(str, "linewidth.set arg:%d\n", d->prefs.lineWidth); | 192 | appendFormat_String(str, "linewidth.set arg:%d\n", d->prefs.lineWidth); |
192 | appendFormat_String(str, "prefs.biglede.changed arg:%d\n", d->prefs.bigFirstParagraph); | 193 | appendFormat_String(str, "prefs.biglede.changed arg:%d\n", d->prefs.bigFirstParagraph); |
193 | appendFormat_String(str, "prefs.sideicon.changed arg:%d\n", d->prefs.sideIcon); | 194 | appendFormat_String(str, "prefs.sideicon.changed arg:%d\n", d->prefs.sideIcon); |
@@ -836,6 +837,8 @@ static iBool handlePrefsCommands_(iWidget *d, const char *cmd) { | |||
836 | isSelected_Widget(findChild_Widget(d, "prefs.imageloadscroll"))); | 837 | isSelected_Widget(findChild_Widget(d, "prefs.imageloadscroll"))); |
837 | postCommandf_App("ostheme arg:%d", | 838 | postCommandf_App("ostheme arg:%d", |
838 | isSelected_Widget(findChild_Widget(d, "prefs.ostheme"))); | 839 | isSelected_Widget(findChild_Widget(d, "prefs.ostheme"))); |
840 | postCommandf_App("decodeurls arg:%d", | ||
841 | isSelected_Widget(findChild_Widget(d, "prefs.decodeurls"))); | ||
839 | postCommandf_App("proxy.gemini address:%s", | 842 | postCommandf_App("proxy.gemini address:%s", |
840 | cstr_String(text_InputWidget(findChild_Widget(d, "prefs.proxy.gemini")))); | 843 | cstr_String(text_InputWidget(findChild_Widget(d, "prefs.proxy.gemini")))); |
841 | postCommandf_App("proxy.gopher address:%s", | 844 | postCommandf_App("proxy.gopher address:%s", |
@@ -1094,6 +1097,10 @@ iBool handleCommand_App(const char *cmd) { | |||
1094 | d->prefs.smoothScrolling = arg_Command(cmd); | 1097 | d->prefs.smoothScrolling = arg_Command(cmd); |
1095 | return iTrue; | 1098 | return iTrue; |
1096 | } | 1099 | } |
1100 | else if (equal_Command(cmd, "decodeurls")) { | ||
1101 | d->prefs.decodeUserVisibleURLs = arg_Command(cmd); | ||
1102 | return iTrue; | ||
1103 | } | ||
1097 | else if (equal_Command(cmd, "imageloadscroll")) { | 1104 | else if (equal_Command(cmd, "imageloadscroll")) { |
1098 | d->prefs.loadImageInsteadOfScrolling = arg_Command(cmd); | 1105 | d->prefs.loadImageInsteadOfScrolling = arg_Command(cmd); |
1099 | return iTrue; | 1106 | return iTrue; |
@@ -1184,7 +1191,7 @@ iBool handleCommand_App(const char *cmd) { | |||
1184 | return iTrue; | 1191 | return iTrue; |
1185 | } | 1192 | } |
1186 | else if (equal_Command(cmd, "open")) { | 1193 | else if (equal_Command(cmd, "open")) { |
1187 | const iString *url = collectNewCStr_String(suffixPtr_Command(cmd, "url")); | 1194 | iString *url = collectNewCStr_String(suffixPtr_Command(cmd, "url")); |
1188 | const iBool noProxy = argLabel_Command(cmd, "noproxy"); | 1195 | const iBool noProxy = argLabel_Command(cmd, "noproxy"); |
1189 | iUrl parts; | 1196 | iUrl parts; |
1190 | init_Url(&parts, url); | 1197 | init_Url(&parts, url); |
@@ -1214,6 +1221,12 @@ iBool handleCommand_App(const char *cmd) { | |||
1214 | setInitialScroll_DocumentWidget(doc, argfLabel_Command(cmd, "scroll")); | 1221 | setInitialScroll_DocumentWidget(doc, argfLabel_Command(cmd, "scroll")); |
1215 | setRedirectCount_DocumentWidget(doc, redirectCount); | 1222 | setRedirectCount_DocumentWidget(doc, redirectCount); |
1216 | setFlags_Widget(findWidget_App("document.progress"), hidden_WidgetFlag, iTrue); | 1223 | setFlags_Widget(findWidget_App("document.progress"), hidden_WidgetFlag, iTrue); |
1224 | if (prefs_App()->decodeUserVisibleURLs) { | ||
1225 | urlDecodePath_String(url); | ||
1226 | } | ||
1227 | else { | ||
1228 | urlEncodePath_String(url); | ||
1229 | } | ||
1217 | setUrlFromCache_DocumentWidget(doc, url, isHistory); | 1230 | setUrlFromCache_DocumentWidget(doc, url, isHistory); |
1218 | /* Optionally, jump to a text in the document. This will only work if the document | 1231 | /* Optionally, jump to a text in the document. This will only work if the document |
1219 | is already available, e.g., it's from "about:" or restored from cache. */ | 1232 | is already available, e.g., it's from "about:" or restored from cache. */ |
@@ -1332,6 +1345,7 @@ iBool handleCommand_App(const char *cmd) { | |||
1332 | dlg, format_CStr("prefs.saturation.%d", (int) (d->prefs.saturation * 3.99f))), | 1345 | dlg, format_CStr("prefs.saturation.%d", (int) (d->prefs.saturation * 3.99f))), |
1333 | selected_WidgetFlag, | 1346 | selected_WidgetFlag, |
1334 | iTrue); | 1347 | iTrue); |
1348 | setToggle_Widget(findChild_Widget(dlg, "prefs.decodeurls"), d->prefs.decodeUserVisibleURLs); | ||
1335 | setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.gemini"), &d->prefs.geminiProxy); | 1349 | setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.gemini"), &d->prefs.geminiProxy); |
1336 | setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.gopher"), &d->prefs.gopherProxy); | 1350 | setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.gopher"), &d->prefs.gopherProxy); |
1337 | setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.http"), &d->prefs.httpProxy); | 1351 | setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.http"), &d->prefs.httpProxy); |
diff --git a/src/gmrequest.c b/src/gmrequest.c index 991485bc..1f922142 100644 --- a/src/gmrequest.c +++ b/src/gmrequest.c | |||
@@ -482,8 +482,6 @@ void deinit_GmRequest(iGmRequest *d) { | |||
482 | deinit_Gopher(&d->gopher); | 482 | deinit_Gopher(&d->gopher); |
483 | delete_Audience(d->finished); | 483 | delete_Audience(d->finished); |
484 | delete_Audience(d->updated); | 484 | delete_Audience(d->updated); |
485 | // delete_GmResponse(d->respPub); | ||
486 | // deinit_GmResponse(&d->respInt); | ||
487 | delete_GmResponse(d->resp); | 485 | delete_GmResponse(d->resp); |
488 | deinit_String(&d->url); | 486 | deinit_String(&d->url); |
489 | delete_Mutex(d->mtx); | 487 | delete_Mutex(d->mtx); |
@@ -494,6 +492,10 @@ void setUrl_GmRequest(iGmRequest *d, const iString *url) { | |||
494 | /* Encode hostname to Punycode here because we want to submit the Punycode domain name | 492 | /* Encode hostname to Punycode here because we want to submit the Punycode domain name |
495 | in the request. (TODO: Pending possible Gemini spec change.) */ | 493 | in the request. (TODO: Pending possible Gemini spec change.) */ |
496 | punyEncodeUrlHost_String(&d->url); | 494 | punyEncodeUrlHost_String(&d->url); |
495 | /* TODO: Gemini spec allows UTF-8 encoded URLs, but still need to percent-encode non-ASCII | ||
496 | characters? Could be a server-side issue, e.g., if they're using a URL parser meant for | ||
497 | the web. */ | ||
498 | urlEncodePath_String(&d->url); | ||
497 | urlEncodeSpaces_String(&d->url); | 499 | urlEncodeSpaces_String(&d->url); |
498 | } | 500 | } |
499 | 501 | ||
diff --git a/src/gmutil.c b/src/gmutil.c index 68525be9..afca4978 100644 --- a/src/gmutil.c +++ b/src/gmutil.c | |||
@@ -151,6 +151,42 @@ static iString *punyDecodeHost_(iRangecc host) { | |||
151 | return result; | 151 | return result; |
152 | } | 152 | } |
153 | 153 | ||
154 | void urlDecodePath_String(iString *d) { | ||
155 | iUrl url; | ||
156 | init_Url(&url, d); | ||
157 | if (isEmpty_Range(&url.path)) { | ||
158 | return; | ||
159 | } | ||
160 | iString *decoded = new_String(); | ||
161 | appendRange_String(decoded, (iRangecc){ constBegin_String(d), url.path.start }); | ||
162 | iString *path = newRange_String(url.path); | ||
163 | iString *decPath = urlDecode_String(path); | ||
164 | append_String(decoded, decPath); | ||
165 | delete_String(decPath); | ||
166 | delete_String(path); | ||
167 | appendRange_String(decoded, (iRangecc){ url.path.end, constEnd_String(d) }); | ||
168 | set_String(d, decoded); | ||
169 | delete_String(decoded); | ||
170 | } | ||
171 | |||
172 | void urlEncodePath_String(iString *d) { | ||
173 | iUrl url; | ||
174 | init_Url(&url, d); | ||
175 | if (isEmpty_Range(&url.path)) { | ||
176 | return; | ||
177 | } | ||
178 | iString *encoded = new_String(); | ||
179 | appendRange_String(encoded , (iRangecc){ constBegin_String(d), url.path.start }); | ||
180 | iString *path = newRange_String(url.path); | ||
181 | iString *encPath = urlEncodeExclude_String(path, "%/ "); | ||
182 | append_String(encoded, encPath); | ||
183 | delete_String(encPath); | ||
184 | delete_String(path); | ||
185 | appendRange_String(encoded, (iRangecc){ url.path.end, constEnd_String(d) }); | ||
186 | set_String(d, encoded); | ||
187 | delete_String(encoded); | ||
188 | } | ||
189 | |||
154 | const iString *absoluteUrl_String(const iString *d, const iString *urlMaybeRelative) { | 190 | const iString *absoluteUrl_String(const iString *d, const iString *urlMaybeRelative) { |
155 | iUrl orig; | 191 | iUrl orig; |
156 | iUrl rel; | 192 | iUrl rel; |
diff --git a/src/gmutil.h b/src/gmutil.h index bbadbafd..88ed1f32 100644 --- a/src/gmutil.h +++ b/src/gmutil.h | |||
@@ -104,6 +104,8 @@ iRangecc urlScheme_String (const iString *); | |||
104 | iRangecc urlHost_String (const iString *); | 104 | iRangecc urlHost_String (const iString *); |
105 | const iString * absoluteUrl_String (const iString *, const iString *urlMaybeRelative); | 105 | const iString * absoluteUrl_String (const iString *, const iString *urlMaybeRelative); |
106 | void punyEncodeUrlHost_String(iString *); | 106 | void punyEncodeUrlHost_String(iString *); |
107 | void urlDecodePath_String (iString *); | ||
108 | void urlEncodePath_String (iString *); | ||
107 | iString * makeFileUrl_String (const iString *localFilePath); | 109 | iString * makeFileUrl_String (const iString *localFilePath); |
108 | const char * makeFileUrl_CStr (const char *localFilePath); | 110 | const char * makeFileUrl_CStr (const char *localFilePath); |
109 | void urlEncodeSpaces_String (iString *); | 111 | void urlEncodeSpaces_String (iString *); |
diff --git a/src/prefs.c b/src/prefs.c index 574e07d0..31ffe03b 100644 --- a/src/prefs.c +++ b/src/prefs.c | |||
@@ -33,6 +33,7 @@ void init_Prefs(iPrefs *d) { | |||
33 | d->hoverOutline = iFalse; | 33 | d->hoverOutline = iFalse; |
34 | d->smoothScrolling = iTrue; | 34 | d->smoothScrolling = iTrue; |
35 | d->loadImageInsteadOfScrolling = iFalse; | 35 | d->loadImageInsteadOfScrolling = iFalse; |
36 | d->decodeUserVisibleURLs = iTrue; | ||
36 | d->font = nunito_TextFont; | 37 | d->font = nunito_TextFont; |
37 | d->headingFont = nunito_TextFont; | 38 | d->headingFont = nunito_TextFont; |
38 | d->monospaceGemini = iFalse; | 39 | d->monospaceGemini = iFalse; |
diff --git a/src/prefs.h b/src/prefs.h index 3f4f534f..e95a32da 100644 --- a/src/prefs.h +++ b/src/prefs.h | |||
@@ -48,6 +48,7 @@ struct Impl_Prefs { | |||
48 | iBool smoothScrolling; | 48 | iBool smoothScrolling; |
49 | iBool loadImageInsteadOfScrolling; | 49 | iBool loadImageInsteadOfScrolling; |
50 | /* Network */ | 50 | /* Network */ |
51 | iBool decodeUserVisibleURLs; | ||
51 | iString geminiProxy; | 52 | iString geminiProxy; |
52 | iString gopherProxy; | 53 | iString gopherProxy; |
53 | iString httpProxy; | 54 | iString httpProxy; |
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 8024b240..1167ebe3 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c | |||
@@ -240,6 +240,13 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { | |||
240 | const iVisitedUrl *visit = i.ptr; | 240 | const iVisitedUrl *visit = i.ptr; |
241 | iSidebarItem *item = new_SidebarItem(); | 241 | iSidebarItem *item = new_SidebarItem(); |
242 | set_String(&item->url, &visit->url); | 242 | set_String(&item->url, &visit->url); |
243 | set_String(&item->label, &visit->url); | ||
244 | if (prefs_App()->decodeUserVisibleURLs) { | ||
245 | urlDecodePath_String(&item->label); | ||
246 | } | ||
247 | else { | ||
248 | urlEncodePath_String(&item->label); | ||
249 | } | ||
243 | iDate date; | 250 | iDate date; |
244 | init_Date(&date, &visit->when); | 251 | init_Date(&date, &visit->when); |
245 | if (date.day != on.day || date.month != on.month || date.year != on.year) { | 252 | if (date.day != on.day || date.month != on.month || date.year != on.year) { |
@@ -1211,7 +1218,7 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect, | |||
1211 | } | 1218 | } |
1212 | else { | 1219 | else { |
1213 | iUrl parts; | 1220 | iUrl parts; |
1214 | init_Url(&parts, &d->url); | 1221 | init_Url(&parts, &d->label); |
1215 | const iBool isAbout = equalCase_Rangecc(parts.scheme, "about"); | 1222 | const iBool isAbout = equalCase_Rangecc(parts.scheme, "about"); |
1216 | const iBool isGemini = equalCase_Rangecc(parts.scheme, "gemini"); | 1223 | const iBool isGemini = equalCase_Rangecc(parts.scheme, "gemini"); |
1217 | draw_Text(font, | 1224 | draw_Text(font, |
diff --git a/src/ui/util.c b/src/ui/util.c index 1ad3f30e..6c9d75dc 100644 --- a/src/ui/util.c +++ b/src/ui/util.c | |||
@@ -1136,7 +1136,9 @@ iWidget *makePreferences_Widget(void) { | |||
1136 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.biglede"))); | 1136 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.biglede"))); |
1137 | } | 1137 | } |
1138 | /* Proxies. */ { | 1138 | /* Proxies. */ { |
1139 | appendTwoColumnPage_(tabs, "Proxies", '5', &headings, &values); | 1139 | appendTwoColumnPage_(tabs, "Network", '5', &headings, &values); |
1140 | addChild_Widget(headings, iClob(makeHeading_Widget("Decode paths:"))); | ||
1141 | addChild_Widget(values, iClob(makeToggle_Widget("prefs.decodeurls"))); | ||
1140 | addChild_Widget(headings, iClob(makeHeading_Widget("Gemini proxy:"))); | 1142 | addChild_Widget(headings, iClob(makeHeading_Widget("Gemini proxy:"))); |
1141 | setId_Widget(addChild_Widget(values, iClob(new_InputWidget(0))), "prefs.proxy.gemini"); | 1143 | setId_Widget(addChild_Widget(values, iClob(new_InputWidget(0))), "prefs.proxy.gemini"); |
1142 | addChild_Widget(headings, iClob(makeHeading_Widget("Gopher proxy:"))); | 1144 | addChild_Widget(headings, iClob(makeHeading_Widget("Gopher proxy:"))); |