| /* |
| * Hotspot 2.0 client - Web browser using WebKit |
| * Copyright (c) 2013, Qualcomm Atheros, Inc. |
| * |
| * This software may be distributed under the terms of the BSD license. |
| * See README for more details. |
| */ |
| |
| #include "includes.h" |
| #include <webkit/webkit.h> |
| |
| #include "common.h" |
| #include "browser.h" |
| |
| |
| struct browser_context { |
| GtkWidget *win; |
| int success; |
| int progress; |
| char *hover_link; |
| char *title; |
| }; |
| |
| static void win_cb_destroy(GtkWidget *win, struct browser_context *ctx) |
| { |
| wpa_printf(MSG_DEBUG, "BROWSER:%s", __func__); |
| gtk_main_quit(); |
| } |
| |
| |
| static void browser_update_title(struct browser_context *ctx) |
| { |
| char buf[100]; |
| |
| if (ctx->hover_link) { |
| gtk_window_set_title(GTK_WINDOW(ctx->win), ctx->hover_link); |
| return; |
| } |
| |
| if (ctx->progress == 100) { |
| gtk_window_set_title(GTK_WINDOW(ctx->win), |
| ctx->title ? ctx->title : |
| "Hotspot 2.0 client"); |
| return; |
| } |
| |
| snprintf(buf, sizeof(buf), "[%d%%] %s", ctx->progress, |
| ctx->title ? ctx->title : "Hotspot 2.0 client"); |
| gtk_window_set_title(GTK_WINDOW(ctx->win), buf); |
| } |
| |
| |
| static void view_cb_notify_progress(WebKitWebView *view, GParamSpec *pspec, |
| struct browser_context *ctx) |
| { |
| ctx->progress = 100 * webkit_web_view_get_progress(view); |
| wpa_printf(MSG_DEBUG, "BROWSER:%s progress=%d", __func__, |
| ctx->progress); |
| browser_update_title(ctx); |
| } |
| |
| |
| static void view_cb_notify_load_status(WebKitWebView *view, GParamSpec *pspec, |
| struct browser_context *ctx) |
| { |
| int status = webkit_web_view_get_load_status(view); |
| wpa_printf(MSG_DEBUG, "BROWSER:%s load-status=%d uri=%s", |
| __func__, status, webkit_web_view_get_uri(view)); |
| } |
| |
| |
| static void view_cb_resource_request_starting(WebKitWebView *view, |
| WebKitWebFrame *frame, |
| WebKitWebResource *res, |
| WebKitNetworkRequest *req, |
| WebKitNetworkResponse *resp, |
| struct browser_context *ctx) |
| { |
| const gchar *uri = webkit_network_request_get_uri(req); |
| wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri); |
| if (g_str_has_suffix(uri, "/favicon.ico")) |
| webkit_network_request_set_uri(req, "about:blank"); |
| if (g_str_has_prefix(uri, "osu://")) { |
| ctx->success = atoi(uri + 6); |
| gtk_main_quit(); |
| } |
| if (g_str_has_prefix(uri, "http://localhost:12345")) { |
| /* |
| * This is used as a special trigger to indicate that the |
| * user exchange has been completed. |
| */ |
| ctx->success = 1; |
| gtk_main_quit(); |
| } |
| } |
| |
| |
| static gboolean view_cb_mime_type_policy_decision( |
| WebKitWebView *view, WebKitWebFrame *frame, WebKitNetworkRequest *req, |
| gchar *mime, WebKitWebPolicyDecision *policy, |
| struct browser_context *ctx) |
| { |
| wpa_printf(MSG_DEBUG, "BROWSER:%s mime=%s", __func__, mime); |
| |
| if (!webkit_web_view_can_show_mime_type(view, mime)) { |
| webkit_web_policy_decision_download(policy); |
| return TRUE; |
| } |
| |
| return FALSE; |
| } |
| |
| |
| static gboolean view_cb_download_requested(WebKitWebView *view, |
| WebKitDownload *dl, |
| struct browser_context *ctx) |
| { |
| const gchar *uri; |
| uri = webkit_download_get_uri(dl); |
| wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri); |
| return FALSE; |
| } |
| |
| |
| static void view_cb_hovering_over_link(WebKitWebView *view, gchar *title, |
| gchar *uri, struct browser_context *ctx) |
| { |
| wpa_printf(MSG_DEBUG, "BROWSER:%s title=%s uri=%s", __func__, title, |
| uri); |
| os_free(ctx->hover_link); |
| if (uri) |
| ctx->hover_link = os_strdup(uri); |
| else |
| ctx->hover_link = NULL; |
| |
| browser_update_title(ctx); |
| } |
| |
| |
| static void view_cb_title_changed(WebKitWebView *view, WebKitWebFrame *frame, |
| const char *title, |
| struct browser_context *ctx) |
| { |
| wpa_printf(MSG_DEBUG, "BROWSER:%s title=%s", __func__, title); |
| os_free(ctx->title); |
| ctx->title = os_strdup(title); |
| browser_update_title(ctx); |
| } |
| |
| |
| int hs20_web_browser(const char *url) |
| { |
| GtkWidget *scroll; |
| SoupSession *s; |
| WebKitWebView *view; |
| WebKitWebSettings *settings; |
| struct browser_context ctx; |
| |
| memset(&ctx, 0, sizeof(ctx)); |
| if (!gtk_init_check(NULL, NULL)) |
| return -1; |
| |
| s = webkit_get_default_session(); |
| g_object_set(G_OBJECT(s), "ssl-ca-file", |
| "/etc/ssl/certs/ca-certificates.crt", NULL); |
| g_object_set(G_OBJECT(s), "ssl-strict", FALSE, NULL); |
| |
| ctx.win = gtk_window_new(GTK_WINDOW_TOPLEVEL); |
| gtk_window_set_wmclass(GTK_WINDOW(ctx.win), "Hotspot 2.0 client", |
| "Hotspot 2.0 client"); |
| gtk_window_set_default_size(GTK_WINDOW(ctx.win), 800, 600); |
| |
| scroll = gtk_scrolled_window_new(NULL, NULL); |
| gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), |
| GTK_POLICY_NEVER, GTK_POLICY_NEVER); |
| |
| g_signal_connect(G_OBJECT(ctx.win), "destroy", |
| G_CALLBACK(win_cb_destroy), &ctx); |
| |
| view = WEBKIT_WEB_VIEW(webkit_web_view_new()); |
| g_signal_connect(G_OBJECT(view), "notify::progress", |
| G_CALLBACK(view_cb_notify_progress), &ctx); |
| g_signal_connect(G_OBJECT(view), "notify::load-status", |
| G_CALLBACK(view_cb_notify_load_status), &ctx); |
| g_signal_connect(G_OBJECT(view), "resource-request-starting", |
| G_CALLBACK(view_cb_resource_request_starting), &ctx); |
| g_signal_connect(G_OBJECT(view), "mime-type-policy-decision-requested", |
| G_CALLBACK(view_cb_mime_type_policy_decision), &ctx); |
| g_signal_connect(G_OBJECT(view), "download-requested", |
| G_CALLBACK(view_cb_download_requested), &ctx); |
| g_signal_connect(G_OBJECT(view), "hovering-over-link", |
| G_CALLBACK(view_cb_hovering_over_link), &ctx); |
| g_signal_connect(G_OBJECT(view), "title-changed", |
| G_CALLBACK(view_cb_title_changed), &ctx); |
| |
| gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(view)); |
| gtk_container_add(GTK_CONTAINER(ctx.win), GTK_WIDGET(scroll)); |
| |
| gtk_widget_grab_focus(GTK_WIDGET(view)); |
| gtk_widget_show_all(ctx.win); |
| |
| settings = webkit_web_view_get_settings(view); |
| g_object_set(G_OBJECT(settings), "user-agent", |
| "Mozilla/5.0 (X11; U; Unix; en-US) " |
| "AppleWebKit/537.15 (KHTML, like Gecko) " |
| "hs20-client/1.0", NULL); |
| g_object_set(G_OBJECT(settings), "auto-load-images", TRUE, NULL); |
| |
| webkit_web_view_load_uri(view, url); |
| |
| gtk_main(); |
| gtk_widget_destroy(ctx.win); |
| while (gtk_events_pending()) |
| gtk_main_iteration(); |
| |
| free(ctx.hover_link); |
| free(ctx.title); |
| return ctx.success; |
| } |