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