browser.c 6.0 KB

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