]> git.ipfire.org Git - thirdparty/hostap.git/blob - src/utils/browser.c
43d47dca3a2a79321a39a979e431e707f71848a7
[thirdparty/hostap.git] / src / utils / browser.c
1 /*
2 * Hotspot 2.0 client - Web browser using WebKit
3 * Copyright (c) 2013, Qualcomm Atheros, Inc.
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9 #include "includes.h"
10 #ifdef USE_WEBKIT2
11 #include <webkit2/webkit2.h>
12 #else /* USE_WEBKIT2 */
13 #include <webkit/webkit.h>
14 #endif /* USE_WEBKIT2 */
15
16 #include "common.h"
17 #include "browser.h"
18
19
20 struct browser_context {
21 GtkWidget *win;
22 int success;
23 int progress;
24 char *hover_link;
25 char *title;
26 };
27
28 static void win_cb_destroy(GtkWidget *win, struct browser_context *ctx)
29 {
30 wpa_printf(MSG_DEBUG, "BROWSER:%s", __func__);
31 gtk_main_quit();
32 }
33
34
35 static void browser_update_title(struct browser_context *ctx)
36 {
37 char buf[100];
38
39 if (ctx->hover_link) {
40 gtk_window_set_title(GTK_WINDOW(ctx->win), ctx->hover_link);
41 return;
42 }
43
44 if (ctx->progress == 100) {
45 gtk_window_set_title(GTK_WINDOW(ctx->win),
46 ctx->title ? ctx->title :
47 "Hotspot 2.0 client");
48 return;
49 }
50
51 snprintf(buf, sizeof(buf), "[%d%%] %s", ctx->progress,
52 ctx->title ? ctx->title : "Hotspot 2.0 client");
53 gtk_window_set_title(GTK_WINDOW(ctx->win), buf);
54 }
55
56
57 static void view_cb_notify_progress(WebKitWebView *view, GParamSpec *pspec,
58 struct browser_context *ctx)
59 {
60 #ifdef USE_WEBKIT2
61 ctx->progress = 100 * webkit_web_view_get_estimated_load_progress(view);
62 #else /* USE_WEBKIT2 */
63 ctx->progress = 100 * webkit_web_view_get_progress(view);
64 #endif /* USE_WEBKIT2 */
65 wpa_printf(MSG_DEBUG, "BROWSER:%s progress=%d", __func__,
66 ctx->progress);
67 browser_update_title(ctx);
68 }
69
70
71 static void view_cb_notify_load_status(WebKitWebView *view, GParamSpec *pspec,
72 struct browser_context *ctx)
73 {
74 #ifdef USE_WEBKIT2
75 int status = webkit_web_view_get_estimated_load_progress(view);
76 #else /* USE_WEBKIT2 */
77 int status = webkit_web_view_get_load_status(view);
78 #endif /* USE_WEBKIT2 */
79 wpa_printf(MSG_DEBUG, "BROWSER:%s load-status=%d uri=%s",
80 __func__, status, webkit_web_view_get_uri(view));
81 }
82
83
84 static void view_cb_resource_request_starting(WebKitWebView *view,
85 #ifndef USE_WEBKIT2
86 WebKitWebFrame *frame,
87 #endif /* USE_WEBKIT2 */
88 WebKitWebResource *res,
89 #ifdef USE_WEBKIT2
90 WebKitURIRequest *req,
91 #else /* USE_WEBKIT2 */
92 WebKitNetworkRequest *req,
93 WebKitNetworkResponse *resp,
94 #endif /* USE_WEBKIT2 */
95 struct browser_context *ctx)
96 {
97 #ifdef USE_WEBKIT2
98 const gchar *uri = webkit_uri_request_get_uri(req);
99 #else /* USE_WEBKIT2 */
100 const gchar *uri = webkit_network_request_get_uri(req);
101 #endif /* USE_WEBKIT2 */
102 wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri);
103 if (g_str_has_suffix(uri, "/favicon.ico")) {
104 #ifdef USE_WEBKIT2
105 webkit_uri_request_set_uri(req, "about:blank");
106 #else /* USE_WEBKIT2 */
107 webkit_network_request_set_uri(req, "about:blank");
108 #endif /* USE_WEBKIT2 */
109 }
110
111 if (g_str_has_prefix(uri, "osu://")) {
112 ctx->success = atoi(uri + 6);
113 gtk_main_quit();
114 }
115 if (g_str_has_prefix(uri, "http://localhost:12345")) {
116 /*
117 * This is used as a special trigger to indicate that the
118 * user exchange has been completed.
119 */
120 ctx->success = 1;
121 gtk_main_quit();
122 }
123 }
124
125
126 static gboolean view_cb_mime_type_policy_decision(
127 WebKitWebView *view,
128 #ifndef USE_WEBKIT2
129 WebKitWebFrame *frame, WebKitNetworkRequest *req,
130 gchar *mime, WebKitWebPolicyDecision *policy,
131 #else /* USE_WEBKIT2 */
132 WebKitPolicyDecision *policy,
133 WebKitPolicyDecisionType type,
134 #endif /* USE_WEBKIT2 */
135 struct browser_context *ctx)
136 {
137 #ifdef USE_WEBKIT2
138 wpa_printf(MSG_DEBUG, "BROWSER:%s type=%d", __func__, type);
139 switch (type) {
140 case WEBKIT_POLICY_DECISION_TYPE_RESPONSE: {
141 /* This function makes webkit send a download signal for all
142 * unknown mime types. */
143 WebKitResponsePolicyDecision *response;
144
145 response = WEBKIT_RESPONSE_POLICY_DECISION(policy);
146 if (!webkit_response_policy_decision_is_mime_type_supported(
147 response)) {
148 webkit_policy_decision_download(policy);
149 return TRUE;
150 }
151 break;
152 }
153 default:
154 break;
155 }
156 #else /* USE_WEBKIT2 */
157 wpa_printf(MSG_DEBUG, "BROWSER:%s mime=%s", __func__, mime);
158
159 if (!webkit_web_view_can_show_mime_type(view, mime)) {
160 webkit_web_policy_decision_download(policy);
161 return TRUE;
162 }
163 #endif /* USE_WEBKIT2 */
164
165 return FALSE;
166 }
167
168
169 #ifndef USE_WEBKIT2
170 static gboolean view_cb_download_requested(WebKitWebView *view,
171 WebKitDownload *dl,
172 struct browser_context *ctx)
173 {
174 const gchar *uri;
175 uri = webkit_download_get_uri(dl);
176 wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri);
177 return FALSE;
178 }
179 #endif /* USE_WEBKIT2 */
180
181
182 static void view_cb_hovering_over_link(WebKitWebView *view, gchar *title,
183 gchar *uri, struct browser_context *ctx)
184 {
185 wpa_printf(MSG_DEBUG, "BROWSER:%s title=%s uri=%s", __func__, title,
186 uri);
187 os_free(ctx->hover_link);
188 if (uri)
189 ctx->hover_link = os_strdup(uri);
190 else
191 ctx->hover_link = NULL;
192
193 browser_update_title(ctx);
194 }
195
196
197 #ifndef USE_WEBKIT2
198 static void view_cb_title_changed(WebKitWebView *view, WebKitWebFrame *frame,
199 const char *title,
200 struct browser_context *ctx)
201 {
202 wpa_printf(MSG_DEBUG, "BROWSER:%s title=%s", __func__, title);
203 os_free(ctx->title);
204 ctx->title = os_strdup(title);
205 browser_update_title(ctx);
206 }
207 #endif /* USE_WEBKIT2 */
208
209
210 int hs20_web_browser(const char *url)
211 {
212 GtkWidget *scroll;
213 WebKitWebView *view;
214 #ifdef USE_WEBKIT2
215 WebKitSettings *settings;
216 #else /* USE_WEBKIT2 */
217 WebKitWebSettings *settings;
218 SoupSession *s;
219 #endif /* USE_WEBKIT2 */
220 struct browser_context ctx;
221
222 memset(&ctx, 0, sizeof(ctx));
223 if (!gtk_init_check(NULL, NULL))
224 return -1;
225
226 #ifndef USE_WEBKIT2
227 s = webkit_get_default_session();
228 g_object_set(G_OBJECT(s), "ssl-ca-file",
229 "/etc/ssl/certs/ca-certificates.crt", NULL);
230 g_object_set(G_OBJECT(s), "ssl-strict", FALSE, NULL);
231 #endif /* USE_WEBKIT2 */
232
233 ctx.win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
234 gtk_window_set_role(GTK_WINDOW(ctx.win), "Hotspot 2.0 client");
235 gtk_window_set_default_size(GTK_WINDOW(ctx.win), 800, 600);
236
237 scroll = gtk_scrolled_window_new(NULL, NULL);
238 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
239 GTK_POLICY_NEVER, GTK_POLICY_NEVER);
240
241 g_signal_connect(G_OBJECT(ctx.win), "destroy",
242 G_CALLBACK(win_cb_destroy), &ctx);
243
244 view = WEBKIT_WEB_VIEW(webkit_web_view_new());
245 g_signal_connect(G_OBJECT(view), "notify::progress",
246 G_CALLBACK(view_cb_notify_progress), &ctx);
247 g_signal_connect(G_OBJECT(view), "notify::load-status",
248 G_CALLBACK(view_cb_notify_load_status), &ctx);
249 #ifdef USE_WEBKIT2
250 g_signal_connect(G_OBJECT(view), "resource-load-started",
251 G_CALLBACK(view_cb_resource_request_starting), &ctx);
252 g_signal_connect(G_OBJECT(view), "decide-policy",
253 G_CALLBACK(view_cb_mime_type_policy_decision), &ctx);
254 /* TODO: Implement these?
255 g_signal_connect(G_OBJECT(view), "download-started",
256 G_CALLBACK(view_cb_download_requested), &ctx);
257 g_signal_connect(G_OBJECT(view), "notify::title",
258 G_CALLBACK(view_cb_title_changed), &ctx);
259 */
260 #else /* USE_WEBKIT2 */
261 g_signal_connect(G_OBJECT(view), "resource-request-starting",
262 G_CALLBACK(view_cb_resource_request_starting), &ctx);
263 g_signal_connect(G_OBJECT(view), "mime-type-policy-decision-requested",
264 G_CALLBACK(view_cb_mime_type_policy_decision), &ctx);
265 g_signal_connect(G_OBJECT(view), "download-requested",
266 G_CALLBACK(view_cb_download_requested), &ctx);
267 g_signal_connect(G_OBJECT(view), "title-changed",
268 G_CALLBACK(view_cb_title_changed), &ctx);
269 #endif /* USE_WEBKIT2 */
270
271 g_signal_connect(G_OBJECT(view), "hovering-over-link",
272 G_CALLBACK(view_cb_hovering_over_link), &ctx);
273
274 gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(view));
275 gtk_container_add(GTK_CONTAINER(ctx.win), GTK_WIDGET(scroll));
276
277 gtk_widget_grab_focus(GTK_WIDGET(view));
278 gtk_widget_show_all(ctx.win);
279
280 settings = webkit_web_view_get_settings(view);
281 g_object_set(G_OBJECT(settings), "user-agent",
282 "Mozilla/5.0 (X11; U; Unix; en-US) "
283 "AppleWebKit/537.15 (KHTML, like Gecko) "
284 "hs20-client/1.0", NULL);
285 g_object_set(G_OBJECT(settings), "auto-load-images", TRUE, NULL);
286
287 webkit_web_view_load_uri(view, url);
288
289 gtk_main();
290 gtk_widget_destroy(ctx.win);
291 while (gtk_events_pending())
292 gtk_main_iteration();
293
294 free(ctx.hover_link);
295 free(ctx.title);
296 return ctx.success;
297 }