xref: /freebsd/contrib/wpa/src/utils/browser.c (revision 4bc523382c7e72183c32be2c3aedecc1f5e844dd)
15b9c547cSRui Paulo /*
25b9c547cSRui Paulo  * Hotspot 2.0 client - Web browser using WebKit
35b9c547cSRui Paulo  * Copyright (c) 2013, Qualcomm Atheros, Inc.
45b9c547cSRui Paulo  *
55b9c547cSRui Paulo  * This software may be distributed under the terms of the BSD license.
65b9c547cSRui Paulo  * See README for more details.
75b9c547cSRui Paulo  */
85b9c547cSRui Paulo 
95b9c547cSRui Paulo #include "includes.h"
105b9c547cSRui Paulo #include <webkit/webkit.h>
115b9c547cSRui Paulo 
125b9c547cSRui Paulo #include "common.h"
135b9c547cSRui Paulo #include "browser.h"
145b9c547cSRui Paulo 
155b9c547cSRui Paulo 
165b9c547cSRui Paulo struct browser_context {
175b9c547cSRui Paulo 	GtkWidget *win;
185b9c547cSRui Paulo 	int success;
195b9c547cSRui Paulo 	int progress;
205b9c547cSRui Paulo 	char *hover_link;
215b9c547cSRui Paulo 	char *title;
225b9c547cSRui Paulo };
235b9c547cSRui Paulo 
245b9c547cSRui Paulo static void win_cb_destroy(GtkWidget *win, struct browser_context *ctx)
255b9c547cSRui Paulo {
265b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "BROWSER:%s", __func__);
275b9c547cSRui Paulo 	gtk_main_quit();
285b9c547cSRui Paulo }
295b9c547cSRui Paulo 
305b9c547cSRui Paulo 
315b9c547cSRui Paulo static void browser_update_title(struct browser_context *ctx)
325b9c547cSRui Paulo {
335b9c547cSRui Paulo 	char buf[100];
345b9c547cSRui Paulo 
355b9c547cSRui Paulo 	if (ctx->hover_link) {
365b9c547cSRui Paulo 		gtk_window_set_title(GTK_WINDOW(ctx->win), ctx->hover_link);
375b9c547cSRui Paulo 		return;
385b9c547cSRui Paulo 	}
395b9c547cSRui Paulo 
405b9c547cSRui Paulo 	if (ctx->progress == 100) {
415b9c547cSRui Paulo 		gtk_window_set_title(GTK_WINDOW(ctx->win),
425b9c547cSRui Paulo 				     ctx->title ? ctx->title :
435b9c547cSRui Paulo 				     "Hotspot 2.0 client");
445b9c547cSRui Paulo 		return;
455b9c547cSRui Paulo 	}
465b9c547cSRui Paulo 
475b9c547cSRui Paulo 	snprintf(buf, sizeof(buf), "[%d%%] %s", ctx->progress,
485b9c547cSRui Paulo 		 ctx->title ? ctx->title : "Hotspot 2.0 client");
495b9c547cSRui Paulo 	gtk_window_set_title(GTK_WINDOW(ctx->win), buf);
505b9c547cSRui Paulo }
515b9c547cSRui Paulo 
525b9c547cSRui Paulo 
535b9c547cSRui Paulo static void view_cb_notify_progress(WebKitWebView *view, GParamSpec *pspec,
545b9c547cSRui Paulo 				    struct browser_context *ctx)
555b9c547cSRui Paulo {
565b9c547cSRui Paulo 	ctx->progress = 100 * webkit_web_view_get_progress(view);
575b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "BROWSER:%s progress=%d", __func__,
585b9c547cSRui Paulo 		   ctx->progress);
595b9c547cSRui Paulo 	browser_update_title(ctx);
605b9c547cSRui Paulo }
615b9c547cSRui Paulo 
625b9c547cSRui Paulo 
635b9c547cSRui Paulo static void view_cb_notify_load_status(WebKitWebView *view, GParamSpec *pspec,
645b9c547cSRui Paulo 				       struct browser_context *ctx)
655b9c547cSRui Paulo {
665b9c547cSRui Paulo 	int status = webkit_web_view_get_load_status(view);
675b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "BROWSER:%s load-status=%d uri=%s",
685b9c547cSRui Paulo 		   __func__, status, webkit_web_view_get_uri(view));
695b9c547cSRui Paulo }
705b9c547cSRui Paulo 
715b9c547cSRui Paulo 
725b9c547cSRui Paulo static void view_cb_resource_request_starting(WebKitWebView *view,
735b9c547cSRui Paulo 					      WebKitWebFrame *frame,
745b9c547cSRui Paulo 					      WebKitWebResource *res,
755b9c547cSRui Paulo 					      WebKitNetworkRequest *req,
765b9c547cSRui Paulo 					      WebKitNetworkResponse *resp,
775b9c547cSRui Paulo 					      struct browser_context *ctx)
785b9c547cSRui Paulo {
795b9c547cSRui Paulo 	const gchar *uri = webkit_network_request_get_uri(req);
805b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri);
815b9c547cSRui Paulo 	if (g_str_has_suffix(uri, "/favicon.ico"))
825b9c547cSRui Paulo 		webkit_network_request_set_uri(req, "about:blank");
835b9c547cSRui Paulo 	if (g_str_has_prefix(uri, "osu://")) {
845b9c547cSRui Paulo 		ctx->success = atoi(uri + 6);
855b9c547cSRui Paulo 		gtk_main_quit();
865b9c547cSRui Paulo 	}
875b9c547cSRui Paulo 	if (g_str_has_prefix(uri, "http://localhost:12345")) {
885b9c547cSRui Paulo 		/*
895b9c547cSRui Paulo 		 * This is used as a special trigger to indicate that the
905b9c547cSRui Paulo 		 * user exchange has been completed.
915b9c547cSRui Paulo 		 */
925b9c547cSRui Paulo 		ctx->success = 1;
935b9c547cSRui Paulo 		gtk_main_quit();
945b9c547cSRui Paulo 	}
955b9c547cSRui Paulo }
965b9c547cSRui Paulo 
975b9c547cSRui Paulo 
985b9c547cSRui Paulo static gboolean view_cb_mime_type_policy_decision(
995b9c547cSRui Paulo 	WebKitWebView *view, WebKitWebFrame *frame, WebKitNetworkRequest *req,
1005b9c547cSRui Paulo 	gchar *mime, WebKitWebPolicyDecision *policy,
1015b9c547cSRui Paulo 	struct browser_context *ctx)
1025b9c547cSRui Paulo {
1035b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "BROWSER:%s mime=%s", __func__, mime);
1045b9c547cSRui Paulo 
1055b9c547cSRui Paulo 	if (!webkit_web_view_can_show_mime_type(view, mime)) {
1065b9c547cSRui Paulo 		webkit_web_policy_decision_download(policy);
1075b9c547cSRui Paulo 		return TRUE;
1085b9c547cSRui Paulo 	}
1095b9c547cSRui Paulo 
1105b9c547cSRui Paulo 	return FALSE;
1115b9c547cSRui Paulo }
1125b9c547cSRui Paulo 
1135b9c547cSRui Paulo 
1145b9c547cSRui Paulo static gboolean view_cb_download_requested(WebKitWebView *view,
1155b9c547cSRui Paulo 					   WebKitDownload *dl,
1165b9c547cSRui Paulo 					   struct browser_context *ctx)
1175b9c547cSRui Paulo {
1185b9c547cSRui Paulo 	const gchar *uri;
1195b9c547cSRui Paulo 	uri = webkit_download_get_uri(dl);
1205b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri);
1215b9c547cSRui Paulo 	return FALSE;
1225b9c547cSRui Paulo }
1235b9c547cSRui Paulo 
1245b9c547cSRui Paulo 
1255b9c547cSRui Paulo static void view_cb_hovering_over_link(WebKitWebView *view, gchar *title,
1265b9c547cSRui Paulo 				       gchar *uri, struct browser_context *ctx)
1275b9c547cSRui Paulo {
1285b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "BROWSER:%s title=%s uri=%s", __func__, title,
1295b9c547cSRui Paulo 		   uri);
1305b9c547cSRui Paulo 	os_free(ctx->hover_link);
1315b9c547cSRui Paulo 	if (uri)
1325b9c547cSRui Paulo 		ctx->hover_link = os_strdup(uri);
1335b9c547cSRui Paulo 	else
1345b9c547cSRui Paulo 		ctx->hover_link = NULL;
1355b9c547cSRui Paulo 
1365b9c547cSRui Paulo 	browser_update_title(ctx);
1375b9c547cSRui Paulo }
1385b9c547cSRui Paulo 
1395b9c547cSRui Paulo 
1405b9c547cSRui Paulo static void view_cb_title_changed(WebKitWebView *view, WebKitWebFrame *frame,
1415b9c547cSRui Paulo 				  const char *title,
1425b9c547cSRui Paulo 				  struct browser_context *ctx)
1435b9c547cSRui Paulo {
1445b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "BROWSER:%s title=%s", __func__, title);
1455b9c547cSRui Paulo 	os_free(ctx->title);
1465b9c547cSRui Paulo 	ctx->title = os_strdup(title);
1475b9c547cSRui Paulo 	browser_update_title(ctx);
1485b9c547cSRui Paulo }
1495b9c547cSRui Paulo 
1505b9c547cSRui Paulo 
1515b9c547cSRui Paulo int hs20_web_browser(const char *url)
1525b9c547cSRui Paulo {
1535b9c547cSRui Paulo 	GtkWidget *scroll;
1545b9c547cSRui Paulo 	SoupSession *s;
1555b9c547cSRui Paulo 	WebKitWebView *view;
1565b9c547cSRui Paulo 	WebKitWebSettings *settings;
1575b9c547cSRui Paulo 	struct browser_context ctx;
1585b9c547cSRui Paulo 
1595b9c547cSRui Paulo 	memset(&ctx, 0, sizeof(ctx));
1605b9c547cSRui Paulo 	if (!gtk_init_check(NULL, NULL))
1615b9c547cSRui Paulo 		return -1;
1625b9c547cSRui Paulo 
1635b9c547cSRui Paulo 	s = webkit_get_default_session();
1645b9c547cSRui Paulo 	g_object_set(G_OBJECT(s), "ssl-ca-file",
1655b9c547cSRui Paulo 		     "/etc/ssl/certs/ca-certificates.crt", NULL);
1665b9c547cSRui Paulo 	g_object_set(G_OBJECT(s), "ssl-strict", FALSE, NULL);
1675b9c547cSRui Paulo 
1685b9c547cSRui Paulo 	ctx.win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
169*4bc52338SCy Schubert 	gtk_window_set_role(GTK_WINDOW(ctx.win), "Hotspot 2.0 client");
1705b9c547cSRui Paulo 	gtk_window_set_default_size(GTK_WINDOW(ctx.win), 800, 600);
1715b9c547cSRui Paulo 
1725b9c547cSRui Paulo 	scroll = gtk_scrolled_window_new(NULL, NULL);
1735b9c547cSRui Paulo 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
1745b9c547cSRui Paulo 				       GTK_POLICY_NEVER, GTK_POLICY_NEVER);
1755b9c547cSRui Paulo 
1765b9c547cSRui Paulo 	g_signal_connect(G_OBJECT(ctx.win), "destroy",
1775b9c547cSRui Paulo 			 G_CALLBACK(win_cb_destroy), &ctx);
1785b9c547cSRui Paulo 
1795b9c547cSRui Paulo 	view = WEBKIT_WEB_VIEW(webkit_web_view_new());
1805b9c547cSRui Paulo 	g_signal_connect(G_OBJECT(view), "notify::progress",
1815b9c547cSRui Paulo 			 G_CALLBACK(view_cb_notify_progress), &ctx);
1825b9c547cSRui Paulo 	g_signal_connect(G_OBJECT(view), "notify::load-status",
1835b9c547cSRui Paulo 			 G_CALLBACK(view_cb_notify_load_status), &ctx);
1845b9c547cSRui Paulo 	g_signal_connect(G_OBJECT(view), "resource-request-starting",
1855b9c547cSRui Paulo 			 G_CALLBACK(view_cb_resource_request_starting), &ctx);
1865b9c547cSRui Paulo 	g_signal_connect(G_OBJECT(view), "mime-type-policy-decision-requested",
1875b9c547cSRui Paulo 			 G_CALLBACK(view_cb_mime_type_policy_decision), &ctx);
1885b9c547cSRui Paulo 	g_signal_connect(G_OBJECT(view), "download-requested",
1895b9c547cSRui Paulo 			 G_CALLBACK(view_cb_download_requested), &ctx);
1905b9c547cSRui Paulo 	g_signal_connect(G_OBJECT(view), "hovering-over-link",
1915b9c547cSRui Paulo 			 G_CALLBACK(view_cb_hovering_over_link), &ctx);
1925b9c547cSRui Paulo 	g_signal_connect(G_OBJECT(view), "title-changed",
1935b9c547cSRui Paulo 			 G_CALLBACK(view_cb_title_changed), &ctx);
1945b9c547cSRui Paulo 
1955b9c547cSRui Paulo 	gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(view));
1965b9c547cSRui Paulo 	gtk_container_add(GTK_CONTAINER(ctx.win), GTK_WIDGET(scroll));
1975b9c547cSRui Paulo 
1985b9c547cSRui Paulo 	gtk_widget_grab_focus(GTK_WIDGET(view));
1995b9c547cSRui Paulo 	gtk_widget_show_all(ctx.win);
2005b9c547cSRui Paulo 
2015b9c547cSRui Paulo 	settings = webkit_web_view_get_settings(view);
2025b9c547cSRui Paulo 	g_object_set(G_OBJECT(settings), "user-agent",
2035b9c547cSRui Paulo 		     "Mozilla/5.0 (X11; U; Unix; en-US) "
2045b9c547cSRui Paulo 		     "AppleWebKit/537.15 (KHTML, like Gecko) "
2055b9c547cSRui Paulo 		     "hs20-client/1.0", NULL);
2065b9c547cSRui Paulo 	g_object_set(G_OBJECT(settings), "auto-load-images", TRUE, NULL);
2075b9c547cSRui Paulo 
2085b9c547cSRui Paulo 	webkit_web_view_load_uri(view, url);
2095b9c547cSRui Paulo 
2105b9c547cSRui Paulo 	gtk_main();
2115b9c547cSRui Paulo 	gtk_widget_destroy(ctx.win);
2125b9c547cSRui Paulo 	while (gtk_events_pending())
2135b9c547cSRui Paulo 		gtk_main_iteration();
2145b9c547cSRui Paulo 
2155b9c547cSRui Paulo 	free(ctx.hover_link);
2165b9c547cSRui Paulo 	free(ctx.title);
2175b9c547cSRui Paulo 	return ctx.success;
2185b9c547cSRui Paulo }
219