diff options
Diffstat (limited to 'src/schemes/view-source.c')
-rw-r--r-- | src/schemes/view-source.c | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/src/schemes/view-source.c b/src/schemes/view-source.c new file mode 100644 index 0000000..b6cce86 --- /dev/null +++ b/src/schemes/view-source.c @@ -0,0 +1,150 @@ +/* + * view-source: URI scheme + * + * Copyright (C) 2017 Patrick McDermott + * + * This file is part of Marquee. + * + * Marquee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Marquee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Marquee. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "view-source.h" + +#include <string.h> + +#include <glib.h> +#include <webkit2/webkit2.h> + +#include "../application.h" +#include "../utils/resources.h" +#include "../utils/string.h" + +typedef struct { + WebKitURISchemeRequest *request; + gchar *uri; + gulong handler_id; +} DataSignalData; + +static const gchar *document = + "<!doctype html>\n" + "<html dir=\"%s\">\n" + "<head>\n" + "<meta charset=\"utf-8\">\n" + "<title>Source of %s</title>\n" + "<link rel=\"stylesheet\" type=\"text/css\" " + "media=\"all\" " + "href=\"view-source:resources/prism/" + "prism.css\">\n" + "<script src=\"view-source:resources/prism/" + "prism.js\"></script>\n" + "</head>\n" + "<body style=\"margin: 0;\">\n" + "<pre style=\"overflow: visible; width: 100%; " + "margin: 0;\">\n" + "<code class=\"language-markup line-numbers\" " + "style=\"overflow: visible;\">" + "%s</code>\n" + "</pre>\n" + "</body>\n" + "</html>\n"; + +static void +respond(WebKitURISchemeRequest *request, const gchar *uri, guchar *data, + gsize length) +{ + gchar *escaped_data; + GInputStream *stream; + + escaped_data = g_markup_escape_text((gchar *) data, length); + + stream = g_memory_input_stream_new_from_data( + g_strdup_printf(document, + gtk_widget_get_default_direction() == + GTK_TEXT_DIR_RTL ? "rtl" : "ltr", + uri, escaped_data), -1, g_free); + + webkit_uri_scheme_request_finish(request, stream, -1, "text/html"); + g_object_unref(stream); +} + +static void +data_cb(MqWebView *web_view, GParamSpec G_GNUC_UNUSED *param_spec, + DataSignalData *data_signal_data) +{ + guchar *data; + gsize length; + + data = mq_web_view_get_data(web_view, &length); + respond(data_signal_data->request, data_signal_data->uri, data, length); + g_signal_handler_disconnect(web_view, data_signal_data->handler_id); + g_free(data_signal_data->uri); + g_free(data_signal_data); +} + +void +mq_view_source_request(WebKitURISchemeRequest *request, + MqApplication *application) +{ + const gchar *path; + gchar *query_str; + GHashTable *query; + gint64 origin_tab_id; + gchar *uri; + MqTabPage *origin_tab; + MqWebView *origin_web_view; + guchar *data; + gsize length; + DataSignalData *data_signal_data; + + path = webkit_uri_scheme_request_get_path(request); + + if (g_str_has_prefix(path, "resources/")) { + mq_resource_response(application, path + sizeof("resources"), + request); + return; + } + + query_str = g_strdup(path); + query = mq_parse_query_string(query_str); + + /* TODO: Handle missing tab ID ("origin-tab=0"). */ + origin_tab_id = mq_atoi64(g_hash_table_lookup(query, "origin-tab")); + uri = g_strdup(g_hash_table_lookup(query, "uri")); + + g_hash_table_unref(query); + g_free(query_str); + + origin_tab = mq_application_get_tab(application, origin_tab_id); + + if (origin_tab) { + origin_web_view = mq_tab_page_get_web_view(origin_tab); + + data = mq_web_view_get_data(origin_web_view, &length); + if (data) { + respond(request, uri, data, length); + } else { + data_signal_data = g_new(DataSignalData, 1); + data_signal_data->request = request; + data_signal_data->uri = uri; + data_signal_data->handler_id = g_signal_connect( + origin_web_view, "notify::data", + G_CALLBACK(data_cb), data_signal_data); + } + } else { + /* TODO: Handling reloads by newly requesting the resource + * should obviate this. */ + respond(request, uri, + (guchar *) g_strdup("Viewed tab no longer open"), -1); + } +} |