From 3ff5371635ae392034ad3905fa03e814dabda98e Mon Sep 17 00:00:00 2001
From: Daniel Friesel <derf@finalrewind.org>
Date: Sun, 24 Jan 2021 05:44:17 +0100
Subject: Handle URL-encoded components in "feh --start-at file://...."

Closes #584
---
 src/filelist.c | 28 ++++++++++++++++++++++++++++
 src/filelist.h |  1 +
 src/options.c  | 21 ++++++++++++++++++---
 3 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/src/filelist.c b/src/filelist.c
index ae8d7b2..9d8b38a 100644
--- a/src/filelist.c
+++ b/src/filelist.c
@@ -28,6 +28,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include <libexif/exif-data.h>
 #endif
 
+#ifdef HAVE_LIBCURL
+#include <curl/curl.h>
+#endif
+
 #include "feh.h"
 #include "filelist.h"
 #include "signals.h"
@@ -678,3 +682,27 @@ void feh_save_filelist()
 	free(tmpname);
 	return;
 }
+
+#ifdef HAVE_LIBCURL
+
+char *feh_http_unescape(char *url)
+{
+	CURL *curl = curl_easy_init();
+	if (!curl) {
+		return NULL;
+	}
+	char *tmp_url = curl_easy_unescape(curl, url, 0, NULL);
+	char *new_url = estrdup(tmp_url);
+	curl_free(tmp_url);
+	curl_easy_cleanup(curl);
+	return new_url;
+}
+
+#else
+
+char *feh_http_unescape(char *url)
+{
+	return NULL;
+}
+
+#endif
diff --git a/src/filelist.h b/src/filelist.h
index e24a6a6..ff0645e 100644
--- a/src/filelist.h
+++ b/src/filelist.h
@@ -97,6 +97,7 @@ gib_list *feh_read_filelist(char *filename);
 char *feh_absolute_path(char *path);
 gib_list *feh_file_remove_from_list(gib_list * list, gib_list * l);
 void feh_save_filelist();
+char *feh_http_unescape(char * url);
 
 int feh_cmp_name(void *file1, void *file2);
 int feh_cmp_dirname(void *file1, void *file2);
diff --git a/src/options.c b/src/options.c
index 0bc1a5e..4744bb0 100644
--- a/src/options.c
+++ b/src/options.c
@@ -859,11 +859,26 @@ static void feh_parse_option_array(int argc, char **argv, int finalrun)
 		 */
 		if (opt.start_list_at && path_is_url(opt.start_list_at) && (strlen(opt.start_list_at) <= 8 || strncmp(opt.start_list_at, "file:///", 8) != 0)) {
 			add_file_to_filelist_recursively(opt.start_list_at, FILELIST_FIRST);
+		/*
+		 * Otherwise, make "feh --start-at dir/file.jpg" behave like
+		 * "feh --start-at dir/file.jpg dir".
+		 */
 		} else if (opt.start_list_at && strrchr(opt.start_list_at, '/')) {
+			/*
+			 * feh can't candle urlencoded path components ("some%20dir" etc).
+			 * Use libcurl to unescape them if --start-at is file://...
+			 */
 			if (strlen(opt.start_list_at) > 8 && strncmp(opt.start_list_at, "file:///", 8) == 0) {
-				char *start_at_path = estrdup(opt.start_list_at + 7);
-				free(opt.start_list_at);
-				opt.start_list_at = start_at_path;
+				char *unescaped_path = feh_http_unescape(opt.start_list_at);
+				if (unescaped_path != NULL) {
+					free(opt.start_list_at);
+					opt.start_list_at = estrdup(unescaped_path + 7);
+					free(unescaped_path);
+				} else {
+					char *new_path = estrdup(opt.start_list_at + 7);
+					free(opt.start_list_at);
+					opt.start_list_at = new_path;
+				}
 			}
 			char *target_directory = estrdup(opt.start_list_at);
 			char *filename_start = strrchr(target_directory, '/');
-- 
cgit v1.2.3