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