1/* 2 Copyright (C) 2009-2018 Christian Dywan <christian@twotoats.de> 3 Copyright (C) 2009-2012 Alexander Butenko <a.butenka@gmail.com> 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 See the file COPYING for the full license text. 11*/ 12 13namespace Adblock { 14 public class Button : Gtk.Button { 15 public string icon_name { get; protected set; } 16 Settings settings = Settings.get_default (); 17 18 construct { 19 action_name = "win.adblock-status"; 20 tooltip_text = _("Advertisement blocker"); 21 var image = new Gtk.Image.from_icon_name (icon_name, Gtk.IconSize.BUTTON); 22 bind_property ("icon-name", image, "icon-name"); 23 image.use_fallback = true; 24 image.show (); 25 add (image); 26 settings.notify["enabled"].connect (update_icon); 27 update_icon (); 28 show (); 29 } 30 31 void update_icon () { 32 icon_name = "security-%s-symbolic".printf (settings.enabled ? "high" : "low"); 33 } 34 35 public Button (Midori.Browser browser) { 36 var action = new SimpleAction ("adblock-status", null); 37 action.activate.connect (() => { 38 settings.enabled = !settings.enabled; 39 browser.tab.reload (); 40 }); 41 browser.notify["uri"].connect (() => { 42 action.set_enabled (browser.uri.has_prefix ("http")); 43 }); 44 browser.add_action (action); 45 browser.application.set_accels_for_action ("win.adblock-status", { }); 46 } 47 } 48 49 public class Frontend : Object, Midori.BrowserActivatable { 50 public Midori.Browser browser { owned get; set; } 51 52 public void activate () { 53 var button = new Button (browser); 54 browser.add_button (button); 55 deactivate.connect (() => { 56 button.destroy (); 57 }); 58 59 browser.web_context.register_uri_scheme ("abp", (request) => { 60 if (request.get_uri ().has_prefix ("abp:subscribe?location=")) { 61 // abp://subscripe?location=http://example.com&title=foo 62 var sub = new Subscription (request.get_uri ().substring (23, -1)); 63 debug ("Adding %s to filters\n", sub.uri); 64 Settings.get_default ().add (sub); 65 sub.active = true; 66 request.get_web_view ().stop_loading (); 67 } else { 68 request.finish_error (new FileError.NOENT (_("Invalid URI"))); 69 } 70 }); 71 } 72 } 73 74 public class RequestFilter : Peas.ExtensionBase, Peas.Activatable { 75 public Object object { owned get; construct; } 76 77 public void activate () { 78 string? page_uri; 79 object.get ("uri", out page_uri); 80 object.connect ("signal::send-request", handle_request, page_uri); 81 } 82 83 bool handle_request (Object request, Object? response, string? page_uri) { 84 string? uri; 85 request.get ("uri", out uri); 86 if (page_uri == null) { 87 // Note: 'this' is the WebKit.WebPage object in this context 88 get ("uri", out page_uri); 89 } 90 return get_directive_for_uri (uri, page_uri) == Directive.BLOCK; 91 } 92 93 Directive get_directive_for_uri (string request_uri, string page_uri) { 94 var settings = Settings.get_default (); 95 96 if (!settings.enabled) 97 return Directive.ALLOW; 98 99 // Always allow the main page 100 if (request_uri == page_uri) 101 return Directive.ALLOW; 102 103 // No adblock on non-http(s) schemes 104 if (!request_uri.has_prefix ("http")) 105 return Directive.ALLOW; 106 107 Directive? directive = null; 108 foreach (var sub in settings) { 109 directive = sub.get_directive (request_uri, page_uri); 110 if (directive != null) 111 break; 112 } 113 114 if (directive == null) { 115 directive = Directive.ALLOW; 116 } 117 return directive; 118 } 119 120 public void deactivate () { 121 } 122 123 public void update_state () { 124 } 125 } 126 127 public class Preferences : Object, Midori.PreferencesActivatable { 128 public Midori.Preferences preferences { owned get; set; } 129 130 public void activate () { 131 var box = new Midori.LabelWidget (_("Configure Advertisement filters")); 132 var listbox = new Gtk.ListBox (); 133 listbox.selection_mode = Gtk.SelectionMode.NONE; 134 var settings = Settings.get_default (); 135 foreach (var sub in settings) { 136 var row = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 4); 137 var button = new Gtk.CheckButton.with_label (sub.title); 138 button.tooltip_text = sub.uri; 139 sub.bind_property ("active", button, "active", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL); 140 row.pack_start (button); 141 if (!settings.default_filters.contains (sub.uri.split ("&")[0])) { 142 var remove = new Gtk.Button.from_icon_name ("list-remove-symbolic"); 143 remove.relief = Gtk.ReliefStyle.NONE; 144 remove.clicked.connect (() => { 145 settings.remove (sub); 146 row.destroy (); 147 }); 148 row.pack_end (remove, false); 149 } 150 listbox.insert (row, -1); 151 } 152 153 // Provide guidance to adding additional filters via the abp: scheme 154 var label = new Gtk.Label ( 155 _("You can find more lists by visiting following sites:\n %s, %s\n").printf ( 156 "<a href=\"https://adblockplus.org/en/subscriptions\">AdblockPlus</a>", 157 "<a href=\"https://easylist.to\">EasyList</a>")); 158 label.use_markup = true; 159 label.activate_link.connect ((uri) => { 160 var files = new File[1]; 161 files[0] = File.new_for_uri (uri); 162 Application.get_default ().open (files, ""); 163 return true; 164 }); 165 listbox.insert (label, -1); 166 167 box.add (listbox); 168 box.show_all (); 169 preferences.add (_("Privacy"), box); 170 deactivate.connect (() => { 171 box.destroy (); 172 }); 173 } 174 } 175} 176 177[ModuleInit] 178public void peas_register_types(TypeModule module) { 179 ((Peas.ObjectModule)module).register_extension_type ( 180 typeof (Midori.BrowserActivatable), typeof (Adblock.Frontend)); 181 ((Peas.ObjectModule)module).register_extension_type ( 182 typeof (Peas.Activatable), typeof (Adblock.RequestFilter)); 183 ((Peas.ObjectModule)module).register_extension_type ( 184 typeof (Midori.PreferencesActivatable), typeof (Adblock.Preferences)); 185} 186