1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /*
3 * Copyright © 2000-2003 Marco Pesenti Gritti
4 * Copyright © 2011 Igalia S.L.
5 *
6 * This file is part of Epiphany.
7 *
8 * Epiphany is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * Epiphany is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with Epiphany. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <config.h>
23 #include "ephy-embed-shell.h"
24
25 #include "ephy-about-handler.h"
26 #include "ephy-debug.h"
27 #include "ephy-downloads-manager.h"
28 #include "ephy-embed-container.h"
29 #include "ephy-embed-prefs.h"
30 #include "ephy-embed-type-builtins.h"
31 #include "ephy-embed-utils.h"
32 #include "ephy-encodings.h"
33 #include "ephy-file-helpers.h"
34 #include "ephy-filters-manager.h"
35 #include "ephy-flatpak-utils.h"
36 #include "ephy-history-service.h"
37 #include "ephy-password-manager.h"
38 #include "ephy-pdf-handler.h"
39 #include "ephy-profile-utils.h"
40 #include "ephy-reader-handler.h"
41 #include "ephy-settings.h"
42 #include "ephy-snapshot-service.h"
43 #include "ephy-tabs-catalog.h"
44 #include "ephy-uri-helpers.h"
45 #include "ephy-view-source-handler.h"
46 #include "ephy-web-app-utils.h"
47
48 #include <glib/gi18n.h>
49 #include <gtk/gtk.h>
50 #include <stdlib.h>
51
52 #define PAGE_SETUP_FILENAME "page-setup-gtk.ini"
53 #define PRINT_SETTINGS_FILENAME "print-settings.ini"
54
55 typedef struct {
56 WebKitWebContext *web_context;
57 EphyHistoryService *global_history_service;
58 EphyGSBService *global_gsb_service;
59 EphyEncodings *encodings;
60 GtkPageSetup *page_setup;
61 GtkPrintSettings *print_settings;
62 EphyEmbedShellMode mode;
63 EphyDownloadsManager *downloads_manager;
64 EphyPermissionsManager *permissions_manager;
65 EphyPasswordManager *password_manager;
66 EphyAboutHandler *about_handler;
67 EphyViewSourceHandler *source_handler;
68 EphyReaderHandler *reader_handler;
69 EphyPDFHandler *pdf_handler;
70 char *guid;
71 EphyFiltersManager *filters_manager;
72 EphySearchEngineManager *search_engine_manager;
73 GCancellable *cancellable;
74 } EphyEmbedShellPrivate;
75
76 enum {
77 RESTORED_WINDOW,
78 WEB_VIEW_CREATED,
79 ALLOW_TLS_CERTIFICATE,
80 ALLOW_UNSAFE_BROWSING,
81 PASSWORD_FORM_FOCUSED,
82
83 LAST_SIGNAL
84 };
85
86 static guint signals[LAST_SIGNAL];
87
88 enum {
89 PROP_0,
90 PROP_MODE,
91 N_PROPERTIES
92 };
93
94 static GParamSpec *object_properties[N_PROPERTIES] = { NULL, };
95
96 static EphyEmbedShell *embed_shell = NULL;
97
98 static void ephy_embed_shell_tabs_catalog_iface_init (EphyTabsCatalogInterface *iface);
99
G_DEFINE_TYPE_WITH_CODE(EphyEmbedShell,ephy_embed_shell,DZL_TYPE_APPLICATION,G_ADD_PRIVATE (EphyEmbedShell)G_IMPLEMENT_INTERFACE (EPHY_TYPE_TABS_CATALOG,ephy_embed_shell_tabs_catalog_iface_init))100 G_DEFINE_TYPE_WITH_CODE (EphyEmbedShell, ephy_embed_shell, DZL_TYPE_APPLICATION,
101 G_ADD_PRIVATE (EphyEmbedShell)
102 G_IMPLEMENT_INTERFACE (EPHY_TYPE_TABS_CATALOG,
103 ephy_embed_shell_tabs_catalog_iface_init))
104
105 static EphyWebView *
106 ephy_embed_shell_get_view_for_page_id (EphyEmbedShell *self,
107 guint64 page_id,
108 const char *origin)
109 {
110 GList *windows = gtk_application_get_windows (GTK_APPLICATION (self));
111
112 for (GList *l = windows; l && l->data; l = l->next) {
113 g_autoptr (GList) tabs = ephy_embed_container_get_children (l->data);
114
115 for (GList *t = tabs; t && t->data; t = t->next) {
116 EphyWebView *ephy_view = ephy_embed_get_web_view (t->data);
117 WebKitWebView *web_view = WEBKIT_WEB_VIEW (ephy_view);
118 g_autofree char *real_origin = NULL;
119
120 if (webkit_web_view_get_page_id (web_view) != page_id)
121 continue;
122
123 real_origin = ephy_uri_to_security_origin (webkit_web_view_get_uri (web_view));
124
125 if (g_strcmp0 (real_origin, origin)) {
126 g_debug ("Extension's origin '%s' doesn't match real origin '%s'", origin, real_origin);
127 return NULL;
128 }
129
130 return ephy_view;
131 }
132 }
133
134 return NULL;
135 }
136
137 static GList *
tabs_catalog_get_tabs_info(EphyTabsCatalog * catalog)138 tabs_catalog_get_tabs_info (EphyTabsCatalog *catalog)
139 {
140 WebKitFaviconDatabase *database;
141 GList *windows;
142 g_autoptr (GList) tabs = NULL;
143 GList *tabs_info = NULL;
144 const char *title;
145 const char *url;
146 g_autofree char *favicon = NULL;
147
148 g_assert ((gpointer)catalog == (gpointer)embed_shell);
149
150 windows = gtk_application_get_windows (GTK_APPLICATION (embed_shell));
151 database = webkit_web_context_get_favicon_database (ephy_embed_shell_get_web_context (embed_shell));
152
153 for (GList *l = windows; l && l->data; l = l->next) {
154 tabs = ephy_embed_container_get_children (l->data);
155
156 for (GList *t = tabs; t && t->data; t = t->next) {
157 title = ephy_embed_get_title (t->data);
158
159 if (!g_strcmp0 (title, _(BLANK_PAGE_TITLE)) || !g_strcmp0 (title, _(OVERVIEW_PAGE_TITLE)))
160 continue;
161
162 url = ephy_web_view_get_display_address (ephy_embed_get_web_view (t->data));
163 favicon = webkit_favicon_database_get_favicon_uri (database, url);
164
165 tabs_info = g_list_prepend (tabs_info,
166 ephy_tab_info_new (title, url, favicon));
167 }
168 }
169
170 return tabs_info;
171 }
172
173 static void
ephy_embed_shell_tabs_catalog_iface_init(EphyTabsCatalogInterface * iface)174 ephy_embed_shell_tabs_catalog_iface_init (EphyTabsCatalogInterface *iface)
175 {
176 iface->get_tabs_info = tabs_catalog_get_tabs_info;
177 }
178
179 static void
ephy_embed_shell_dispose(GObject * object)180 ephy_embed_shell_dispose (GObject *object)
181 {
182 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (EPHY_EMBED_SHELL (object));
183
184 if (priv->cancellable) {
185 g_cancellable_cancel (priv->cancellable);
186 g_clear_object (&priv->cancellable);
187 }
188
189 g_clear_object (&priv->encodings);
190 g_clear_object (&priv->page_setup);
191 g_clear_object (&priv->print_settings);
192 g_clear_object (&priv->global_history_service);
193 g_clear_object (&priv->global_gsb_service);
194 g_clear_object (&priv->about_handler);
195 g_clear_object (&priv->reader_handler);
196 g_clear_object (&priv->source_handler);
197 g_clear_object (&priv->pdf_handler);
198 g_clear_object (&priv->downloads_manager);
199 g_clear_object (&priv->password_manager);
200 g_clear_object (&priv->permissions_manager);
201 g_clear_object (&priv->web_context);
202 g_clear_pointer (&priv->guid, g_free);
203 g_clear_object (&priv->filters_manager);
204 g_clear_object (&priv->search_engine_manager);
205
206 G_OBJECT_CLASS (ephy_embed_shell_parent_class)->dispose (object);
207 }
208
209 static void
web_process_extension_password_form_focused_message_received_cb(WebKitUserContentManager * manager,WebKitJavascriptResult * message,EphyEmbedShell * shell)210 web_process_extension_password_form_focused_message_received_cb (WebKitUserContentManager *manager,
211 WebKitJavascriptResult *message,
212 EphyEmbedShell *shell)
213 {
214 guint64 page_id;
215 gboolean insecure_form_action;
216 g_autoptr (GVariant) variant = NULL;
217 g_autofree char *message_str = NULL;
218
219 message_str = jsc_value_to_string (webkit_javascript_result_get_js_value (message));
220 variant = g_variant_parse (G_VARIANT_TYPE ("(tb)"), message_str, NULL, NULL, NULL);
221
222 g_variant_get (variant, "(tb)", &page_id, &insecure_form_action);
223 g_signal_emit (shell, signals[PASSWORD_FORM_FOCUSED], 0,
224 page_id, insecure_form_action);
225 }
226
227 static void
history_service_query_urls_cb(EphyHistoryService * service,gboolean success,GList * urls,EphyEmbedShell * shell)228 history_service_query_urls_cb (EphyHistoryService *service,
229 gboolean success,
230 GList *urls,
231 EphyEmbedShell *shell)
232 {
233 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
234 GList *l;
235 GVariantBuilder builder;
236
237 if (!success)
238 return;
239
240 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ss)"));
241 for (l = urls; l; l = g_list_next (l)) {
242 EphyHistoryURL *url = (EphyHistoryURL *)l->data;
243
244 g_variant_builder_add (&builder, "(ss)", url->url, url->title);
245 ephy_embed_shell_schedule_thumbnail_update (shell, (EphyHistoryURL *)l->data);
246 }
247
248 webkit_web_context_send_message_to_all_extensions (priv->web_context,
249 webkit_user_message_new ("History.SetURLs",
250 g_variant_builder_end (&builder)));
251 }
252
253 static void
ephy_embed_shell_update_overview_urls(EphyEmbedShell * shell)254 ephy_embed_shell_update_overview_urls (EphyEmbedShell *shell)
255 {
256 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
257 g_autoptr (EphyHistoryQuery) query = NULL;
258
259 query = ephy_history_query_new_for_overview ();
260 ephy_history_service_query_urls (priv->global_history_service, query, NULL,
261 (EphyHistoryJobCallback)history_service_query_urls_cb,
262 shell);
263 }
264
265 static void
history_service_urls_visited_cb(EphyHistoryService * history,EphyEmbedShell * shell)266 history_service_urls_visited_cb (EphyHistoryService *history,
267 EphyEmbedShell *shell)
268 {
269 ephy_embed_shell_update_overview_urls (shell);
270 }
271
272 static void
history_set_url_hidden_cb(EphyHistoryService * service,gboolean success,gpointer result_data,EphyEmbedShell * shell)273 history_set_url_hidden_cb (EphyHistoryService *service,
274 gboolean success,
275 gpointer result_data,
276 EphyEmbedShell *shell)
277 {
278 if (!success)
279 return;
280
281 ephy_embed_shell_update_overview_urls (shell);
282 }
283
284 static void
web_process_extension_overview_message_received_cb(WebKitUserContentManager * manager,WebKitJavascriptResult * message,EphyEmbedShell * shell)285 web_process_extension_overview_message_received_cb (WebKitUserContentManager *manager,
286 WebKitJavascriptResult *message,
287 EphyEmbedShell *shell)
288 {
289 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
290 g_autofree char *url_to_remove = NULL;
291
292 url_to_remove = jsc_value_to_string (webkit_javascript_result_get_js_value (message));
293
294 ephy_history_service_set_url_hidden (priv->global_history_service,
295 url_to_remove, TRUE, NULL,
296 (EphyHistoryJobCallback)history_set_url_hidden_cb,
297 shell);
298 }
299
300 static void
web_process_extension_tls_error_page_message_received_cb(WebKitUserContentManager * manager,WebKitJavascriptResult * message,EphyEmbedShell * shell)301 web_process_extension_tls_error_page_message_received_cb (WebKitUserContentManager *manager,
302 WebKitJavascriptResult *message,
303 EphyEmbedShell *shell)
304 {
305 guint64 page_id;
306
307 page_id = jsc_value_to_double (webkit_javascript_result_get_js_value (message));
308 g_signal_emit (shell, signals[ALLOW_TLS_CERTIFICATE], 0, page_id);
309 }
310
311 static void
web_process_extension_unsafe_browsing_error_page_message_received_cb(WebKitUserContentManager * manager,WebKitJavascriptResult * message,EphyEmbedShell * shell)312 web_process_extension_unsafe_browsing_error_page_message_received_cb (WebKitUserContentManager *manager,
313 WebKitJavascriptResult *message,
314 EphyEmbedShell *shell)
315 {
316 guint64 page_id;
317
318 page_id = jsc_value_to_double (webkit_javascript_result_get_js_value (message));
319 g_signal_emit (shell, signals[ALLOW_UNSAFE_BROWSING], 0, page_id);
320 }
321
322 static void
web_process_extension_about_apps_message_received_cb(WebKitUserContentManager * manager,WebKitJavascriptResult * message,EphyEmbedShell * shell)323 web_process_extension_about_apps_message_received_cb (WebKitUserContentManager *manager,
324 WebKitJavascriptResult *message,
325 EphyEmbedShell *shell)
326 {
327 g_autofree char *app_id = NULL;
328
329 app_id = jsc_value_to_string (webkit_javascript_result_get_js_value (message));
330 ephy_web_application_delete (app_id);
331 }
332
333 static char *
property_to_string_or_null(JSCValue * value,const char * name)334 property_to_string_or_null (JSCValue *value,
335 const char *name)
336 {
337 g_autoptr (JSCValue) prop = jsc_value_object_get_property (value, name);
338 if (jsc_value_is_null (prop) || jsc_value_is_undefined (prop))
339 return NULL;
340 return jsc_value_to_string (prop);
341 }
342
343 static int
property_to_uint64(JSCValue * value,const char * name)344 property_to_uint64 (JSCValue *value,
345 const char *name)
346 {
347 g_autoptr (JSCValue) prop = jsc_value_object_get_property (value, name);
348 return (guint64)jsc_value_to_double (prop);
349 }
350
351 typedef struct {
352 EphyPasswordManager *password_manager;
353 EphyPermissionsManager *permissions_manager;
354 char *origin;
355 char *target_origin;
356 char *username;
357 char *password;
358 char *username_field;
359 char *password_field;
360 gboolean is_new;
361 } SaveAuthRequest;
362
363 static void
save_auth_request_free(SaveAuthRequest * request)364 save_auth_request_free (SaveAuthRequest *request)
365 {
366 g_object_unref (request->password_manager);
367 g_object_unref (request->permissions_manager);
368 g_free (request->origin);
369 g_free (request->target_origin);
370 g_free (request->username);
371 g_free (request->password);
372 g_free (request->username_field);
373 g_free (request->password_field);
374 g_free (request);
375 }
376
377 static void
save_auth_request_response_cb(gint response_id,SaveAuthRequest * data)378 save_auth_request_response_cb (gint response_id,
379 SaveAuthRequest *data)
380 {
381 if (response_id == GTK_RESPONSE_REJECT) {
382 ephy_permissions_manager_set_permission (data->permissions_manager,
383 EPHY_PERMISSION_TYPE_SAVE_PASSWORD,
384 data->origin,
385 EPHY_PERMISSION_DENY);
386 } else if (response_id == GTK_RESPONSE_YES) {
387 ephy_password_manager_save (data->password_manager, data->origin, data->target_origin,
388 data->username, data->password, data->username_field,
389 data->password_field, data->is_new);
390 }
391 }
392
393 static void
web_process_extension_password_manager_save_real(EphyEmbedShell * shell,JSCValue * value,gboolean is_request)394 web_process_extension_password_manager_save_real (EphyEmbedShell *shell,
395 JSCValue *value,
396 gboolean is_request)
397 {
398 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
399 g_autofree char *origin = property_to_string_or_null (value, "origin");
400 g_autofree char *target_origin = property_to_string_or_null (value, "targetOrigin");
401 g_autofree char *username = property_to_string_or_null (value, "username");
402 g_autofree char *password = property_to_string_or_null (value, "password");
403 g_autofree char *username_field = property_to_string_or_null (value, "usernameField");
404 g_autofree char *password_field = property_to_string_or_null (value, "passwordField");
405 g_autoptr (JSCValue) is_new_prop = jsc_value_object_get_property (value, "isNew");
406 gboolean is_new = jsc_value_to_boolean (is_new_prop);
407 guint64 page_id = property_to_uint64 (value, "pageID");
408 EphyWebView *view;
409 SaveAuthRequest *request;
410
411 /* Both origin and target origin are required. */
412 if (!origin || !target_origin)
413 return;
414
415 /* Both password and password field are required. */
416 if (!password || !password_field)
417 return;
418
419 /* The username field is required if username is present. */
420 if (username && !username_field)
421 g_clear_pointer (&username, g_free);
422
423 /* The username is required if username field is present. */
424 if (!username && username_field)
425 g_clear_pointer (&username_field, g_free);
426
427 /* This also sanity checks that a page isn't saving websites for
428 * other origins. Remember the request comes from the untrusted web
429 * process and we have to make sure it's not being evil here. This
430 * could also happen even without malice if the origin of a subframe
431 * doesn't match the origin of the main frame (in which case we'll
432 * refuse to save the password).
433 */
434 view = ephy_embed_shell_get_view_for_page_id (shell, page_id, origin);
435 if (!view)
436 return;
437
438 if (!is_request) {
439 ephy_password_manager_save (priv->password_manager, origin, target_origin, username,
440 password, username_field, password_field, is_new);
441 return;
442 }
443
444 request = g_new (SaveAuthRequest, 1);
445 request->password_manager = g_object_ref (priv->password_manager);
446 request->permissions_manager = g_object_ref (priv->permissions_manager);
447 request->origin = g_steal_pointer (&origin);
448 request->target_origin = g_steal_pointer (&target_origin);
449 request->username = g_steal_pointer (&username);
450 request->password = g_steal_pointer (&password);
451 request->username_field = g_steal_pointer (&username_field);
452 request->password_field = g_steal_pointer (&password_field);
453 request->is_new = is_new;
454 ephy_web_view_show_auth_form_save_request (view, request->origin, request->username,
455 (EphyPasswordSaveRequestCallback)save_auth_request_response_cb,
456 request, (GDestroyNotify)save_auth_request_free);
457 }
458
459 static void
web_process_extension_password_manager_save_received_cb(WebKitUserContentManager * manager,WebKitJavascriptResult * message,EphyEmbedShell * shell)460 web_process_extension_password_manager_save_received_cb (WebKitUserContentManager *manager,
461 WebKitJavascriptResult *message,
462 EphyEmbedShell *shell)
463 {
464 JSCValue *value = webkit_javascript_result_get_js_value (message);
465 web_process_extension_password_manager_save_real (shell, value, FALSE);
466 }
467
468 static void
web_process_extension_password_manager_request_save_received_cb(WebKitUserContentManager * manager,WebKitJavascriptResult * message,EphyEmbedShell * shell)469 web_process_extension_password_manager_request_save_received_cb (WebKitUserContentManager *manager,
470 WebKitJavascriptResult *message,
471 EphyEmbedShell *shell)
472 {
473 JSCValue *value = webkit_javascript_result_get_js_value (message);
474 web_process_extension_password_manager_save_real (shell, value, TRUE);
475 }
476
477 static void
history_service_url_title_changed_cb(EphyHistoryService * service,const char * url,const char * title,EphyEmbedShell * shell)478 history_service_url_title_changed_cb (EphyHistoryService *service,
479 const char *url,
480 const char *title,
481 EphyEmbedShell *shell)
482 {
483 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
484
485 webkit_web_context_send_message_to_all_extensions (priv->web_context,
486 webkit_user_message_new ("History.SetURLTitle",
487 g_variant_new ("(ss)", url, title)));
488 }
489
490 static void
history_service_url_deleted_cb(EphyHistoryService * service,EphyHistoryURL * url,EphyEmbedShell * shell)491 history_service_url_deleted_cb (EphyHistoryService *service,
492 EphyHistoryURL *url,
493 EphyEmbedShell *shell)
494 {
495 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
496
497 webkit_web_context_send_message_to_all_extensions (priv->web_context,
498 webkit_user_message_new ("History.DeleteURL",
499 g_variant_new ("s", url->url)));
500 }
501
502 static void
history_service_host_deleted_cb(EphyHistoryService * service,const char * deleted_url,EphyEmbedShell * shell)503 history_service_host_deleted_cb (EphyHistoryService *service,
504 const char *deleted_url,
505 EphyEmbedShell *shell)
506 {
507 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
508 g_autoptr (GUri) deleted_uri = NULL;
509
510 deleted_uri = g_uri_parse (deleted_url, G_URI_FLAGS_NONE, NULL);
511 webkit_web_context_send_message_to_all_extensions (priv->web_context,
512 webkit_user_message_new ("History.DeleteHost",
513 g_variant_new ("s", g_uri_get_host (deleted_uri))));
514 }
515
516 static void
history_service_cleared_cb(EphyHistoryService * service,EphyEmbedShell * shell)517 history_service_cleared_cb (EphyHistoryService *service,
518 EphyEmbedShell *shell)
519 {
520 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
521
522 webkit_web_context_send_message_to_all_extensions (priv->web_context,
523 webkit_user_message_new ("History.Clear",
524 NULL));
525 }
526
527 void
ephy_embed_shell_set_thumbnail_path(EphyEmbedShell * shell,const char * url,const char * path)528 ephy_embed_shell_set_thumbnail_path (EphyEmbedShell *shell,
529 const char *url,
530 const char *path)
531 {
532 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
533
534 webkit_web_context_send_message_to_all_extensions (priv->web_context,
535 webkit_user_message_new ("History.SetURLThumbnail",
536 g_variant_new ("(ss)", url, path)));
537 }
538
539 static void
got_snapshot_path_for_url_cb(EphySnapshotService * service,GAsyncResult * result,char * url)540 got_snapshot_path_for_url_cb (EphySnapshotService *service,
541 GAsyncResult *result,
542 char *url)
543 {
544 g_autofree char *snapshot = NULL;
545 g_autoptr (GError) error = NULL;
546
547 snapshot = ephy_snapshot_service_get_snapshot_path_for_url_finish (service, result, &error);
548 if (snapshot) {
549 ephy_embed_shell_set_thumbnail_path (ephy_embed_shell_get_default (), url, snapshot);
550 } else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
551 /* Bad luck, not something to warn about. */
552 g_info ("Failed to get snapshot for URL %s: %s", url, error->message);
553 }
554
555 g_free (url);
556 }
557
558 void
ephy_embed_shell_schedule_thumbnail_update(EphyEmbedShell * shell,EphyHistoryURL * url)559 ephy_embed_shell_schedule_thumbnail_update (EphyEmbedShell *shell,
560 EphyHistoryURL *url)
561 {
562 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
563 EphySnapshotService *service;
564 const char *snapshot;
565
566 service = ephy_snapshot_service_get_default ();
567 snapshot = ephy_snapshot_service_lookup_cached_snapshot_path (service, url->url);
568
569 if (snapshot) {
570 ephy_embed_shell_set_thumbnail_path (shell, url->url, snapshot);
571 } else {
572 ephy_snapshot_service_get_snapshot_path_for_url_async (service,
573 url->url,
574 priv->cancellable,
575 (GAsyncReadyCallback)got_snapshot_path_for_url_cb,
576 g_strdup (url->url));
577 }
578 }
579
580 /**
581 * ephy_embed_shell_get_global_history_service:
582 * @shell: the #EphyEmbedShell
583 *
584 * Return value: (transfer none): the global #EphyHistoryService
585 **/
586 EphyHistoryService *
ephy_embed_shell_get_global_history_service(EphyEmbedShell * shell)587 ephy_embed_shell_get_global_history_service (EphyEmbedShell *shell)
588 {
589 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
590
591 g_assert (EPHY_IS_EMBED_SHELL (shell));
592
593 if (!priv->global_history_service) {
594 g_autofree char *filename = NULL;
595 EphySQLiteConnectionMode mode;
596
597 if (priv->mode == EPHY_EMBED_SHELL_MODE_INCOGNITO ||
598 priv->mode == EPHY_EMBED_SHELL_MODE_AUTOMATION ||
599 priv->mode == EPHY_EMBED_SHELL_MODE_SEARCH_PROVIDER)
600 mode = EPHY_SQLITE_CONNECTION_MODE_MEMORY;
601 else
602 mode = EPHY_SQLITE_CONNECTION_MODE_READWRITE;
603
604 filename = g_build_filename (ephy_profile_dir (), EPHY_HISTORY_FILE, NULL);
605 priv->global_history_service = ephy_history_service_new (filename, mode);
606
607 g_signal_connect_object (priv->global_history_service, "urls-visited",
608 G_CALLBACK (history_service_urls_visited_cb),
609 shell, 0);
610 g_signal_connect_object (priv->global_history_service, "url-title-changed",
611 G_CALLBACK (history_service_url_title_changed_cb),
612 shell, 0);
613 g_signal_connect_object (priv->global_history_service, "url-deleted",
614 G_CALLBACK (history_service_url_deleted_cb),
615 shell, 0);
616 g_signal_connect_object (priv->global_history_service, "host-deleted",
617 G_CALLBACK (history_service_host_deleted_cb),
618 shell, 0);
619 g_signal_connect_object (priv->global_history_service, "cleared",
620 G_CALLBACK (history_service_cleared_cb),
621 shell, 0);
622 }
623
624 return priv->global_history_service;
625 }
626
627 /**
628 * ephy_embed_shell_get_global_gsb_service:
629 * @shell: the #EphyEmbedShell
630 *
631 * Return value: (transfer none): the global #EphyGSBService
632 **/
633 EphyGSBService *
ephy_embed_shell_get_global_gsb_service(EphyEmbedShell * shell)634 ephy_embed_shell_get_global_gsb_service (EphyEmbedShell *shell)
635 {
636 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
637
638 g_assert (EPHY_IS_EMBED_SHELL (shell));
639
640 if (!priv->global_gsb_service) {
641 g_autofree char *db_path = NULL;
642 g_autofree char *default_cache_dir = ephy_default_cache_dir ();
643
644 db_path = g_build_filename (default_cache_dir, EPHY_GSB_FILE, NULL);
645 priv->global_gsb_service = ephy_gsb_service_new (GSB_API_KEY, db_path);
646 }
647
648 return priv->global_gsb_service;
649 }
650
651 /**
652 * ephy_embed_shell_get_encodings:
653 * @shell: the #EphyEmbedShell
654 *
655 * Return value: (transfer none):
656 **/
657 EphyEncodings *
ephy_embed_shell_get_encodings(EphyEmbedShell * shell)658 ephy_embed_shell_get_encodings (EphyEmbedShell *shell)
659 {
660 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
661
662 g_assert (EPHY_IS_EMBED_SHELL (shell));
663
664 if (!priv->encodings)
665 priv->encodings = ephy_encodings_new ();
666
667 return priv->encodings;
668 }
669
670 void
ephy_embed_shell_restored_window(EphyEmbedShell * shell)671 ephy_embed_shell_restored_window (EphyEmbedShell *shell)
672 {
673 g_signal_emit (shell, signals[RESTORED_WINDOW], 0);
674 }
675
676 static void
about_request_cb(WebKitURISchemeRequest * request,EphyEmbedShell * shell)677 about_request_cb (WebKitURISchemeRequest *request,
678 EphyEmbedShell *shell)
679 {
680 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
681
682 ephy_about_handler_handle_request (priv->about_handler, request);
683 }
684
685 static void
source_request_cb(WebKitURISchemeRequest * request,EphyEmbedShell * shell)686 source_request_cb (WebKitURISchemeRequest *request,
687 EphyEmbedShell *shell)
688 {
689 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
690
691 ephy_view_source_handler_handle_request (priv->source_handler, request);
692 }
693
694 static void
reader_request_cb(WebKitURISchemeRequest * request,EphyEmbedShell * shell)695 reader_request_cb (WebKitURISchemeRequest *request,
696 EphyEmbedShell *shell)
697 {
698 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
699
700 ephy_reader_handler_handle_request (priv->reader_handler, request);
701 }
702
703 static void
pdf_request_cb(WebKitURISchemeRequest * request,EphyEmbedShell * shell)704 pdf_request_cb (WebKitURISchemeRequest *request,
705 EphyEmbedShell *shell)
706 {
707 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
708
709 ephy_pdf_handler_handle_request (priv->pdf_handler, request);
710 }
711
712 static void
ephy_resource_request_cb(WebKitURISchemeRequest * request)713 ephy_resource_request_cb (WebKitURISchemeRequest *request)
714 {
715 const char *path;
716 gsize size;
717 WebKitWebView *request_view;
718 const char *uri;
719 g_autoptr (GInputStream) stream = NULL;
720 g_autoptr (GError) error = NULL;
721
722 path = webkit_uri_scheme_request_get_path (request);
723 if (!g_resources_get_info (path, 0, &size, NULL, &error)) {
724 webkit_uri_scheme_request_finish_error (request, error);
725 return;
726 }
727
728 request_view = webkit_uri_scheme_request_get_web_view (request);
729 uri = webkit_web_view_get_uri (request_view);
730
731 /* ephy-resource:// requests bypass CORS in order to allow ephy-pdf:// to
732 * access ephy-resource://. Accordingly, we need some custom security to
733 * prevent websites from directly accessing ephy-resource://.
734 *
735 * We'll have to leave open /page-icons and /page-templates since they are
736 * needed for our alternate HTML error pages.
737 */
738 if (g_str_has_prefix (uri, "ephy-resource:") ||
739 g_str_has_prefix (path, "/org/gnome/epiphany/page-icons/") ||
740 g_str_has_prefix (path, "/org/gnome/epiphany/page-templates/") ||
741 (g_str_has_prefix (uri, "ephy-pdf:") && g_str_has_prefix (path, "/org/gnome/epiphany/pdfjs/")) ||
742 (g_str_has_prefix (uri, "ephy-reader:") && g_str_has_prefix (path, "/org/gnome/epiphany/readability/")) ||
743 (g_str_has_prefix (uri, "ephy-source:") && g_str_has_prefix (path, "/org/gnome/epiphany/highlightjs/"))) {
744 stream = g_resources_open_stream (path, 0, &error);
745 if (stream)
746 webkit_uri_scheme_request_finish (request, stream, size, NULL);
747 else
748 webkit_uri_scheme_request_finish_error (request, error);
749 return;
750 }
751
752 error = g_error_new (WEBKIT_NETWORK_ERROR, WEBKIT_NETWORK_ERROR_FAILED,
753 _("URI %s not authorized to access Epiphany resource %s"),
754 uri, path);
755 webkit_uri_scheme_request_finish_error (request, error);
756 }
757
758 static void
initialize_web_process_extensions(WebKitWebContext * web_context,EphyEmbedShell * shell)759 initialize_web_process_extensions (WebKitWebContext *web_context,
760 EphyEmbedShell *shell)
761 {
762 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
763 g_autoptr (GVariant) user_data = NULL;
764 gboolean private_profile;
765
766 #if DEVELOPER_MODE
767 webkit_web_context_set_web_extensions_directory (web_context, BUILD_ROOT "/embed/web-process-extension");
768 #else
769 webkit_web_context_set_web_extensions_directory (web_context, EPHY_WEB_PROCESS_EXTENSIONS_DIR);
770 #endif
771
772 private_profile = priv->mode == EPHY_EMBED_SHELL_MODE_PRIVATE || priv->mode == EPHY_EMBED_SHELL_MODE_INCOGNITO || priv->mode == EPHY_EMBED_SHELL_MODE_AUTOMATION;
773 user_data = g_variant_new ("(smsbb)",
774 priv->guid,
775 ephy_profile_dir_is_default () ? NULL : ephy_profile_dir (),
776 g_settings_get_boolean (EPHY_SETTINGS_WEB, EPHY_PREFS_WEB_REMEMBER_PASSWORDS),
777 private_profile);
778 webkit_web_context_set_web_extensions_initialization_user_data (web_context, g_steal_pointer (&user_data));
779 }
780
781 static void
initialize_notification_permissions(WebKitWebContext * web_context,EphyEmbedShell * shell)782 initialize_notification_permissions (WebKitWebContext *web_context,
783 EphyEmbedShell *shell)
784 {
785 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
786 GList *permitted_origins;
787 GList *denied_origins;
788
789 permitted_origins = ephy_permissions_manager_get_permitted_origins (priv->permissions_manager,
790 EPHY_PERMISSION_TYPE_SHOW_NOTIFICATIONS);
791 denied_origins = ephy_permissions_manager_get_denied_origins (priv->permissions_manager,
792 EPHY_PERMISSION_TYPE_SHOW_NOTIFICATIONS);
793 webkit_web_context_initialize_notification_permissions (web_context, permitted_origins, denied_origins);
794 }
795
796 static void
ephy_embed_shell_create_web_context(EphyEmbedShell * shell)797 ephy_embed_shell_create_web_context (EphyEmbedShell *shell)
798 {
799 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
800 g_autoptr (WebKitWebsiteDataManager) manager = NULL;
801
802 if (priv->mode == EPHY_EMBED_SHELL_MODE_INCOGNITO || priv->mode == EPHY_EMBED_SHELL_MODE_AUTOMATION) {
803 manager = webkit_website_data_manager_new_ephemeral ();
804 } else {
805 manager = webkit_website_data_manager_new ("base-data-directory", ephy_profile_dir (),
806 "base-cache-directory", ephy_cache_dir (),
807 NULL);
808 webkit_website_data_manager_set_persistent_credential_storage_enabled (manager, FALSE);
809 }
810
811 webkit_website_data_manager_set_itp_enabled (manager,
812 g_settings_get_boolean (EPHY_SETTINGS_WEB,
813 EPHY_PREFS_WEB_ENABLE_ITP));
814
815 priv->web_context = g_object_new (WEBKIT_TYPE_WEB_CONTEXT,
816 "website-data-manager", manager,
817 "process-swap-on-cross-site-navigation-enabled", TRUE,
818 NULL);
819
820 if (priv->mode == EPHY_EMBED_SHELL_MODE_AUTOMATION)
821 webkit_web_context_set_automation_allowed (priv->web_context, TRUE);
822 }
823
824 static void
download_started_cb(WebKitWebContext * web_context,WebKitDownload * download,EphyEmbedShell * shell)825 download_started_cb (WebKitWebContext *web_context,
826 WebKitDownload *download,
827 EphyEmbedShell *shell)
828 {
829 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
830 g_autoptr (EphyDownload) ephy_download = NULL;
831 gboolean ephy_download_set;
832 WebKitWebView *web_view;
833
834 /* Is download locked down? */
835 if (g_settings_get_boolean (EPHY_SETTINGS_LOCKDOWN,
836 EPHY_PREFS_LOCKDOWN_SAVE_TO_DISK)) {
837 webkit_download_cancel (download);
838 return;
839 }
840
841 /* Only create an EphyDownload for the WebKitDownload if it doesn't exist yet.
842 * This can happen when the download has been started automatically by WebKit,
843 * due to a context menu action or policy checker decision. Downloads started
844 * explicitly by Epiphany are marked with ephy-download-set GObject data.
845 */
846 ephy_download_set = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (download), "ephy-download-set"));
847 if (ephy_download_set)
848 return;
849
850 ephy_download = ephy_download_new (download);
851
852 web_view = webkit_download_get_web_view (download);
853 if (EPHY_IS_WEB_VIEW (web_view)) {
854 if (ephy_web_view_get_document_type (EPHY_WEB_VIEW (web_view)) != EPHY_WEB_VIEW_DOCUMENT_PDF)
855 ephy_downloads_manager_add_download (priv->downloads_manager, ephy_download);
856 } else {
857 ephy_downloads_manager_add_download (priv->downloads_manager, ephy_download);
858 }
859 }
860
861 static void
remember_passwords_setting_changed_cb(GSettings * settings,char * key,EphyEmbedShell * shell)862 remember_passwords_setting_changed_cb (GSettings *settings,
863 char *key,
864 EphyEmbedShell *shell)
865 {
866 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
867 gboolean should_remember_passwords;
868
869 should_remember_passwords = g_settings_get_boolean (EPHY_SETTINGS_WEB, EPHY_PREFS_WEB_REMEMBER_PASSWORDS);
870
871 webkit_web_context_send_message_to_all_extensions (priv->web_context,
872 webkit_user_message_new ("PasswordManager.SetShouldRememberPasswords",
873 g_variant_new ("b", should_remember_passwords)));
874 }
875
876 static void
enable_itp_setting_changed_cb(GSettings * settings,char * key,EphyEmbedShell * shell)877 enable_itp_setting_changed_cb (GSettings *settings,
878 char *key,
879 EphyEmbedShell *shell)
880 {
881 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
882 WebKitWebsiteDataManager *manager;
883
884 manager = webkit_web_context_get_website_data_manager (priv->web_context);
885 webkit_website_data_manager_set_itp_enabled (manager,
886 g_settings_get_boolean (EPHY_SETTINGS_WEB,
887 EPHY_PREFS_WEB_ENABLE_ITP));
888 }
889
890 static void
update_system_scrollbars(EphyEmbedShell * shell)891 update_system_scrollbars (EphyEmbedShell *shell)
892 {
893 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
894 const char *theme_name;
895 gboolean enabled;
896
897 g_object_get (gtk_settings_get_default (),
898 "gtk-theme_name", &theme_name,
899 NULL);
900
901 /* Don't enable system scrollbars for Adwaita */
902 enabled = g_strcmp0 (theme_name, "Adwaita") &&
903 g_strcmp0 (theme_name, "Adwaita-dark") &&
904 g_strcmp0 (theme_name, "HighContrast") &&
905 g_strcmp0 (theme_name, "HighContrastInverse");
906
907 webkit_web_context_set_use_system_appearance_for_scrollbars (priv->web_context,
908 enabled);
909 }
910
911 static void
ephy_embed_shell_startup(GApplication * application)912 ephy_embed_shell_startup (GApplication *application)
913 {
914 EphyEmbedShell *shell = EPHY_EMBED_SHELL (application);
915 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
916 g_autofree char *favicon_db_path = NULL;
917 WebKitCookieManager *cookie_manager;
918 g_autofree char *filename = NULL;
919
920 G_APPLICATION_CLASS (ephy_embed_shell_parent_class)->startup (application);
921
922 webkit_web_context_set_process_model (priv->web_context, WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES);
923
924 webkit_web_context_set_sandbox_enabled (priv->web_context, TRUE);
925 webkit_web_context_add_path_to_sandbox (priv->web_context, ephy_profile_dir (), TRUE);
926 webkit_web_context_add_path_to_sandbox (priv->web_context, ephy_cache_dir (), TRUE);
927 webkit_web_context_add_path_to_sandbox (priv->web_context, ephy_config_dir (), TRUE);
928
929 #if DEVELOPER_MODE
930 webkit_web_context_add_path_to_sandbox (priv->web_context, BUILD_ROOT, TRUE);
931 #endif
932
933 g_signal_connect_object (priv->web_context, "initialize-web-extensions",
934 G_CALLBACK (initialize_web_process_extensions),
935 shell, 0);
936
937 g_signal_connect_object (priv->web_context, "initialize-notification-permissions",
938 G_CALLBACK (initialize_notification_permissions),
939 shell, 0);
940
941 priv->password_manager = ephy_password_manager_new ();
942
943 /* Do not cache favicons in automation mode. Don't change the TLS policy either, since that's
944 * handled by session capabilities in automation mode.
945 */
946 if (priv->mode != EPHY_EMBED_SHELL_MODE_AUTOMATION) {
947 /* Favicon Database */
948 favicon_db_path = g_build_filename (ephy_cache_dir (), "icondatabase", NULL);
949 webkit_web_context_set_favicon_database_directory (priv->web_context, favicon_db_path);
950 }
951
952 /* about: URIs handler */
953 priv->about_handler = ephy_about_handler_new ();
954 webkit_web_context_register_uri_scheme (priv->web_context,
955 EPHY_ABOUT_SCHEME,
956 (WebKitURISchemeRequestCallback)about_request_cb,
957 shell, NULL);
958
959 /* Register about scheme as local so that it can contain file resources */
960 webkit_security_manager_register_uri_scheme_as_local (webkit_web_context_get_security_manager (priv->web_context),
961 EPHY_ABOUT_SCHEME);
962
963 /* view source handler */
964 priv->source_handler = ephy_view_source_handler_new ();
965 webkit_web_context_register_uri_scheme (priv->web_context, EPHY_VIEW_SOURCE_SCHEME,
966 (WebKitURISchemeRequestCallback)source_request_cb,
967 shell, NULL);
968 /* pdf handler */
969 priv->pdf_handler = ephy_pdf_handler_new ();
970 webkit_web_context_register_uri_scheme (priv->web_context, EPHY_PDF_SCHEME,
971 (WebKitURISchemeRequestCallback)pdf_request_cb,
972 shell, NULL);
973
974 /* reader mode handler */
975 priv->reader_handler = ephy_reader_handler_new ();
976 webkit_web_context_register_uri_scheme (priv->web_context, EPHY_READER_SCHEME,
977 (WebKitURISchemeRequestCallback)reader_request_cb,
978 shell, NULL);
979
980 /* ephy-resource handler */
981 webkit_web_context_register_uri_scheme (priv->web_context, "ephy-resource",
982 (WebKitURISchemeRequestCallback)ephy_resource_request_cb,
983 NULL, NULL);
984 webkit_security_manager_register_uri_scheme_as_secure (webkit_web_context_get_security_manager (priv->web_context),
985 "ephy-resource");
986
987 /* Store cookies in moz-compatible SQLite format */
988 cookie_manager = webkit_web_context_get_cookie_manager (priv->web_context);
989 if (!webkit_web_context_is_ephemeral (priv->web_context)) {
990 filename = g_build_filename (ephy_profile_dir (), "cookies.sqlite", NULL);
991 webkit_cookie_manager_set_persistent_storage (cookie_manager, filename,
992 WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE);
993 }
994
995 g_signal_connect_object (priv->web_context, "download-started",
996 G_CALLBACK (download_started_cb), shell, 0);
997
998 g_signal_connect_object (EPHY_SETTINGS_WEB, "changed::remember-passwords",
999 G_CALLBACK (remember_passwords_setting_changed_cb), shell, 0);
1000
1001 g_signal_connect_object (EPHY_SETTINGS_WEB, "changed::enable-itp",
1002 G_CALLBACK (enable_itp_setting_changed_cb), shell, 0);
1003
1004 update_system_scrollbars (shell);
1005
1006 g_signal_connect_swapped (gtk_settings_get_default (),
1007 "notify::gtk-theme-name",
1008 G_CALLBACK (update_system_scrollbars),
1009 shell);
1010 }
1011
1012 static void
ephy_embed_shell_shutdown(GApplication * application)1013 ephy_embed_shell_shutdown (GApplication *application)
1014 {
1015 G_APPLICATION_CLASS (ephy_embed_shell_parent_class)->shutdown (application);
1016
1017 g_object_unref (ephy_embed_prefs_get_settings ());
1018 ephy_embed_utils_shutdown ();
1019 }
1020
1021 static void
ephy_embed_shell_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1022 ephy_embed_shell_set_property (GObject *object,
1023 guint prop_id,
1024 const GValue *value,
1025 GParamSpec *pspec)
1026 {
1027 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (EPHY_EMBED_SHELL (object));
1028
1029 switch (prop_id) {
1030 case PROP_MODE:
1031 priv->mode = g_value_get_enum (value);
1032 break;
1033 default:
1034 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1035 }
1036 }
1037
1038 static void
ephy_embed_shell_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1039 ephy_embed_shell_get_property (GObject *object,
1040 guint prop_id,
1041 GValue *value,
1042 GParamSpec *pspec)
1043 {
1044 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (EPHY_EMBED_SHELL (object));
1045
1046 switch (prop_id) {
1047 case PROP_MODE:
1048 g_value_set_enum (value, priv->mode);
1049 break;
1050 default:
1051 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1052 }
1053 }
1054
1055 static void
ephy_embed_shell_constructed(GObject * object)1056 ephy_embed_shell_constructed (GObject *object)
1057 {
1058 EphyEmbedShell *shell;
1059 EphyEmbedShellPrivate *priv;
1060
1061 G_OBJECT_CLASS (ephy_embed_shell_parent_class)->constructed (object);
1062
1063 shell = EPHY_EMBED_SHELL (object);
1064 priv = ephy_embed_shell_get_instance_private (shell);
1065 priv->guid = g_dbus_generate_guid ();
1066
1067 ephy_embed_shell_create_web_context (shell);
1068
1069 priv->permissions_manager = ephy_permissions_manager_new ();
1070 priv->filters_manager = ephy_filters_manager_new (NULL);
1071 }
1072
1073 static void
ephy_embed_shell_init(EphyEmbedShell * shell)1074 ephy_embed_shell_init (EphyEmbedShell *shell)
1075 {
1076 /* globally accessible singleton */
1077 g_assert (!embed_shell);
1078 embed_shell = shell;
1079 }
1080
1081 static void
ephy_embed_shell_class_init(EphyEmbedShellClass * klass)1082 ephy_embed_shell_class_init (EphyEmbedShellClass *klass)
1083 {
1084 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1085 GApplicationClass *application_class = G_APPLICATION_CLASS (klass);
1086
1087 object_class->dispose = ephy_embed_shell_dispose;
1088 object_class->set_property = ephy_embed_shell_set_property;
1089 object_class->get_property = ephy_embed_shell_get_property;
1090 object_class->constructed = ephy_embed_shell_constructed;
1091
1092 application_class->startup = ephy_embed_shell_startup;
1093 application_class->shutdown = ephy_embed_shell_shutdown;
1094
1095 object_properties[PROP_MODE] =
1096 g_param_spec_enum ("mode",
1097 "Mode",
1098 "The global mode for this instance.",
1099 EPHY_TYPE_EMBED_SHELL_MODE,
1100 EPHY_EMBED_SHELL_MODE_BROWSER,
1101 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
1102
1103 g_object_class_install_properties (object_class,
1104 N_PROPERTIES,
1105 object_properties);
1106
1107 /**
1108 * EphyEmbedShell::finished-restoring-window:
1109 * @shell: the #EphyEmbedShell
1110 *
1111 * The ::finished-restoring-window signal is emitted when the
1112 * session finishes restoring a window.
1113 **/
1114 signals[RESTORED_WINDOW] =
1115 g_signal_new ("window-restored",
1116 EPHY_TYPE_EMBED_SHELL,
1117 G_SIGNAL_RUN_FIRST,
1118 G_STRUCT_OFFSET (EphyEmbedShellClass, restored_window),
1119 NULL, NULL, NULL,
1120 G_TYPE_NONE,
1121 0);
1122
1123 /**
1124 * EphyEmbedShell::web-view-created:
1125 * @shell: the #EphyEmbedShell
1126 * @view: the newly created #EphyWebView
1127 *
1128 * The ::web-view-created signal will be emitted every time a new
1129 * #EphyWebView is created.
1130 *
1131 **/
1132 signals[WEB_VIEW_CREATED] =
1133 g_signal_new ("web-view-created",
1134 EPHY_TYPE_EMBED_SHELL,
1135 G_SIGNAL_RUN_LAST,
1136 0, NULL, NULL, NULL,
1137 G_TYPE_NONE, 1,
1138 EPHY_TYPE_WEB_VIEW);
1139
1140 /**
1141 * EphyEmbedShell::allow-tls-certificate:
1142 * @shell: the #EphyEmbedShell
1143 * @page_id: the identifier of the web page
1144 *
1145 * Emitted when the web process extension requests an exception be
1146 * permitted for the invalid TLS certificate on the given page
1147 */
1148 signals[ALLOW_TLS_CERTIFICATE] =
1149 g_signal_new ("allow-tls-certificate",
1150 EPHY_TYPE_EMBED_SHELL,
1151 G_SIGNAL_RUN_FIRST,
1152 0, NULL, NULL, NULL,
1153 G_TYPE_NONE, 1,
1154 G_TYPE_UINT64);
1155
1156 /**
1157 * EphyEmbedShell::allow-unsafe-browsing:
1158 * @shell: the #EphyEmbedShell
1159 * @page_id: the identifier of the web page
1160 *
1161 * Emitted when the web process extension requests an exception be
1162 * permitted for the unsafe browsing warning on the given page
1163 */
1164 signals[ALLOW_UNSAFE_BROWSING] =
1165 g_signal_new ("allow-unsafe-browsing",
1166 EPHY_TYPE_EMBED_SHELL,
1167 G_SIGNAL_RUN_FIRST,
1168 0, NULL, NULL, NULL,
1169 G_TYPE_NONE, 1,
1170 G_TYPE_UINT64);
1171
1172 /**
1173 * EphyEmbedShell::password-form-focused
1174 * @shell: the #EphyEmbedShell
1175 * @page_id: the identifier of the web page
1176 * @insecure_action: whether the target of the form is http://
1177 *
1178 * Emitted when a form in a web page gains focus.
1179 */
1180 signals[PASSWORD_FORM_FOCUSED] =
1181 g_signal_new ("password-form-focused",
1182 EPHY_TYPE_EMBED_SHELL,
1183 G_SIGNAL_RUN_FIRST,
1184 0, NULL, NULL, NULL,
1185 G_TYPE_NONE, 2,
1186 G_TYPE_UINT64,
1187 G_TYPE_BOOLEAN);
1188 }
1189
1190 /**
1191 * ephy_embed_shell_get_default:
1192 *
1193 * Retrieves the default #EphyEmbedShell object
1194 *
1195 * Return value: (transfer none): the default #EphyEmbedShell
1196 **/
1197 EphyEmbedShell *
ephy_embed_shell_get_default(void)1198 ephy_embed_shell_get_default (void)
1199 {
1200 return embed_shell;
1201 }
1202
1203 void
ephy_embed_shell_set_page_setup(EphyEmbedShell * shell,GtkPageSetup * page_setup)1204 ephy_embed_shell_set_page_setup (EphyEmbedShell *shell,
1205 GtkPageSetup *page_setup)
1206 {
1207 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
1208 g_autofree char *path = NULL;
1209
1210 g_assert (EPHY_IS_EMBED_SHELL (shell));
1211
1212 if (page_setup)
1213 g_object_ref (page_setup);
1214 else
1215 page_setup = gtk_page_setup_new ();
1216
1217 if (priv->page_setup)
1218 g_object_unref (priv->page_setup);
1219
1220 priv->page_setup = page_setup;
1221
1222 path = g_build_filename (ephy_profile_dir (), PAGE_SETUP_FILENAME, NULL);
1223 gtk_page_setup_to_file (page_setup, path, NULL);
1224 }
1225
1226 /**
1227 * ephy_embed_shell_get_page_setup:
1228 *
1229 * Return value: (transfer none):
1230 **/
1231 GtkPageSetup *
ephy_embed_shell_get_page_setup(EphyEmbedShell * shell)1232 ephy_embed_shell_get_page_setup (EphyEmbedShell *shell)
1233 {
1234 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
1235
1236 g_assert (EPHY_IS_EMBED_SHELL (shell));
1237
1238 if (!priv->page_setup) {
1239 g_autofree char *path = NULL;
1240
1241 path = g_build_filename (ephy_profile_dir (), PAGE_SETUP_FILENAME, NULL);
1242 priv->page_setup = gtk_page_setup_new_from_file (path, NULL);
1243
1244 /* If that still didn't work, create a new, empty one */
1245 if (!priv->page_setup)
1246 priv->page_setup = gtk_page_setup_new ();
1247 }
1248
1249 return priv->page_setup;
1250 }
1251
1252 /**
1253 * ephy_embed_shell_set_print_settings:
1254 * @shell: the #EphyEmbedShell
1255 * @settings: the new #GtkPrintSettings object
1256 *
1257 * Sets the global #GtkPrintSettings object.
1258 *
1259 **/
1260 void
ephy_embed_shell_set_print_settings(EphyEmbedShell * shell,GtkPrintSettings * settings)1261 ephy_embed_shell_set_print_settings (EphyEmbedShell *shell,
1262 GtkPrintSettings *settings)
1263 {
1264 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
1265 g_autofree char *path = NULL;
1266
1267 g_assert (EPHY_IS_EMBED_SHELL (shell));
1268
1269 if (settings)
1270 g_object_ref (settings);
1271
1272 if (priv->print_settings)
1273 g_object_unref (priv->print_settings);
1274
1275 priv->print_settings = settings ? settings : gtk_print_settings_new ();
1276
1277 path = g_build_filename (ephy_profile_dir (), PRINT_SETTINGS_FILENAME, NULL);
1278 gtk_print_settings_to_file (settings, path, NULL);
1279 }
1280
1281 /**
1282 * ephy_embed_shell_get_print_settings:
1283 * @shell: the #EphyEmbedShell
1284 *
1285 * Gets the global #GtkPrintSettings object.
1286 *
1287 * Returns: (transfer none): a #GtkPrintSettings object
1288 **/
1289 GtkPrintSettings *
ephy_embed_shell_get_print_settings(EphyEmbedShell * shell)1290 ephy_embed_shell_get_print_settings (EphyEmbedShell *shell)
1291 {
1292 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
1293
1294 g_assert (EPHY_IS_EMBED_SHELL (shell));
1295
1296 if (!priv->print_settings) {
1297 g_autofree char *path = NULL;
1298
1299 path = g_build_filename (ephy_profile_dir (), PRINT_SETTINGS_FILENAME, NULL);
1300 priv->print_settings = gtk_print_settings_new_from_file (path, NULL);
1301
1302 /* Note: the gtk print settings file format is the same as our
1303 * legacy one, so no need to migrate here.
1304 */
1305
1306 if (!priv->print_settings)
1307 priv->print_settings = gtk_print_settings_new ();
1308 }
1309
1310 return priv->print_settings;
1311 }
1312
1313 /**
1314 * ephy_embed_shell_get_mode:
1315 * @shell: an #EphyEmbedShell
1316 *
1317 * Returns: the global mode of the @shell
1318 **/
1319 EphyEmbedShellMode
ephy_embed_shell_get_mode(EphyEmbedShell * shell)1320 ephy_embed_shell_get_mode (EphyEmbedShell *shell)
1321 {
1322 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
1323
1324 g_assert (EPHY_IS_EMBED_SHELL (shell));
1325
1326 return priv->mode;
1327 }
1328
1329 /**
1330 * ephy_embed_shell_clear_cache:
1331 * @shell: an #EphyEmbedShell
1332 *
1333 * Clears the HTTP cache (temporarily saved web pages).
1334 **/
1335 void
ephy_embed_shell_clear_cache(EphyEmbedShell * shell)1336 ephy_embed_shell_clear_cache (EphyEmbedShell *shell)
1337 {
1338 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
1339
1340 webkit_web_context_clear_cache (priv->web_context);
1341 }
1342
1343 EphyFiltersManager *
ephy_embed_shell_get_filters_manager(EphyEmbedShell * shell)1344 ephy_embed_shell_get_filters_manager (EphyEmbedShell *shell)
1345 {
1346 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
1347
1348 return priv->filters_manager;
1349 }
1350
1351 const char *
ephy_embed_shell_get_guid(EphyEmbedShell * shell)1352 ephy_embed_shell_get_guid (EphyEmbedShell *shell)
1353 {
1354 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
1355
1356 return priv->guid;
1357 }
1358
1359 WebKitWebContext *
ephy_embed_shell_get_web_context(EphyEmbedShell * shell)1360 ephy_embed_shell_get_web_context (EphyEmbedShell *shell)
1361 {
1362 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
1363
1364 return priv->web_context;
1365 }
1366
1367 EphyDownloadsManager *
ephy_embed_shell_get_downloads_manager(EphyEmbedShell * shell)1368 ephy_embed_shell_get_downloads_manager (EphyEmbedShell *shell)
1369 {
1370 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
1371
1372 if (!priv->downloads_manager)
1373 priv->downloads_manager = EPHY_DOWNLOADS_MANAGER (g_object_new (EPHY_TYPE_DOWNLOADS_MANAGER, NULL));
1374 return priv->downloads_manager;
1375 }
1376
1377 EphyPermissionsManager *
ephy_embed_shell_get_permissions_manager(EphyEmbedShell * shell)1378 ephy_embed_shell_get_permissions_manager (EphyEmbedShell *shell)
1379 {
1380 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
1381
1382 return priv->permissions_manager;
1383 }
1384
1385 EphySearchEngineManager *
ephy_embed_shell_get_search_engine_manager(EphyEmbedShell * shell)1386 ephy_embed_shell_get_search_engine_manager (EphyEmbedShell *shell)
1387 {
1388 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
1389
1390 if (!priv->search_engine_manager)
1391 priv->search_engine_manager = ephy_search_engine_manager_new ();
1392 return priv->search_engine_manager;
1393 }
1394
1395 EphyPasswordManager *
ephy_embed_shell_get_password_manager(EphyEmbedShell * shell)1396 ephy_embed_shell_get_password_manager (EphyEmbedShell *shell)
1397 {
1398 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
1399
1400 return priv->password_manager;
1401 }
1402
1403 void
ephy_embed_shell_register_ucm_handler(EphyEmbedShell * shell,WebKitUserContentManager * ucm)1404 ephy_embed_shell_register_ucm_handler (EphyEmbedShell *shell,
1405 WebKitUserContentManager *ucm)
1406 {
1407 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
1408
1409 /* User content manager */
1410 webkit_user_content_manager_register_script_message_handler_in_world (ucm,
1411 "overview",
1412 priv->guid);
1413 g_signal_connect_object (ucm, "script-message-received::overview",
1414 G_CALLBACK (web_process_extension_overview_message_received_cb),
1415 shell, 0);
1416
1417 webkit_user_content_manager_register_script_message_handler (ucm,
1418 "tlsErrorPage");
1419 g_signal_connect_object (ucm, "script-message-received::tlsErrorPage",
1420 G_CALLBACK (web_process_extension_tls_error_page_message_received_cb),
1421 shell, 0);
1422
1423 webkit_user_content_manager_register_script_message_handler (ucm,
1424 "unsafeBrowsingErrorPage");
1425 g_signal_connect_object (ucm, "script-message-received::unsafeBrowsingErrorPage",
1426 G_CALLBACK (web_process_extension_unsafe_browsing_error_page_message_received_cb),
1427 shell, 0);
1428
1429 webkit_user_content_manager_register_script_message_handler_in_world (ucm,
1430 "passwordFormFocused",
1431 priv->guid);
1432 g_signal_connect_object (ucm, "script-message-received::passwordFormFocused",
1433 G_CALLBACK (web_process_extension_password_form_focused_message_received_cb),
1434 shell, 0);
1435
1436 webkit_user_content_manager_register_script_message_handler (ucm,
1437 "aboutApps");
1438 g_signal_connect_object (ucm, "script-message-received::aboutApps",
1439 G_CALLBACK (web_process_extension_about_apps_message_received_cb),
1440 shell, 0);
1441
1442 webkit_user_content_manager_register_script_message_handler_in_world (ucm,
1443 "passwordManagerSave",
1444 priv->guid);
1445 g_signal_connect_object (ucm, "script-message-received::passwordManagerSave",
1446 G_CALLBACK (web_process_extension_password_manager_save_received_cb),
1447 shell, 0);
1448
1449 webkit_user_content_manager_register_script_message_handler_in_world (ucm,
1450 "passwordManagerRequestSave",
1451 priv->guid);
1452 g_signal_connect_object (ucm, "script-message-received::passwordManagerRequestSave",
1453 G_CALLBACK (web_process_extension_password_manager_request_save_received_cb),
1454 shell, 0);
1455
1456 /* Filter Manager */
1457 g_signal_connect_object (priv->filters_manager, "filters-disabled",
1458 G_CALLBACK (webkit_user_content_manager_remove_all_filters),
1459 ucm,
1460 G_CONNECT_SWAPPED);
1461 g_signal_connect_object (priv->filters_manager, "filter-ready",
1462 G_CALLBACK (webkit_user_content_manager_add_filter),
1463 ucm,
1464 G_CONNECT_SWAPPED);
1465 g_signal_connect_object (priv->filters_manager, "filter-removed",
1466 G_CALLBACK (webkit_user_content_manager_remove_filter_by_id),
1467 ucm,
1468 G_CONNECT_SWAPPED);
1469
1470 /* User Scripts */
1471 ephy_embed_prefs_apply_user_style (ucm);
1472 ephy_embed_prefs_apply_user_javascript (ucm);
1473 }
1474
1475 void
ephy_embed_shell_unregister_ucm_handler(EphyEmbedShell * shell,WebKitUserContentManager * ucm)1476 ephy_embed_shell_unregister_ucm_handler (EphyEmbedShell *shell,
1477 WebKitUserContentManager *ucm)
1478 {
1479 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
1480
1481 webkit_user_content_manager_unregister_script_message_handler_in_world (ucm,
1482 "overview",
1483 priv->guid);
1484 webkit_user_content_manager_unregister_script_message_handler (ucm,
1485 "tlsErrorPage");
1486 webkit_user_content_manager_unregister_script_message_handler (ucm,
1487 "unsafeBrowsingErrorPage");
1488 webkit_user_content_manager_unregister_script_message_handler_in_world (ucm,
1489 "passwordManagerRequestSave",
1490 priv->guid);
1491 webkit_user_content_manager_unregister_script_message_handler_in_world (ucm,
1492 "passwordFormFocused",
1493 priv->guid);
1494 webkit_user_content_manager_unregister_script_message_handler (ucm, "aboutApps");
1495 webkit_user_content_manager_unregister_script_message_handler_in_world (ucm,
1496 "passwordManagerSave",
1497 priv->guid);
1498 }
1499
1500 void
ephy_embed_shell_pdf_handler_stop(EphyEmbedShell * shell,WebKitWebView * web_view)1501 ephy_embed_shell_pdf_handler_stop (EphyEmbedShell *shell,
1502 WebKitWebView *web_view)
1503 {
1504 EphyEmbedShellPrivate *priv = ephy_embed_shell_get_instance_private (shell);
1505
1506 ephy_pdf_handler_stop (priv->pdf_handler, web_view);
1507 }
1508