context.py 11.6 KB
Newer Older
Cédric Bellegarde's avatar
Cédric Bellegarde committed
1
# Copyright (c) 2017-2018 Cedric Bellegarde <cedric.bellegarde@adishatz.org>
2 3 4 5 6 7 8 9 10 11 12
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

Cédric Bellegarde's avatar
Cédric Bellegarde committed
13
from gi.repository import GLib, Gio, Gtk, WebKit2
14 15 16

from urllib.parse import urlparse
from gettext import gettext as _
17
from datetime import datetime
18

Cédric Bellegarde's avatar
Cédric Bellegarde committed
19
from eolie.define import App, COOKIES_PATH, EOLIE_DATA_PATH
20 21 22 23 24 25 26 27 28 29 30 31 32


class Context:
    """
        Handle context signals
    """

    def __init__(self, context):
        """
            Init context
            @param context as WebKit2.WebContext
        """
        self.__context = context
33 34
        if not context.is_ephemeral():
            context.set_cache_model(WebKit2.CacheModel.WEB_BROWSER)
35
            context.set_favicon_database_directory(App().favicons_path)
36 37
            cookie_manager = context.get_cookie_manager()
            cookie_manager.set_accept_policy(
Cédric Bellegarde's avatar
Cédric Bellegarde committed
38
                App().settings.get_enum("cookie-storage"))
Cédric Bellegarde's avatar
Cédric Bellegarde committed
39 40 41 42
            path = COOKIES_PATH % (EOLIE_DATA_PATH, "default")
            cookie_manager.set_persistent_storage(
                path,
                WebKit2.CookiePersistentStorage.SQLITE)
43
        context.set_web_extensions_directory(App().extension_dir)
44
        context.set_process_model(
Cédric Bellegarde's avatar
Cédric Bellegarde committed
45
            WebKit2.ProcessModel.MULTIPLE_SECONDARY_PROCESSES)
46
        context.set_spell_checking_enabled(
Cédric Bellegarde's avatar
Cédric Bellegarde committed
47
            App().settings.get_value("enable-spell-check"))
48 49 50
        context.register_uri_scheme("populars", self.__on_populars_scheme)
        context.register_uri_scheme("internal", self.__on_internal_scheme)
        context.register_uri_scheme("accept", self.__on_accept_scheme)
51
        context.register_uri_scheme("file", self.__on_file_scheme)
52 53 54 55 56 57 58 59 60 61 62 63
        context.get_security_manager().register_uri_scheme_as_local("populars")
        # We allow DownloadPopover to connect before default context
        context.connect_after("download-started", self.__on_download_started)

#######################
# PRIVATE             #
#######################
    def __on_populars_scheme(self, request):
        """
            Show populars web pages
            @param request as WebKit2.URISchemeRequest
        """
64 65
        uri = request.get_uri()
        parsed = urlparse(uri)
66
        items = []
67 68
        start_page = App().settings.get_value("start-page").get_string()
        wanted = App().settings.get_value("max-popular-items").get_int32()
69
        if start_page == "popular_book":
70
            reset_function = "reset_bookmark"
71
            for (item_id, uri, title) in App().bookmarks.get_populars(wanted):
72
                items.append((title, uri, "", 1))
73
        else:
74
            reset_function = "reset_history"
75
            for (item_id, uri,
76
                 netloc, title, count) in App().history.get_populars(
Cédric Bellegarde's avatar
Cédric Bellegarde committed
77 78
                    parsed.netloc,
                    wanted):
79
                items.append((title, uri, netloc, count))
80 81 82 83 84 85 86
        start = Gio.File.new_for_uri("resource:///org/gnome/Eolie/start.html")
        end = Gio.File.new_for_uri("resource:///org/gnome/Eolie/end.html")
        (status, start_content, tag) = start.load_contents(None)
        (status, end_content, tag) = end.load_contents(None)
        # Update start
        html_start = start_content.decode("utf-8")
        html_start = html_start.replace("@TITLE@", _("Popular pages"))
87 88 89 90
        fake = Gtk.Entry.new()
        style_context = fake.get_style_context()
        (found, color) = style_context.lookup_color("theme_selected_bg_color")
        if found:
91
            color.alpha = 0.2
92 93 94 95
            html_start = html_start.replace("@BACKGROUND_COLOR@",
                                            color.to_string())
        else:
            html_start = html_start.replace("@BACKGROUND_COLOR@",
96
                                            "rgba(74,144,217,0.2)")
97
        idx = 0
98
        for (title, uri, netloc, count) in items:
99 100
            element_id = "element_%s" % idx
            idx += 1
101 102
            if count == 1:  # No navigation for one page
                netloc = uri
103
            path = App().art.get_path(uri, "start")
104 105
            if path is None or\
                    not GLib.file_test(path, GLib.FileTest.IS_REGULAR):
Cédric Bellegarde's avatar
Cédric Bellegarde committed
106
                continue
107
            favicon_path = App().art.get_favicon_path(netloc)
108 109
            if favicon_path is not None:
                favicon_uri = "file://%s" % favicon_path
110
            else:
111 112 113
                favicon_uri = "internal://applications-internet"
            html_start += '<a class="child" id="%s"\
                           title="%s" href="%s">\
Cédric Bellegarde's avatar
Cédric Bellegarde committed
114
                           <img src="file://%s"></img>\
115
                           <div class="caption">%s\
116 117 118
                           <img onclick="%s(event, %s, %s)"\
                                class="close_button">\
                           <img class="favicon" src="%s">\
119
                           </img></img></div></a>' % (
Cédric Bellegarde's avatar
Cédric Bellegarde committed
120 121 122 123
                element_id, title, netloc, path,
                title, reset_function,
                "'%s'" % netloc,
                "'%s'" % element_id, favicon_uri)
124 125 126 127
        html = html_start.encode("utf-8") + end_content
        stream = Gio.MemoryInputStream.new_from_data(html)
        request.finish(stream, -1, "text/html")

128 129 130 131 132
    def __on_file_scheme(self, request):
        """
            Show populars web pages
            @param request as WebKit2.URISchemeRequest
        """
Cédric Bellegarde's avatar
Cédric Bellegarde committed
133 134 135 136 137 138 139 140 141
        try:
            uri = request.get_uri()
            parent = "/".join(uri.rstrip("/").split("/")[:-1])
            f = Gio.File.new_for_uri(uri)
            info = f.query_info("standard::type",
                                Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
                                None)
            if info.get_file_type() == Gio.FileType.DIRECTORY:
                start = Gio.File.new_for_uri(
Cédric Bellegarde's avatar
Cédric Bellegarde committed
142
                    "resource:///org/gnome/Eolie/start_file.html")
Cédric Bellegarde's avatar
Cédric Bellegarde committed
143
                end = Gio.File.new_for_uri(
Cédric Bellegarde's avatar
Cédric Bellegarde committed
144
                    "resource:///org/gnome/Eolie/end_file.html")
Cédric Bellegarde's avatar
Cédric Bellegarde committed
145 146 147 148 149 150 151 152 153
                (status, start_content, tag) = start.load_contents(None)
                (status, end_content, tag) = end.load_contents(None)
                html_start = start_content.decode("utf-8")
                html_start = html_start.replace("@PATH@", f.get_path())
                html_start = html_start.replace("@NAME@", _("Name"))
                html_start = html_start.replace("@SIZE@", _("Size"))
                html_start = html_start.replace("@LAST_MODIFICATION@",
                                                _("Last modification"))
                if parent:
Cédric Bellegarde's avatar
Cédric Bellegarde committed
154 155
                    html_start += '<tr>'\
                                  '<td><a class="dir" href="%s">%s</a></td>'\
Cédric Bellegarde's avatar
Cédric Bellegarde committed
156 157
                                  '<td></td>'\
                                  '<td></td></tr>' % (
Cédric Bellegarde's avatar
Cédric Bellegarde committed
158
                                      parent, "..")
Cédric Bellegarde's avatar
Cédric Bellegarde committed
159 160
                try:
                    infos = f.enumerate_children(
Cédric Bellegarde's avatar
Cédric Bellegarde committed
161 162 163 164
                        "standard::name,standard::size,"
                        "standard::type,time::modified",
                        Gio.FileQueryInfoFlags.NONE,
                        None)
Cédric Bellegarde's avatar
Cédric Bellegarde committed
165 166 167 168 169 170 171 172 173 174 175 176
                    dirs = {}
                    files = {}
                    for info in infos:
                        name = info.get_name()
                        if f.get_path() == "/":
                            filename = "/%s" % name
                        else:
                            filename = "%s/%s" % (f.get_path(), name)
                        uri = GLib.filename_to_uri(filename)
                        mtime = info.get_attribute_uint64("time::modified")
                        size = round((info.get_size() / 1024), 2)
                        date_str = datetime.fromtimestamp(mtime).strftime(
Cédric Bellegarde's avatar
Cédric Bellegarde committed
177
                            "%Y-%m-%d %H:%M:%S")
Cédric Bellegarde's avatar
Cédric Bellegarde committed
178 179 180 181 182 183 184 185 186 187
                        if info.get_file_type() == Gio.FileType.DIRECTORY:
                            dirs[uri] = (name, size, date_str)
                        else:
                            files[uri] = (name, size, date_str)
                    for uri, (name, size, date_str) in sorted(dirs.items()):
                        html_start += '<tr>'\
                                      '<td><a class="dir" href="%s">'\
                                      '%s</a></td>'\
                                      '<td>%s KB</td>'\
                                      '<td>%s</td></tr>' % (
Cédric Bellegarde's avatar
Cédric Bellegarde committed
188
                                          uri, name, size, date_str)
Cédric Bellegarde's avatar
Cédric Bellegarde committed
189 190 191 192 193 194
                    for uri, (name, size, date_str) in sorted(files.items()):
                        html_start += '<tr>'\
                                      '<td><a class="file" href="%s">'\
                                      '%s</a></td>'\
                                      '<td>%s KB</td>'\
                                      '<td>%s</td></tr>' % (
Cédric Bellegarde's avatar
Cédric Bellegarde committed
195
                                          uri, name, size, date_str)
Cédric Bellegarde's avatar
Cédric Bellegarde committed
196 197
                except Exception as e:
                    infos = []
Cédric Bellegarde's avatar
Cédric Bellegarde committed
198
                    html_start += '<tr>'\
Cédric Bellegarde's avatar
Cédric Bellegarde committed
199 200 201 202 203 204 205 206 207 208 209 210 211
                                  '<td>%s</td>'\
                                  '<td></td>'\
                                  '<td></td></tr>' % e
                html = html_start.encode("utf-8") + end_content
                stream = Gio.MemoryInputStream.new_from_data(html)
                request.finish(stream, -1, "text/html")
            else:
                request.finish(f.read(), -1, None)
        except Exception as e:
            request.get_web_view().emit("load-failed",
                                        WebKit2.LoadEvent.FINISHED,
                                        uri,
                                        GLib.Error(str(e)))
212

213 214 215 216 217
    def __on_internal_scheme(self, request):
        """
            Load an internal resource
            @param request as WebKit2.URISchemeRequest
        """
218 219
        # We use internal:// because resource:// is already used by WebKit2
        icon_name = request.get_uri().replace("internal://", "")
220
        icon_info = Gtk.IconTheme.get_default().lookup_icon(
221
            icon_name, 22,
Cédric Bellegarde's avatar
Cédric Bellegarde committed
222
            Gtk.IconLookupFlags.FORCE_SVG)
223 224
        if icon_info is None:
            return
225
        filename = icon_info.get_filename()
226 227 228 229
        if filename.endswith(".png"):
            mime = "image/png"
        else:
            mime = "image/svg+xml"
230
        f = Gio.File.new_for_path(filename)
231
        request.finish(f.read(), -1, mime)
232 233 234 235 236 237 238 239 240

    def __on_accept_scheme(self, request):
        """
            Accept certificate for uri
            @param request as WebKit2.URISchemeRequest
        """
        view = request.get_web_view()
        if view.bad_tls is None:
            return
241 242 243
        request_uri = request.get_uri()
        parsed = urlparse(request_uri)
        uri = request_uri.replace("accept://", "https://")
244 245
        if not App().websettings.get_accept_tls(uri):
            App().websettings.set_accept_tls(uri, True)
246
        self.__context.allow_tls_certificate_for_host(
Cédric Bellegarde's avatar
Cédric Bellegarde committed
247 248 249
            view.bad_tls,
            # Remove port
            parsed.netloc.split(":")[0])
250
        view.load_uri(uri)
251 252 253 254 255 256 257

    def __on_download_started(self, context, download):
        """
            A new download started, handle signals
            @param context as WebKit2.WebContext
            @param download as WebKit2.Download
        """
258
        App().download_manager.add(download)