xref: /freebsd/contrib/wpa/src/utils/browser.c (revision 5b9c547c072b84410b50897cc53710c75b2f6b74)
1*5b9c547cSRui Paulo /*
2*5b9c547cSRui Paulo  * Hotspot 2.0 client - Web browser using WebKit
3*5b9c547cSRui Paulo  * Copyright (c) 2013, Qualcomm Atheros, Inc.
4*5b9c547cSRui Paulo  *
5*5b9c547cSRui Paulo  * This software may be distributed under the terms of the BSD license.
6*5b9c547cSRui Paulo  * See README for more details.
7*5b9c547cSRui Paulo  */
8*5b9c547cSRui Paulo 
9*5b9c547cSRui Paulo #include "includes.h"
10*5b9c547cSRui Paulo #include <webkit/webkit.h>
11*5b9c547cSRui Paulo 
12*5b9c547cSRui Paulo #include "common.h"
13*5b9c547cSRui Paulo #include "browser.h"
14*5b9c547cSRui Paulo 
15*5b9c547cSRui Paulo 
16*5b9c547cSRui Paulo struct browser_context {
17*5b9c547cSRui Paulo 	GtkWidget *win;
18*5b9c547cSRui Paulo 	int success;
19*5b9c547cSRui Paulo 	int progress;
20*5b9c547cSRui Paulo 	char *hover_link;
21*5b9c547cSRui Paulo 	char *title;
22*5b9c547cSRui Paulo };
23*5b9c547cSRui Paulo 
24*5b9c547cSRui Paulo static void win_cb_destroy(GtkWidget *win, struct browser_context *ctx)
25*5b9c547cSRui Paulo {
26*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "BROWSER:%s", __func__);
27*5b9c547cSRui Paulo 	gtk_main_quit();
28*5b9c547cSRui Paulo }
29*5b9c547cSRui Paulo 
30*5b9c547cSRui Paulo 
31*5b9c547cSRui Paulo static void browser_update_title(struct browser_context *ctx)
32*5b9c547cSRui Paulo {
33*5b9c547cSRui Paulo 	char buf[100];
34*5b9c547cSRui Paulo 
35*5b9c547cSRui Paulo 	if (ctx->hover_link) {
36*5b9c547cSRui Paulo 		gtk_window_set_title(GTK_WINDOW(ctx->win), ctx->hover_link);
37*5b9c547cSRui Paulo 		return;
38*5b9c547cSRui Paulo 	}
39*5b9c547cSRui Paulo 
40*5b9c547cSRui Paulo 	if (ctx->progress == 100) {
41*5b9c547cSRui Paulo 		gtk_window_set_title(GTK_WINDOW(ctx->win),
42*5b9c547cSRui Paulo 				     ctx->title ? ctx->title :
43*5b9c547cSRui Paulo 				     "Hotspot 2.0 client");
44*5b9c547cSRui Paulo 		return;
45*5b9c547cSRui Paulo 	}
46*5b9c547cSRui Paulo 
47*5b9c547cSRui Paulo 	snprintf(buf, sizeof(buf), "[%d%%] %s", ctx->progress,
48*5b9c547cSRui Paulo 		 ctx->title ? ctx->title : "Hotspot 2.0 client");
49*5b9c547cSRui Paulo 	gtk_window_set_title(GTK_WINDOW(ctx->win), buf);
50*5b9c547cSRui Paulo }
51*5b9c547cSRui Paulo 
52*5b9c547cSRui Paulo 
53*5b9c547cSRui Paulo static void view_cb_notify_progress(WebKitWebView *view, GParamSpec *pspec,
54*5b9c547cSRui Paulo 				    struct browser_context *ctx)
55*5b9c547cSRui Paulo {
56*5b9c547cSRui Paulo 	ctx->progress = 100 * webkit_web_view_get_progress(view);
57*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "BROWSER:%s progress=%d", __func__,
58*5b9c547cSRui Paulo 		   ctx->progress);
59*5b9c547cSRui Paulo 	browser_update_title(ctx);
60*5b9c547cSRui Paulo }
61*5b9c547cSRui Paulo 
62*5b9c547cSRui Paulo 
63*5b9c547cSRui Paulo static void view_cb_notify_load_status(WebKitWebView *view, GParamSpec *pspec,
64*5b9c547cSRui Paulo 				       struct browser_context *ctx)
65*5b9c547cSRui Paulo {
66*5b9c547cSRui Paulo 	int status = webkit_web_view_get_load_status(view);
67*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "BROWSER:%s load-status=%d uri=%s",
68*5b9c547cSRui Paulo 		   __func__, status, webkit_web_view_get_uri(view));
69*5b9c547cSRui Paulo }
70*5b9c547cSRui Paulo 
71*5b9c547cSRui Paulo 
72*5b9c547cSRui Paulo static void view_cb_resource_request_starting(WebKitWebView *view,
73*5b9c547cSRui Paulo 					      WebKitWebFrame *frame,
74*5b9c547cSRui Paulo 					      WebKitWebResource *res,
75*5b9c547cSRui Paulo 					      WebKitNetworkRequest *req,
76*5b9c547cSRui Paulo 					      WebKitNetworkResponse *resp,
77*5b9c547cSRui Paulo 					      struct browser_context *ctx)
78*5b9c547cSRui Paulo {
79*5b9c547cSRui Paulo 	const gchar *uri = webkit_network_request_get_uri(req);
80*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri);
81*5b9c547cSRui Paulo 	if (g_str_has_suffix(uri, "/favicon.ico"))
82*5b9c547cSRui Paulo 		webkit_network_request_set_uri(req, "about:blank");
83*5b9c547cSRui Paulo 	if (g_str_has_prefix(uri, "osu://")) {
84*5b9c547cSRui Paulo 		ctx->success = atoi(uri + 6);
85*5b9c547cSRui Paulo 		gtk_main_quit();
86*5b9c547cSRui Paulo 	}
87*5b9c547cSRui Paulo 	if (g_str_has_prefix(uri, "http://localhost:12345")) {
88*5b9c547cSRui Paulo 		/*
89*5b9c547cSRui Paulo 		 * This is used as a special trigger to indicate that the
90*5b9c547cSRui Paulo 		 * user exchange has been completed.
91*5b9c547cSRui Paulo 		 */
92*5b9c547cSRui Paulo 		ctx->success = 1;
93*5b9c547cSRui Paulo 		gtk_main_quit();
94*5b9c547cSRui Paulo 	}
95*5b9c547cSRui Paulo }
96*5b9c547cSRui Paulo 
97*5b9c547cSRui Paulo 
98*5b9c547cSRui Paulo static gboolean view_cb_mime_type_policy_decision(
99*5b9c547cSRui Paulo 	WebKitWebView *view, WebKitWebFrame *frame, WebKitNetworkRequest *req,
100*5b9c547cSRui Paulo 	gchar *mime, WebKitWebPolicyDecision *policy,
101*5b9c547cSRui Paulo 	struct browser_context *ctx)
102*5b9c547cSRui Paulo {
103*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "BROWSER:%s mime=%s", __func__, mime);
104*5b9c547cSRui Paulo 
105*5b9c547cSRui Paulo 	if (!webkit_web_view_can_show_mime_type(view, mime)) {
106*5b9c547cSRui Paulo 		webkit_web_policy_decision_download(policy);
107*5b9c547cSRui Paulo 		return TRUE;
108*5b9c547cSRui Paulo 	}
109*5b9c547cSRui Paulo 
110*5b9c547cSRui Paulo 	return FALSE;
111*5b9c547cSRui Paulo }
112*5b9c547cSRui Paulo 
113*5b9c547cSRui Paulo 
114*5b9c547cSRui Paulo static gboolean view_cb_download_requested(WebKitWebView *view,
115*5b9c547cSRui Paulo 					   WebKitDownload *dl,
116*5b9c547cSRui Paulo 					   struct browser_context *ctx)
117*5b9c547cSRui Paulo {
118*5b9c547cSRui Paulo 	const gchar *uri;
119*5b9c547cSRui Paulo 	uri = webkit_download_get_uri(dl);
120*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri);
121*5b9c547cSRui Paulo 	return FALSE;
122*5b9c547cSRui Paulo }
123*5b9c547cSRui Paulo 
124*5b9c547cSRui Paulo 
125*5b9c547cSRui Paulo static void view_cb_hovering_over_link(WebKitWebView *view, gchar *title,
126*5b9c547cSRui Paulo 				       gchar *uri, struct browser_context *ctx)
127*5b9c547cSRui Paulo {
128*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "BROWSER:%s title=%s uri=%s", __func__, title,
129*5b9c547cSRui Paulo 		   uri);
130*5b9c547cSRui Paulo 	os_free(ctx->hover_link);
131*5b9c547cSRui Paulo 	if (uri)
132*5b9c547cSRui Paulo 		ctx->hover_link = os_strdup(uri);
133*5b9c547cSRui Paulo 	else
134*5b9c547cSRui Paulo 		ctx->hover_link = NULL;
135*5b9c547cSRui Paulo 
136*5b9c547cSRui Paulo 	browser_update_title(ctx);
137*5b9c547cSRui Paulo }
138*5b9c547cSRui Paulo 
139*5b9c547cSRui Paulo 
140*5b9c547cSRui Paulo static void view_cb_title_changed(WebKitWebView *view, WebKitWebFrame *frame,
141*5b9c547cSRui Paulo 				  const char *title,
142*5b9c547cSRui Paulo 				  struct browser_context *ctx)
143*5b9c547cSRui Paulo {
144*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "BROWSER:%s title=%s", __func__, title);
145*5b9c547cSRui Paulo 	os_free(ctx->title);
146*5b9c547cSRui Paulo 	ctx->title = os_strdup(title);
147*5b9c547cSRui Paulo 	browser_update_title(ctx);
148*5b9c547cSRui Paulo }
149*5b9c547cSRui Paulo 
150*5b9c547cSRui Paulo 
151*5b9c547cSRui Paulo int hs20_web_browser(const char *url)
152*5b9c547cSRui Paulo {
153*5b9c547cSRui Paulo 	GtkWidget *scroll;
154*5b9c547cSRui Paulo 	SoupSession *s;
155*5b9c547cSRui Paulo 	WebKitWebView *view;
156*5b9c547cSRui Paulo 	WebKitWebSettings *settings;
157*5b9c547cSRui Paulo 	struct browser_context ctx;
158*5b9c547cSRui Paulo 
159*5b9c547cSRui Paulo 	memset(&ctx, 0, sizeof(ctx));
160*5b9c547cSRui Paulo 	if (!gtk_init_check(NULL, NULL))
161*5b9c547cSRui Paulo 		return -1;
162*5b9c547cSRui Paulo 
163*5b9c547cSRui Paulo 	s = webkit_get_default_session();
164*5b9c547cSRui Paulo 	g_object_set(G_OBJECT(s), "ssl-ca-file",
165*5b9c547cSRui Paulo 		     "/etc/ssl/certs/ca-certificates.crt", NULL);
166*5b9c547cSRui Paulo 	g_object_set(G_OBJECT(s), "ssl-strict", FALSE, NULL);
167*5b9c547cSRui Paulo 
168*5b9c547cSRui Paulo 	ctx.win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
169*5b9c547cSRui Paulo 	gtk_window_set_wmclass(GTK_WINDOW(ctx.win), "Hotspot 2.0 client",
170*5b9c547cSRui Paulo 			       "Hotspot 2.0 client");
171*5b9c547cSRui Paulo 	gtk_window_set_default_size(GTK_WINDOW(ctx.win), 800, 600);
172*5b9c547cSRui Paulo 
173*5b9c547cSRui Paulo 	scroll = gtk_scrolled_window_new(NULL, NULL);
174*5b9c547cSRui Paulo 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
175*5b9c547cSRui Paulo 				       GTK_POLICY_NEVER, GTK_POLICY_NEVER);
176*5b9c547cSRui Paulo 
177*5b9c547cSRui Paulo 	g_signal_connect(G_OBJECT(ctx.win), "destroy",
178*5b9c547cSRui Paulo 			 G_CALLBACK(win_cb_destroy), &ctx);
179*5b9c547cSRui Paulo 
180*5b9c547cSRui Paulo 	view = WEBKIT_WEB_VIEW(webkit_web_view_new());
181*5b9c547cSRui Paulo 	g_signal_connect(G_OBJECT(view), "notify::progress",
182*5b9c547cSRui Paulo 			 G_CALLBACK(view_cb_notify_progress), &ctx);
183*5b9c547cSRui Paulo 	g_signal_connect(G_OBJECT(view), "notify::load-status",
184*5b9c547cSRui Paulo 			 G_CALLBACK(view_cb_notify_load_status), &ctx);
185*5b9c547cSRui Paulo 	g_signal_connect(G_OBJECT(view), "resource-request-starting",
186*5b9c547cSRui Paulo 			 G_CALLBACK(view_cb_resource_request_starting), &ctx);
187*5b9c547cSRui Paulo 	g_signal_connect(G_OBJECT(view), "mime-type-policy-decision-requested",
188*5b9c547cSRui Paulo 			 G_CALLBACK(view_cb_mime_type_policy_decision), &ctx);
189*5b9c547cSRui Paulo 	g_signal_connect(G_OBJECT(view), "download-requested",
190*5b9c547cSRui Paulo 			 G_CALLBACK(view_cb_download_requested), &ctx);
191*5b9c547cSRui Paulo 	g_signal_connect(G_OBJECT(view), "hovering-over-link",
192*5b9c547cSRui Paulo 			 G_CALLBACK(view_cb_hovering_over_link), &ctx);
193*5b9c547cSRui Paulo 	g_signal_connect(G_OBJECT(view), "title-changed",
194*5b9c547cSRui Paulo 			 G_CALLBACK(view_cb_title_changed), &ctx);
195*5b9c547cSRui Paulo 
196*5b9c547cSRui Paulo 	gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(view));
197*5b9c547cSRui Paulo 	gtk_container_add(GTK_CONTAINER(ctx.win), GTK_WIDGET(scroll));
198*5b9c547cSRui Paulo 
199*5b9c547cSRui Paulo 	gtk_widget_grab_focus(GTK_WIDGET(view));
200*5b9c547cSRui Paulo 	gtk_widget_show_all(ctx.win);
201*5b9c547cSRui Paulo 
202*5b9c547cSRui Paulo 	settings = webkit_web_view_get_settings(view);
203*5b9c547cSRui Paulo 	g_object_set(G_OBJECT(settings), "user-agent",
204*5b9c547cSRui Paulo 		     "Mozilla/5.0 (X11; U; Unix; en-US) "
205*5b9c547cSRui Paulo 		     "AppleWebKit/537.15 (KHTML, like Gecko) "
206*5b9c547cSRui Paulo 		     "hs20-client/1.0", NULL);
207*5b9c547cSRui Paulo 	g_object_set(G_OBJECT(settings), "auto-load-images", TRUE, NULL);
208*5b9c547cSRui Paulo 
209*5b9c547cSRui Paulo 	webkit_web_view_load_uri(view, url);
210*5b9c547cSRui Paulo 
211*5b9c547cSRui Paulo 	gtk_main();
212*5b9c547cSRui Paulo 	gtk_widget_destroy(ctx.win);
213*5b9c547cSRui Paulo 	while (gtk_events_pending())
214*5b9c547cSRui Paulo 		gtk_main_iteration();
215*5b9c547cSRui Paulo 
216*5b9c547cSRui Paulo 	free(ctx.hover_link);
217*5b9c547cSRui Paulo 	free(ctx.title);
218*5b9c547cSRui Paulo 	return ctx.success;
219*5b9c547cSRui Paulo }
220