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