Merge lp:~midori/midori/addingDefaultsAndFilters into lp:midori
- addingDefaultsAndFilters
- Merge into trunk
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Cris Dywan | ||||||||
Approved revision: | 6610 | ||||||||
Merged at revision: | 6594 | ||||||||
Proposed branch: | lp:~midori/midori/addingDefaultsAndFilters | ||||||||
Merge into: | lp:midori | ||||||||
Diff against target: |
1852 lines (+1095/-298) 14 files modified
data/adblock.list (+1/-0) data/adblock/blocked.svg (+46/-0) data/adblock/disabled.svg (+46/-0) data/adblock/enabled.svg (+80/-0) extensions/adblock/config.vala (+78/-39) extensions/adblock/extension.vala (+421/-210) extensions/adblock/subscriptions.vala (+48/-10) extensions/adblock/updater.vala (+47/-31) extensions/adblock/widgets.vala (+310/-0) katze/midori-paths.vala (+12/-4) midori/midori-app.c (+1/-1) midori/midori-browser.c (+1/-1) midori/midori-download.vala (+3/-2) po/POTFILES.in (+1/-0) |
||||||||
To merge this branch: | bzr merge lp:~midori/midori/addingDefaultsAndFilters | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Cris Dywan | Approve | ||
Review via email: mp+208255@code.launchpad.net |
Commit message
Add filters and defaults
Description of the change
TODO:
- Statusbar icon [x] Debug Matching
- Edit/ view custom rules
- Check checksum hash of the subscription after downloading
- Open local files in editor
- Ability to disable adblock for the current domain
- Save pre-parsed pre filtered ruleset into file as .preparsed
- Save matched/ cached uris from previous runs
[https:/
enabled=1
expires=
retries=1
homepage=https:/
title=EasyList
Test cases https:/
- 6582. By Cris Dywan
-
Only truncate filters string if there's a trailing ;
- 6583. By Cris Dywan
-
Get browser from app instead of get_for_widget
We don't actually get a window we could use as a reference
- 6584. By Paweł Forysiuk
-
Don't show scarry warning if 'disabled' setting is not found
- 6585. By Paweł Forysiuk
-
Don't bother downloading local files
- 6586. By Cris Dywan
-
Refactor Updater properties and show update in treeview
- 6587. By Cris Dywan
-
Handling presets within Config and add first unit tests
- 6588. By Cris Dywan
-
Move enabled switch into Config and add unit tests
- 6589. By Cris Dywan
-
Unit test parsing of subscriptions in Config
- 6590. By Paweł Forysiuk
-
Toggle displaying of hidden elements from adblock icon
- 6591. By Paweł Forysiuk
-
Display current adblock state in a tooltip
- 6592. By Paweł Forysiuk
-
Fix building with older vala version
- 6593. By Paweł Forysiuk
-
Don't reuse menu item variables
- 6594. By Cris Dywan
-
Unit test that saving and loading gives back the same results
- 6595. By Cris Dywan
-
Add adblock:parse for patt/ got messages
- 6596. By Cris Dywan
-
Add fallback to empty string to debug variable checks
- 6597. By Cris Dywan
-
Unit test init, add, remove and request on the whole Extension
- 6598. By Cris Dywan
-
Correct request_handled test case and custom rule test
- 6599. By Cris Dywan
-
Check header parts more carefully in Subscription.
parse_header - 6600. By Cris Dywan
-
Implement a notion of validity in subscriptions if there're no date headers
- 6601. By Cris Dywan
-
Fix and unit test writing of disabled URLs with dashes
- 6602. By Cris Dywan
-
Consider a subscription valid if anything at all gets picked up
There's no requirement to have any update or expiry header.
- 6603. By Cris Dywan
-
Merge lp:midori
- 6604. By Paweł Forysiuk
-
Extract widgets into separate file
- 6605. By Cris Dywan
-
preset_filename needs to fallback to build folder
- 6606. By Paweł Forysiuk
-
Parse subscription uris with a helper function
- 6607. By Paweł Forysiuk
-
Separate subscription parsing helper from subscription manager
- 6608. By Paweł Forysiuk
-
Split preparing hider css into helper functions
- 6609. By Paweł Forysiuk
-
Return if there is no blocked element to hide
- 6610. By Paweł Forysiuk
-
Split getting domains for uri into a separate function
Cris Dywan (kalikiana) : | # |
Preview Diff
1 | === added directory 'data/adblock' |
2 | === modified file 'data/adblock.list' |
3 | --- data/adblock.list 2014-02-17 20:43:55 +0000 |
4 | +++ data/adblock.list 2014-03-10 10:27:25 +0000 |
5 | @@ -7,6 +7,7 @@ |
6 | ! Licence: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt |
7 | ! Copyright (C) 2014 Christian Dywan <christian@twotoasts.de> |
8 | ! |
9 | +! Some freeform text: |
10 | ! Yadayada http://example.com/ e-mail (somebody@example.com). |
11 | ! |
12 | !-----Spam eggs--------! |
13 | |
14 | === added file 'data/adblock/blocked.svg' |
15 | --- data/adblock/blocked.svg 1970-01-01 00:00:00 +0000 |
16 | +++ data/adblock/blocked.svg 2014-03-10 10:27:25 +0000 |
17 | @@ -0,0 +1,46 @@ |
18 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
19 | +<!-- Created with Inkscape (http://www.inkscape.org/) --> |
20 | + |
21 | +<svg |
22 | + xmlns:dc="http://purl.org/dc/elements/1.1/" |
23 | + xmlns:cc="http://creativecommons.org/ns#" |
24 | + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" |
25 | + xmlns:svg="http://www.w3.org/2000/svg" |
26 | + xmlns="http://www.w3.org/2000/svg" |
27 | + version="1.1" |
28 | + width="16" |
29 | + height="16" |
30 | + id="svg7384"> |
31 | + <title |
32 | + id="title9167">Gnome Symbolic Icon Theme</title> |
33 | + <defs |
34 | + id="defs10" /> |
35 | + <metadata |
36 | + id="metadata90"> |
37 | + <rdf:RDF> |
38 | + <cc:Work |
39 | + rdf:about=""> |
40 | + <dc:format>image/svg+xml</dc:format> |
41 | + <dc:type |
42 | + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> |
43 | + <dc:title>Gnome Symbolic Icon Theme</dc:title> |
44 | + </cc:Work> |
45 | + </rdf:RDF> |
46 | + </metadata> |
47 | + <g |
48 | + transform="translate(-111.61542,-601.4038)" |
49 | + id="layer12"> |
50 | + <path |
51 | + d="m 228.01,607.02 c -3.86,0 -7.0073,3.166 -7.0073,7.0103 0,3.8443 3.1472,6.9787 7.0073,6.9787 3.86,0 7.0073,-3.1344 7.0073,-6.9787 0,-3.8443 -3.1472,-7.0103 -7.0073,-7.0103 z m 0,2.021 c 2.7769,0 5.0097,2.2237 5.0097,4.9893 0,2.7656 -2.2328,4.9577 -5.0097,4.9577 -2.777,0 -5.0097,-2.1921 -5.0097,-4.9577 0,-2.7656 2.2328,-4.9893 5.0097,-4.9893 z" |
52 | + id="path4222" |
53 | + style="text-indent:0;text-transform:none;block-progression:tb;color:#000000;fill:#bebebe" /> |
54 | + <path |
55 | + d="m 231.41,609.44 -8,8 1.4062,1.4062 8,-8 -1.4062,-1.4062 z" |
56 | + id="path4992" |
57 | + style="text-indent:0;text-transform:none;block-progression:tb;color:#000000;fill:#bebebe" /> |
58 | + </g> |
59 | + <path |
60 | + d="m 7.96875,0.6875 c -2.8420838,0 -2.8771973,1.9949742 -6.625,2.3125 0,0 -0.98752557,2.5363552 0.34375,6 0.8399195,2.18526 4.3935259,5.981297 6.1875,6 l 0.25,0 C 9.9189736,14.9813 13.472581,11.18526 14.3125,9 15.643775,5.5363552 14.65625,3 14.65625,3 10.908448,2.6824742 10.873333,0.6875 8.03125,0.6875 l -0.0625,0 z m -0.625,2 c 0.1719617,-0.02159 0.3665606,0 0.625,0 l 0.0625,0 c 1.0337572,0 1.1746055,0.1513488 2.03125,0.625 0.133299,0.073703 0.361318,0.1808693 0.53125,0.28125 L 4.0625,9.25 C 3.8118632,8.860346 3.6127069,8.4931804 3.53125,8.28125 2.8541774,6.5196771 2.8806279,5.4183698 3,4.65625 4.2800363,4.3579974 5.3166759,3.6557627 5.9375,3.3125 6.5799833,2.9572616 6.8278648,2.7522692 7.34375,2.6875 z m 5.21875,1.84375 c 0.146121,0.046432 0.28409,0.089255 0.4375,0.125 0.119372,0.7621199 0.145822,1.863427 -0.53125,3.625 -0.223946,0.5826518 -1.210812,2.079776 -2.28125,3.15625 -0.535219,0.538237 -1.0931989,0.993886 -1.53125,1.28125 -0.2903916,0.190498 -0.5086712,0.283423 -0.5625,0.3125 l -0.15625,0 C 7.9117131,13.007739 7.6583409,12.925123 7.34375,12.71875 6.905699,12.431386 6.3477189,11.975737 5.8125,11.4375 5.6307383,11.254713 5.4548666,11.044257 5.28125,10.84375 l 7.28125,-6.3125 z" |
61 | + id="path3016-2" |
62 | + style="color:#000000;fill:#ffa500;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> |
63 | +</svg> |
64 | |
65 | === added file 'data/adblock/disabled.svg' |
66 | --- data/adblock/disabled.svg 1970-01-01 00:00:00 +0000 |
67 | +++ data/adblock/disabled.svg 2014-03-10 10:27:25 +0000 |
68 | @@ -0,0 +1,46 @@ |
69 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
70 | +<!-- Created with Inkscape (http://www.inkscape.org/) --> |
71 | + |
72 | +<svg |
73 | + xmlns:dc="http://purl.org/dc/elements/1.1/" |
74 | + xmlns:cc="http://creativecommons.org/ns#" |
75 | + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" |
76 | + xmlns:svg="http://www.w3.org/2000/svg" |
77 | + xmlns="http://www.w3.org/2000/svg" |
78 | + version="1.1" |
79 | + width="16" |
80 | + height="16" |
81 | + id="svg7384"> |
82 | + <title |
83 | + id="title9167">Gnome Symbolic Icon Theme</title> |
84 | + <defs |
85 | + id="defs10" /> |
86 | + <metadata |
87 | + id="metadata90"> |
88 | + <rdf:RDF> |
89 | + <cc:Work |
90 | + rdf:about=""> |
91 | + <dc:format>image/svg+xml</dc:format> |
92 | + <dc:type |
93 | + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> |
94 | + <dc:title>Gnome Symbolic Icon Theme</dc:title> |
95 | + </cc:Work> |
96 | + </rdf:RDF> |
97 | + </metadata> |
98 | + <g |
99 | + transform="translate(-111.61542,-601.4038)" |
100 | + id="layer12"> |
101 | + <path |
102 | + d="m 228.01,607.02 c -3.86,0 -7.0073,3.166 -7.0073,7.0103 0,3.8443 3.1472,6.9787 7.0073,6.9787 3.86,0 7.0073,-3.1344 7.0073,-6.9787 0,-3.8443 -3.1472,-7.0103 -7.0073,-7.0103 z m 0,2.021 c 2.7769,0 5.0097,2.2237 5.0097,4.9893 0,2.7656 -2.2328,4.9577 -5.0097,4.9577 -2.777,0 -5.0097,-2.1921 -5.0097,-4.9577 0,-2.7656 2.2328,-4.9893 5.0097,-4.9893 z" |
103 | + id="path4222" |
104 | + style="text-indent:0;text-transform:none;block-progression:tb;color:#000000;fill:#bebebe" /> |
105 | + <path |
106 | + d="m 231.41,609.44 -8,8 1.4062,1.4062 8,-8 -1.4062,-1.4062 z" |
107 | + id="path4992" |
108 | + style="text-indent:0;text-transform:none;block-progression:tb;color:#000000;fill:#bebebe" /> |
109 | + </g> |
110 | + <path |
111 | + d="m 7.96875,0.6875 c -2.8420838,0 -2.8771973,1.9949742 -6.625,2.3125 0,0 -0.98752557,2.5363552 0.34375,6 0.8399195,2.18526 4.3935259,5.981297 6.1875,6 l 0.25,0 C 9.9189736,14.9813 13.472581,11.18526 14.3125,9 15.643775,5.5363552 14.65625,3 14.65625,3 10.908448,2.6824742 10.873333,0.6875 8.03125,0.6875 l -0.0625,0 z m -0.625,2 c 0.1719617,-0.02159 0.3665606,0 0.625,0 l 0.0625,0 c 1.0337572,0 1.1746055,0.1513488 2.03125,0.625 0.133299,0.073703 0.361318,0.1808693 0.53125,0.28125 L 4.0625,9.25 C 3.8118632,8.860346 3.6127069,8.4931804 3.53125,8.28125 2.8541774,6.5196771 2.8806279,5.4183698 3,4.65625 4.2800363,4.3579974 5.3166759,3.6557627 5.9375,3.3125 6.5799833,2.9572616 6.8278648,2.7522692 7.34375,2.6875 z m 5.21875,1.84375 c 0.146121,0.046432 0.28409,0.089255 0.4375,0.125 0.119372,0.7621199 0.145822,1.863427 -0.53125,3.625 -0.223946,0.5826518 -1.210812,2.079776 -2.28125,3.15625 -0.535219,0.538237 -1.0931989,0.993886 -1.53125,1.28125 -0.2903916,0.190498 -0.5086712,0.283423 -0.5625,0.3125 l -0.15625,0 C 7.9117131,13.007739 7.6583409,12.925123 7.34375,12.71875 6.905699,12.431386 6.3477189,11.975737 5.8125,11.4375 5.6307383,11.254713 5.4548666,11.044257 5.28125,10.84375 l 7.28125,-6.3125 z" |
112 | + id="path3016-2" |
113 | + style="color:#000000;fill:#cc0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> |
114 | +</svg> |
115 | |
116 | === added file 'data/adblock/enabled.svg' |
117 | --- data/adblock/enabled.svg 1970-01-01 00:00:00 +0000 |
118 | +++ data/adblock/enabled.svg 2014-03-10 10:27:25 +0000 |
119 | @@ -0,0 +1,80 @@ |
120 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
121 | +<!-- Created with Inkscape (http://www.inkscape.org/) --> |
122 | + |
123 | +<svg |
124 | + xmlns:dc="http://purl.org/dc/elements/1.1/" |
125 | + xmlns:cc="http://creativecommons.org/ns#" |
126 | + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" |
127 | + xmlns:svg="http://www.w3.org/2000/svg" |
128 | + xmlns="http://www.w3.org/2000/svg" |
129 | + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" |
130 | + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" |
131 | + version="1.1" |
132 | + width="16" |
133 | + height="16" |
134 | + id="svg7384" |
135 | + inkscape:version="0.48.4 r9939" |
136 | + sodipodi:docname="adblock-enabled.svg"> |
137 | + <sodipodi:namedview |
138 | + pagecolor="#ffffff" |
139 | + bordercolor="#666666" |
140 | + borderopacity="1" |
141 | + objecttolerance="10" |
142 | + gridtolerance="10" |
143 | + guidetolerance="10" |
144 | + inkscape:pageopacity="0" |
145 | + inkscape:pageshadow="2" |
146 | + inkscape:window-width="1920" |
147 | + inkscape:window-height="1026" |
148 | + id="namedview10" |
149 | + showgrid="false" |
150 | + inkscape:zoom="14.75" |
151 | + inkscape:cx="8" |
152 | + inkscape:cy="8" |
153 | + inkscape:window-x="0" |
154 | + inkscape:window-y="32" |
155 | + inkscape:window-maximized="1" |
156 | + inkscape:current-layer="svg7384" /> |
157 | + <title |
158 | + id="title9167">Gnome Symbolic Icon Theme</title> |
159 | + <defs |
160 | + id="defs10" /> |
161 | + <metadata |
162 | + id="metadata90"> |
163 | + <rdf:RDF> |
164 | + <cc:Work |
165 | + rdf:about=""> |
166 | + <dc:format>image/svg+xml</dc:format> |
167 | + <dc:type |
168 | + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> |
169 | + <dc:title>Gnome Symbolic Icon Theme</dc:title> |
170 | + </cc:Work> |
171 | + </rdf:RDF> |
172 | + </metadata> |
173 | + <g |
174 | + transform="translate(-111.61542,-601.4038)" |
175 | + id="layer12"> |
176 | + <path |
177 | + d="m 228.01,607.02 c -3.86,0 -7.0073,3.166 -7.0073,7.0103 0,3.8443 3.1472,6.9787 7.0073,6.9787 3.86,0 7.0073,-3.1344 7.0073,-6.9787 0,-3.8443 -3.1472,-7.0103 -7.0073,-7.0103 z m 0,2.021 c 2.7769,0 5.0097,2.2237 5.0097,4.9893 0,2.7656 -2.2328,4.9577 -5.0097,4.9577 -2.777,0 -5.0097,-2.1921 -5.0097,-4.9577 0,-2.7656 2.2328,-4.9893 5.0097,-4.9893 z" |
178 | + id="path4222" |
179 | + style="text-indent:0;text-transform:none;block-progression:tb;color:#000000;fill:#bebebe" /> |
180 | + <path |
181 | + d="m 231.41,609.44 -8,8 1.4062,1.4062 8,-8 -1.4062,-1.4062 z" |
182 | + id="path4992" |
183 | + style="text-indent:0;text-transform:none;block-progression:tb;color:#000000;fill:#bebebe" /> |
184 | + </g> |
185 | + <path |
186 | + d="m 7.96875,0.6875 c -2.8420838,0 -2.8771973,1.9949742 -6.625,2.3125 0,0 -0.98752557,2.5363552 0.34375,6 0.8399195,2.18526 4.3935259,5.981297 6.1875,6 l 0.25,0 C 9.9189736,14.9813 13.472581,11.18526 14.3125,9 15.643775,5.5363552 14.65625,3 14.65625,3 10.908448,2.6824742 10.873333,0.6875 8.03125,0.6875 l -0.0625,0 z m -0.625,2 c 0.1719617,-0.02159 0.3665606,0 0.625,0 l 0.0625,0 c 1.0337572,0 1.1746055,0.1513488 2.03125,0.625 0.133299,0.073703 0.361318,0.1808693 0.53125,0.28125 L 4.0625,9.25 C 3.8118632,8.860346 3.6127069,8.4931804 3.53125,8.28125 2.8541774,6.5196771 2.8806279,5.4183698 3,4.65625 4.2800363,4.3579974 5.3166759,3.6557627 5.9375,3.3125 6.5799833,2.9572616 6.8278648,2.7522692 7.34375,2.6875 z m 5.21875,1.84375 c 0.146121,0.046432 0.28409,0.089255 0.4375,0.125 0.119372,0.7621199 0.145822,1.863427 -0.53125,3.625 -0.223946,0.5826518 -1.210812,2.079776 -2.28125,3.15625 -0.535219,0.538237 -1.0931989,0.993886 -1.53125,1.28125 -0.2903916,0.190498 -0.5086712,0.283423 -0.5625,0.3125 l -0.15625,0 C 7.9117131,13.007739 7.6583409,12.925123 7.34375,12.71875 6.905699,12.431386 6.3477189,11.975737 5.8125,11.4375 5.6307383,11.254713 5.4548666,11.044257 5.28125,10.84375 l 7.28125,-6.3125 z" |
187 | + id="path3016-2" |
188 | + style="color:#000000;fill:#4e9a06;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> |
189 | + <path |
190 | + style="fill:#000000;fill-opacity:0" |
191 | + d="M 3.8914706,8.8841635 C 3.4103263,8.1221753 3.0583616,6.8749414 3.003735,5.7383534 2.9786317,5.2160416 2.9904131,4.8722447 3.036357,4.7863976 3.0800139,4.7048241 3.2418563,4.6177843 3.4482218,4.5648944 3.8914458,4.4512995 4.5265161,4.1442388 5.8961843,3.3812883 L 7.0127075,2.7593478 7.7697676,2.7353155 C 8.6627475,2.7069685 9.052772,2.7983017 9.8276868,3.2172249 10.1089,3.3692502 10.375652,3.52161 10.420468,3.5558023 10.491273,3.609822 8.8213493,5.090833 4.1912034,9.0803713 4.0886836,9.1687069 4.0587803,9.149132 3.8914706,8.8841635 l 0,0 z" |
192 | + id="path2987" |
193 | + inkscape:connector-curvature="0" /> |
194 | + <path |
195 | + style="fill:#000000;fill-opacity:0" |
196 | + d="M 7.5676774,12.795393 C 7.0256619,12.469009 6.4290755,11.979639 5.8305085,11.370422 5.33023,10.861243 5.3242581,10.851054 5.4600194,10.738315 5.5359114,10.675293 7.1641368,9.2661017 9.0782981,7.6067797 11.684369,5.3476641 12.594872,4.5953246 12.703024,4.6117025 c 0.291451,0.044135 0.329784,0.1886522 0.290923,1.0967721 -0.07204,1.6834953 -0.589725,2.9526655 -1.866622,4.5762714 -0.495094,0.629525 -1.366327,1.526375 -1.8854314,1.94087 C 8.8466967,12.541173 8.091686,13.030508 8,13.030508 c -0.023031,0 -0.2175765,-0.105802 -0.4323226,-0.235115 z" |
197 | + id="path2989" |
198 | + inkscape:connector-curvature="0" /> |
199 | +</svg> |
200 | |
201 | === modified file 'extensions/adblock/config.vala' |
202 | --- extensions/adblock/config.vala 2014-02-20 18:27:01 +0000 |
203 | +++ extensions/adblock/config.vala 2014-03-10 10:27:25 +0000 |
204 | @@ -12,27 +12,26 @@ |
205 | namespace Adblock { |
206 | public class Config : GLib.Object { |
207 | List<Subscription> subscriptions; |
208 | - string? path; |
209 | + public string? path { get; private set; } |
210 | KeyFile keyfile; |
211 | - Subscription? custom; |
212 | + bool should_save; |
213 | + public bool enabled { get; set; } |
214 | |
215 | - public Config (string? path) { |
216 | + public Config (string? path, string? presets) { |
217 | + should_save = false; |
218 | subscriptions = new GLib.List<Subscription> (); |
219 | - |
220 | + enabled = true; |
221 | this.path = path; |
222 | - if (path == null) |
223 | + size = 0; |
224 | + load_file (path); |
225 | + load_file (presets); |
226 | + should_save = true; |
227 | + } |
228 | + |
229 | + void load_file (string? filename) { |
230 | + if (filename == null) |
231 | return; |
232 | |
233 | - string custom_list = GLib.Path.build_filename (path, "custom.list"); |
234 | - try { |
235 | - custom = new Subscription (Filename.to_uri (custom_list, null)); |
236 | - subscriptions.append (custom); |
237 | - } catch (Error error) { |
238 | - custom = null; |
239 | - warning ("Failed to add custom list %s: %s", custom_list, error.message); |
240 | - } |
241 | - |
242 | - string filename = GLib.Path.build_filename (path, "config"); |
243 | keyfile = new GLib.KeyFile (); |
244 | try { |
245 | keyfile.load_from_file (filename, GLib.KeyFileFlags.NONE); |
246 | @@ -40,68 +39,108 @@ |
247 | foreach (string filter in filters) { |
248 | bool active = false; |
249 | string uri = filter; |
250 | - if (filter.has_prefix ("http-")) |
251 | - uri = "http:" + filter.substring (6); |
252 | - else if (filter.has_prefix ("file-")) |
253 | - uri = "file:" + filter.substring (6); |
254 | - else if (filter.has_prefix ("https-")) |
255 | - uri = "https:" + filter.substring (7); |
256 | + if (filter.has_prefix ("http-/")) |
257 | + uri = "http:" + filter.substring (5); |
258 | + else if (filter.has_prefix ("file-/")) |
259 | + uri = "file:" + filter.substring (5); |
260 | + else if (filter.has_prefix ("http-:")) |
261 | + uri = "https" + filter.substring (5); |
262 | else |
263 | active = true; |
264 | Subscription sub = new Subscription (uri); |
265 | sub.active = active; |
266 | sub.add_feature (new Updater ()); |
267 | - sub.notify["active"].connect (active_changed); |
268 | - subscriptions.append (sub); |
269 | + add (sub); |
270 | } |
271 | + enabled = !keyfile.get_boolean ("settings", "disabled"); |
272 | + } catch (KeyFileError.KEY_NOT_FOUND key_error) { |
273 | + /* It's no error if a key is missing */ |
274 | + } catch (KeyFileError.GROUP_NOT_FOUND group_error) { |
275 | + /* It's no error if a group is missing */ |
276 | } catch (FileError.NOENT exist_error) { |
277 | /* It's no error if no config file exists */ |
278 | } catch (GLib.Error settings_error) { |
279 | warning ("Error reading settings from %s: %s\n", filename, settings_error.message); |
280 | } |
281 | |
282 | - size = subscriptions.length (); |
283 | + notify["enabled"].connect (enabled_changed); |
284 | + } |
285 | + |
286 | + void enabled_changed (ParamSpec pspec) { |
287 | + keyfile.set_boolean ("settings", "disabled", !enabled); |
288 | + save (); |
289 | } |
290 | |
291 | void active_changed (Object subscription, ParamSpec pspec) { |
292 | + update_filters (); |
293 | + } |
294 | + |
295 | + void update_filters () { |
296 | var filters = new StringBuilder (); |
297 | foreach (var sub in subscriptions) { |
298 | - if (sub == custom) |
299 | + if (!sub.mutable) |
300 | continue; |
301 | if (sub.uri.has_prefix ("http:") && !sub.active) |
302 | filters.append ("http-" + sub.uri.substring (4)); |
303 | else if (sub.uri.has_prefix ("file:") && !sub.active) |
304 | - filters.append ("file-" + sub.uri.substring (4)); |
305 | + filters.append ("file-" + sub.uri.substring (5)); |
306 | else if (sub.uri.has_prefix ("https:") && !sub.active) |
307 | - filters.append ("https-" + sub.uri.substring (5)); |
308 | + filters.append ("http-" + sub.uri.substring (5)); |
309 | else |
310 | filters.append (sub.uri); |
311 | filters.append_c (';'); |
312 | } |
313 | |
314 | - string[] list = (filters.str.slice (0, -1)).split (";"); |
315 | + if (filters.str.has_suffix (";")) |
316 | + filters.truncate (filters.len - 1); |
317 | + string[] list = filters.str.split (";"); |
318 | keyfile.set_string_list ("settings", "filters", list); |
319 | + |
320 | + save (); |
321 | + } |
322 | + |
323 | + |
324 | + public void save () { |
325 | try { |
326 | - string filename = GLib.Path.build_filename (path, "config"); |
327 | - FileUtils.set_contents (filename, keyfile.to_data ()); |
328 | + FileUtils.set_contents (path, keyfile.to_data ()); |
329 | } catch (Error error) { |
330 | warning ("Failed to save settings: %s", error.message); |
331 | } |
332 | } |
333 | |
334 | - public void add_custom_rule (string rule) { |
335 | - try { |
336 | - var file = File.new_for_uri (custom.uri); |
337 | - file.append_to (FileCreateFlags.NONE).write (("%s\n".printf (rule)).data); |
338 | - } catch (Error error) { |
339 | - warning ("Failed to add custom rule: %s", error.message); |
340 | - } |
341 | - } |
342 | - |
343 | /* foreach support */ |
344 | public new Subscription? get (uint index) { |
345 | return subscriptions.nth_data (index); |
346 | } |
347 | public uint size { get; private set; } |
348 | + |
349 | + bool contains (Subscription subscription) { |
350 | + foreach (var sub in subscriptions) |
351 | + if (sub.uri == subscription.uri) |
352 | + return true; |
353 | + return false; |
354 | + } |
355 | + |
356 | + public bool add (Subscription sub) { |
357 | + if (contains (sub)) |
358 | + return false; |
359 | + |
360 | + sub.notify["active"].connect (active_changed); |
361 | + subscriptions.append (sub); |
362 | + size++; |
363 | + if (should_save) |
364 | + update_filters (); |
365 | + return true; |
366 | + } |
367 | + |
368 | + public void remove (Subscription sub) { |
369 | + if (!contains (sub)) |
370 | + return; |
371 | + |
372 | + subscriptions.remove (sub); |
373 | + sub.notify["active"].disconnect (active_changed); |
374 | + update_filters (); |
375 | + size--; |
376 | + } |
377 | } |
378 | } |
379 | |
380 | === modified file 'extensions/adblock/extension.vala' |
381 | --- extensions/adblock/extension.vala 2014-02-24 00:06:18 +0000 |
382 | +++ extensions/adblock/extension.vala 2014-03-10 10:27:25 +0000 |
383 | @@ -16,9 +16,42 @@ |
384 | BLOCK |
385 | } |
386 | |
387 | + public enum State { |
388 | + ENABLED, |
389 | + DISABLED, |
390 | + BLOCKED |
391 | + } |
392 | + |
393 | + public string? parse_subscription_uri (string? uri) { |
394 | + if (uri == null) |
395 | + return null; |
396 | + |
397 | + if (uri.has_prefix ("http") || uri.has_prefix ("abp") || uri.has_prefix ("file")) |
398 | + { |
399 | + string sub_uri = uri; |
400 | + if (uri.has_prefix ("abp:")) { |
401 | + uri.replace ("abp://", "abp:"); |
402 | + if (uri.has_prefix ("abp:subscribe?location=")) { |
403 | + /* abp://subscripe?location=http://example.com&title=foo */ |
404 | + string[] parts = uri.substring (23, -1).split ("&", 2); |
405 | + sub_uri = parts[0]; |
406 | + } |
407 | + } |
408 | + |
409 | + string decoded_uri = Soup.URI.decode (sub_uri); |
410 | + return decoded_uri; |
411 | + } |
412 | + return null; |
413 | + } |
414 | + |
415 | public class Extension : Midori.Extension { |
416 | - Config config; |
417 | - HashTable<string, Directive?> cache; |
418 | + internal Config config; |
419 | + internal Subscription custom; |
420 | + internal HashTable<string, Directive?> cache; |
421 | + internal StatusIcon status_icon; |
422 | + internal SubscriptionManager manager; |
423 | + internal State state; |
424 | + internal bool debug_element; |
425 | |
426 | #if HAVE_WEBKIT2 |
427 | public Extension (WebKit.WebExtension web_extension) { |
428 | @@ -44,99 +77,7 @@ |
429 | } |
430 | |
431 | void extension_preferences () { |
432 | - open_dialog (null); |
433 | - } |
434 | - |
435 | - void open_dialog (string? uri) { |
436 | - var dialog = new Gtk.Dialog.with_buttons (_("Configure Advertisement filters"), |
437 | - null, |
438 | -#if !HAVE_GTK3 |
439 | - Gtk.DialogFlags.NO_SEPARATOR | |
440 | -#endif |
441 | - Gtk.DialogFlags.DESTROY_WITH_PARENT, |
442 | - Gtk.STOCK_HELP, Gtk.ResponseType.HELP, |
443 | - Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE); |
444 | -#if HAVE_GTK3 |
445 | - dialog.get_widget_for_response (Gtk.ResponseType.HELP).get_style_context ().add_class ("help_button"); |
446 | -#endif |
447 | - dialog.set_icon_name (Gtk.STOCK_PROPERTIES); |
448 | - dialog.set_response_sensitive (Gtk.ResponseType.HELP, false); |
449 | - |
450 | - var hbox = new Gtk.HBox (false, 0); |
451 | - (dialog.get_content_area () as Gtk.Box).pack_start (hbox, true, true, 12); |
452 | - var vbox = new Gtk.VBox (false, 0); |
453 | - hbox.pack_start (vbox, true, true, 4); |
454 | - var button = new Gtk.Label (null); |
455 | - string description = """ |
456 | - Type the address of a preconfigured filter list in the text entry |
457 | - and click "Add" to add it to the list. |
458 | - You can find more lists at %s %s. |
459 | - """.printf ( |
460 | - "<a href=\"http://adblockplus.org/en/subscriptions\">adblockplus.org/en/subscriptions</a>", |
461 | - "<a href=\"http://easylist.adblockplus.org/\">easylist.adblockplus.org</a>"); |
462 | - button.activate_link.connect ((uri)=>{ |
463 | - var browser = Midori.Browser.get_for_widget (button); |
464 | - var view = browser.add_uri (uri); |
465 | - browser.tab = view; |
466 | - return true; |
467 | - }); |
468 | - button.set_markup (description); |
469 | - button.set_line_wrap (true); |
470 | - vbox.pack_start (button, false, false, 4); |
471 | - |
472 | - var entry = new Gtk.Entry (); |
473 | - if (uri != null) |
474 | - entry.set_text (uri); |
475 | - vbox.pack_start (entry, false, false, 4); |
476 | - |
477 | - var liststore = new Gtk.ListStore (1, typeof (Subscription)); |
478 | - var treeview = new Gtk.TreeView.with_model (liststore); |
479 | - treeview.set_headers_visible (false); |
480 | - var column = new Gtk.TreeViewColumn (); |
481 | - var renderer_toggle = new Gtk.CellRendererToggle (); |
482 | - column.pack_start (renderer_toggle, false); |
483 | - column.set_cell_data_func (renderer_toggle, (column, renderer, model, iter) => { |
484 | - Subscription sub; |
485 | - liststore.get (iter, 0, out sub); |
486 | - renderer.set ("active", sub.active, |
487 | - "sensitive", !sub.uri.has_suffix ("custom.list")); |
488 | - }); |
489 | - renderer_toggle.toggled.connect ((path) => { |
490 | - Gtk.TreeIter iter; |
491 | - if (liststore.get_iter_from_string (out iter, path)) { |
492 | - Subscription sub; |
493 | - liststore.get (iter, 0, out sub); |
494 | - sub.active = !sub.active; |
495 | - } |
496 | - }); |
497 | - treeview.append_column (column); |
498 | - |
499 | - column = new Gtk.TreeViewColumn (); |
500 | - var renderer_text = new Gtk.CellRendererText (); |
501 | - column.pack_start (renderer_text, false); |
502 | - renderer_text.set ("editable", true); |
503 | - // TODO: renderer_text.edited.connect |
504 | - column.set_cell_data_func (renderer_text, (column, renderer, model, iter) => { |
505 | - Subscription sub; |
506 | - liststore.get (iter, 0, out sub); |
507 | - renderer.set ("text", sub.uri); |
508 | - }); |
509 | - treeview.append_column (column); |
510 | - |
511 | - var scrolled = new Gtk.ScrolledWindow (null, null); |
512 | - scrolled.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); |
513 | - scrolled.add (treeview); |
514 | - vbox.pack_start (scrolled); |
515 | - |
516 | - foreach (Subscription sub in config) |
517 | - liststore.insert_with_values (null, 0, 0, sub); |
518 | - // TODO: row-inserted row-changed row-deleted |
519 | - // TODO vbox with add/ edit/ remove/ down/ up |
520 | - |
521 | - dialog.get_content_area ().show_all (); |
522 | - |
523 | - dialog.response.connect ((response)=>{ dialog.destroy (); }); |
524 | - dialog.show (); |
525 | + manager.add_subscription (null); |
526 | } |
527 | |
528 | void extension_activated (Midori.App app) { |
529 | @@ -150,14 +91,24 @@ |
530 | foreach (var tab in browser.get_tabs ()) |
531 | tab_added (tab); |
532 | browser.add_tab.connect (tab_added); |
533 | + |
534 | + var toggle_button = new StatusIcon.IconButton (); |
535 | + toggle_button.set_status (config.enabled ? "enabled" : "disabled"); |
536 | + browser.statusbar.pack_start (toggle_button, false, false, 3); |
537 | + toggle_button.show (); |
538 | + toggle_button.clicked.connect (status_icon.icon_clicked); |
539 | + status_icon.toggle_buttons.append (toggle_button); |
540 | } |
541 | |
542 | + |
543 | void tab_added (Midori.View view) { |
544 | view.web_view.resource_request_starting.connect (resource_requested); |
545 | view.web_view.navigation_policy_decision_requested.connect (navigation_requested); |
546 | view.notify["load-status"].connect ((pspec) => { |
547 | - if (view.load_status == Midori.LoadStatus.FINISHED) |
548 | - inject_css (view, view.uri); |
549 | + if (config.enabled) { |
550 | + if (view.load_status == Midori.LoadStatus.FINISHED) |
551 | + inject_css (view, view.uri); |
552 | + } |
553 | }); |
554 | view.context_menu.connect (context_menu); |
555 | } |
556 | @@ -174,54 +125,31 @@ |
557 | return; |
558 | var action = new Gtk.Action ("BlockElement", label, null, null); |
559 | action.activate.connect ((action) => { |
560 | - edit_rule_dialog (uri); |
561 | + CustomRulesEditor custom_rules_editor = new CustomRulesEditor (custom); |
562 | + custom_rules_editor.set_uri (uri); |
563 | + custom_rules_editor.show(); |
564 | }); |
565 | menu.add (action); |
566 | } |
567 | |
568 | - void edit_rule_dialog (string uri) { |
569 | - var dialog = new Gtk.Dialog.with_buttons (_("Edit rule"), |
570 | - null, |
571 | -#if !HAVE_GTK3 |
572 | - Gtk.DialogFlags.NO_SEPARATOR | |
573 | -#endif |
574 | - Gtk.DialogFlags.DESTROY_WITH_PARENT, |
575 | - Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, |
576 | - Gtk.STOCK_ADD, Gtk.ResponseType.ACCEPT); |
577 | - dialog.set_icon_name (Gtk.STOCK_ADD); |
578 | - dialog.resizable = false; |
579 | - |
580 | - var hbox = new Gtk.HBox (false, 8); |
581 | - var sizegroup = new Gtk.SizeGroup (Gtk.SizeGroupMode.HORIZONTAL); |
582 | - hbox.border_width = 5; |
583 | - var label = new Gtk.Label.with_mnemonic (_("_Rule:")); |
584 | - sizegroup.add_widget (label); |
585 | - hbox.pack_start (label, false, false, 0); |
586 | - (dialog.get_content_area () as Gtk.Box).pack_start (hbox, false, true, 0); |
587 | - |
588 | - var entry = new Gtk.Entry (); |
589 | - sizegroup.add_widget (entry); |
590 | - entry.activates_default = true; |
591 | - entry.set_text (uri); |
592 | - hbox.pack_start (entry, true, true, 0); |
593 | - |
594 | - dialog.get_content_area ().show_all (); |
595 | - |
596 | - dialog.set_default_response (Gtk.ResponseType.ACCEPT); |
597 | - if (dialog.run () != Gtk.ResponseType.ACCEPT) |
598 | - return; |
599 | - |
600 | - string new_rule = entry.get_text (); |
601 | - dialog.destroy (); |
602 | - config.add_custom_rule (new_rule); |
603 | + Adblock.State adblock_get_state (Adblock.Directive directive) |
604 | + { |
605 | + if (directive == Directive.BLOCK) |
606 | + return State.BLOCKED; |
607 | + if (config.enabled) |
608 | + return State.ENABLED; |
609 | + else |
610 | + return State.DISABLED; |
611 | } |
612 | |
613 | - |
614 | void resource_requested (WebKit.WebView web_view, WebKit.WebFrame frame, |
615 | WebKit.WebResource resource, WebKit.NetworkRequest request, WebKit.NetworkResponse? response) { |
616 | |
617 | - if (request_handled (web_view.uri, request.uri)) |
618 | + if (request_handled (web_view.uri, request.uri)) { |
619 | request.set_uri ("about:blank"); |
620 | + state = adblock_get_state (get_directive_for_uri (web_view.uri)); |
621 | + status_icon.set_state (state); |
622 | + } |
623 | } |
624 | |
625 | bool navigation_requested (WebKit.WebFrame frame, WebKit.NetworkRequest request, |
626 | @@ -229,39 +157,28 @@ |
627 | |
628 | string uri = request.uri; |
629 | if (uri.has_prefix ("abp:")) { |
630 | - uri = uri.replace ("abp://", "abp:"); |
631 | - if (uri.has_prefix ("abp:subscribe?location=")) { |
632 | - /* abp://subscripe?location=http://example.com&title=foo */ |
633 | - string[] parts = uri.substring (23, -1).split ("&", 2); |
634 | - decision.ignore (); |
635 | - open_dialog (parts[0]); |
636 | - return true; |
637 | - } |
638 | + decision.ignore (); |
639 | + string parsed_uri = parse_subscription_uri (uri); |
640 | + manager.add_subscription (parsed_uri); |
641 | + return true; |
642 | } |
643 | + state = adblock_get_state (get_directive_for_uri (request.uri)); |
644 | + status_icon.set_state (state); |
645 | return false; |
646 | } |
647 | |
648 | - void inject_css (Midori.View view, string page_uri) { |
649 | - /* Don't block ads on internal pages */ |
650 | - if (!Midori.URI.is_http (page_uri)) |
651 | - return; |
652 | - string domain = Midori.URI.parse_hostname (page_uri, null); |
653 | - string[] subdomains = domain.split ("."); |
654 | - if (subdomains == null) |
655 | - return; |
656 | - int cnt = subdomains.length - 1; |
657 | - var subdomain = new StringBuilder (subdomains[cnt]); |
658 | - subdomain.prepend_c ('.'); |
659 | - cnt--; |
660 | - var code = new StringBuilder (); |
661 | - bool debug_element = "adblock:element" in (Environment.get_variable ("MIDORI_DEBUG") ?? ""); |
662 | - string hider_css; |
663 | - |
664 | + string? get_hider_css_for_blocked_resources () { |
665 | /* Hide elements that were blocked, otherwise we will get "broken image" icon */ |
666 | + var code = new StringBuilder (); |
667 | cache.foreach ((key, val) => { |
668 | if (val == Adblock.Directive.BLOCK) |
669 | code.append ("img[src*=\"%s\"] , iframe[src*=\"%s\"] , ".printf (key, key)); |
670 | }); |
671 | + |
672 | + if (code.str == "") |
673 | + return null; |
674 | + |
675 | + string hider_css; |
676 | if (debug_element) |
677 | hider_css = " { background-color: red; border: 4px solid green; }"; |
678 | else |
679 | @@ -271,55 +188,96 @@ |
680 | code.append (hider_css); |
681 | if (debug_element) |
682 | stdout.printf ("hider css: %s\n", code.str); |
683 | - view.inject_stylesheet (code.str); |
684 | + return code.str; |
685 | + } |
686 | |
687 | - code.erase (); |
688 | - int blockscnt = 0; |
689 | + string[]? get_domains_for_uri (string uri) { |
690 | + if (uri == null) |
691 | + return null; |
692 | + string[]? domains = null; |
693 | + string domain = Midori.URI.parse_hostname (uri, null); |
694 | + string[] subdomains = domain.split ("."); |
695 | + if (subdomains == null) |
696 | + return null; |
697 | + int cnt = subdomains.length - 1; |
698 | + var subdomain = new StringBuilder (subdomains[cnt]); |
699 | + subdomain.prepend_c ('.'); |
700 | + cnt--; |
701 | while (cnt >= 0) { |
702 | subdomain.prepend (subdomains[cnt]); |
703 | - string? style = null; |
704 | - foreach (Subscription sub in config) { |
705 | - foreach (var feature in sub) { |
706 | - if (feature is Adblock.Element) { |
707 | - style = (feature as Adblock.Element).lookup (subdomain.str); |
708 | - break; |
709 | + domains += subdomain.str; |
710 | + subdomain.prepend_c ('.'); |
711 | + cnt--; |
712 | + } |
713 | + return domains; |
714 | + } |
715 | + |
716 | + string? get_hider_css_rules_for_uri (string page_uri) { |
717 | + if (page_uri == null) |
718 | + return null; |
719 | + string[]? domains = get_domains_for_uri (page_uri); |
720 | + if (domains == null) |
721 | + return null; |
722 | + var code = new StringBuilder (); |
723 | + int blockscnt = 0; |
724 | + string? style = null; |
725 | + foreach (Subscription sub in config) { |
726 | + foreach (var feature in sub) { |
727 | + if (feature is Adblock.Element) { |
728 | + foreach (var subdomain in domains) { |
729 | + style = (feature as Adblock.Element).lookup (subdomain); |
730 | + if (style != null) { |
731 | + code.append (style); |
732 | + code.append_c (','); |
733 | + blockscnt++; |
734 | + } |
735 | } |
736 | } |
737 | } |
738 | - if (style != null) { |
739 | - code.append (style); |
740 | - code.append_c (','); |
741 | - blockscnt++; |
742 | - } |
743 | - subdomain.prepend_c ('.'); |
744 | - cnt--; |
745 | } |
746 | + |
747 | if (blockscnt == 0) |
748 | - return; |
749 | + return null; |
750 | code.truncate (code.len - 1); |
751 | |
752 | + string hider_css; |
753 | if (debug_element) |
754 | hider_css = " { background-color: red !important; border: 4px solid green !important; }"; |
755 | else |
756 | hider_css = " { display: none !important }"; |
757 | |
758 | code.append (hider_css); |
759 | - view.inject_stylesheet (code.str); |
760 | if (debug_element) |
761 | stdout.printf ("css: %s\n", code.str); |
762 | + |
763 | + return code.str; |
764 | + } |
765 | + |
766 | + void inject_css (Midori.View view, string page_uri) { |
767 | + /* Don't block ads on internal pages */ |
768 | + if (!Midori.URI.is_http (page_uri)) |
769 | + return; |
770 | + |
771 | + if ("adblock:element" in (Environment.get_variable ("MIDORI_DEBUG") ?? "")) |
772 | + debug_element = true; |
773 | + else |
774 | + debug_element = status_icon.debug_element_toggled; |
775 | + |
776 | + string? blocked_css = get_hider_css_for_blocked_resources (); |
777 | + if (blocked_css != null) |
778 | + view.inject_stylesheet (blocked_css); |
779 | + |
780 | + string? style = get_hider_css_rules_for_uri (page_uri); |
781 | + if (style != null) |
782 | + view.inject_stylesheet (style); |
783 | } |
784 | #endif |
785 | |
786 | internal void init () { |
787 | - debug ("Adblock2"); |
788 | - |
789 | - string config_dir = Midori.Paths.get_extension_config_dir ("adblock"); |
790 | - config = new Config (config_dir); |
791 | - reload_rules (); |
792 | - } |
793 | - |
794 | - void reload_rules () { |
795 | cache = new HashTable<string, Directive?> (str_hash, str_equal); |
796 | + load_config (); |
797 | + status_icon = new StatusIcon (config); |
798 | + manager = new SubscriptionManager (config); |
799 | foreach (Subscription sub in config) { |
800 | try { |
801 | sub.parse (); |
802 | @@ -327,24 +285,61 @@ |
803 | warning ("Error parsing %s: %s", sub.uri, error.message); |
804 | } |
805 | } |
806 | - } |
807 | - |
808 | - bool request_handled (string page_uri, string request_uri) { |
809 | - /* Always allow the main page */ |
810 | - if (request_uri == page_uri) |
811 | - return false; |
812 | - |
813 | - /* Skip adblock on internal pages */ |
814 | - if (Midori.URI.is_blank (page_uri)) |
815 | - return false; |
816 | + config.notify["size"].connect (subscriptions_added_removed); |
817 | + manager.description_label.activate_link.connect (open_link); |
818 | + } |
819 | + |
820 | + bool open_link (string uri) { |
821 | + var browser = get_app ().browser; |
822 | + var view = browser.add_uri (uri); |
823 | + browser.tab = view; |
824 | + return true; |
825 | + } |
826 | + |
827 | + void subscriptions_added_removed (ParamSpec pspec) { |
828 | + cache.remove_all (); |
829 | + } |
830 | + |
831 | + void load_config () { |
832 | + string config_dir = Midori.Paths.get_extension_config_dir ("adblock"); |
833 | + string presets = Midori.Paths.get_extension_preset_filename ("adblock", "config"); |
834 | + string filename = Path.build_filename (config_dir, "config"); |
835 | + config = new Config (filename, presets); |
836 | + string custom_list = GLib.Path.build_filename (config_dir, "custom.list"); |
837 | + try { |
838 | + custom = new Subscription (Filename.to_uri (custom_list, null)); |
839 | + custom.mutable = false; |
840 | + custom.title = _("Custom"); |
841 | + config.add (custom); |
842 | + } catch (Error error) { |
843 | + custom = null; |
844 | + warning ("Failed to add custom list %s: %s", custom_list, error.message); |
845 | + } |
846 | + } |
847 | + |
848 | + public Adblock.Directive get_directive_for_uri (string request_uri, string? page_uri = null) { |
849 | + if (!config.enabled) |
850 | + return Directive.ALLOW; |
851 | + |
852 | + if (page_uri != null) { |
853 | + /* Always allow the main page */ |
854 | + if (request_uri == page_uri) |
855 | + return Directive.ALLOW; |
856 | + |
857 | + /* Skip adblock on internal pages */ |
858 | + if (Midori.URI.is_blank (page_uri)) |
859 | + return Directive.ALLOW; |
860 | + } |
861 | |
862 | /* Skip adblock on favicons and non http schemes */ |
863 | if (!Midori.URI.is_http (request_uri) || request_uri.has_suffix ("favicon.ico")) |
864 | - return false; |
865 | + return Directive.ALLOW; |
866 | |
867 | Directive? directive = cache.lookup (request_uri); |
868 | if (directive == null) { |
869 | foreach (Subscription sub in config) { |
870 | + if (page_uri == null) |
871 | + page_uri = request_uri; |
872 | directive = sub.get_directive (request_uri, page_uri); |
873 | if (directive != null) |
874 | break; |
875 | @@ -352,8 +347,14 @@ |
876 | if (directive == null) |
877 | directive = Directive.ALLOW; |
878 | cache.insert (request_uri, directive); |
879 | + if (directive == Directive.BLOCK) |
880 | + cache.insert (page_uri, directive); |
881 | } |
882 | - return directive == Directive.BLOCK; |
883 | + return directive; |
884 | + } |
885 | + |
886 | + internal bool request_handled (string page_uri, string request_uri) { |
887 | + return get_directive_for_uri (request_uri, page_uri) == Directive.BLOCK; |
888 | } |
889 | } |
890 | |
891 | @@ -411,6 +412,179 @@ |
892 | #endif |
893 | |
894 | #if !HAVE_WEBKIT2 |
895 | +static string? tmp_folder = null; |
896 | +string get_test_file (string contents) { |
897 | + if (tmp_folder == null) |
898 | + tmp_folder = Midori.Paths.make_tmp_dir ("adblockXXXXXX"); |
899 | + string checksum = Checksum.compute_for_string (ChecksumType.MD5, contents); |
900 | + string file = Path.build_path (Path.DIR_SEPARATOR_S, tmp_folder, checksum); |
901 | + try { |
902 | + FileUtils.set_contents (file, contents, -1); |
903 | + } catch (Error file_error) { |
904 | + GLib.error (file_error.message); |
905 | + } |
906 | + return file; |
907 | +} |
908 | + |
909 | +struct TestCaseConfig { |
910 | + public string content; |
911 | + public uint size; |
912 | + public bool enabled; |
913 | +} |
914 | + |
915 | +const TestCaseConfig[] configs = { |
916 | + { "", 0, true }, |
917 | + { "[settings]", 0, true }, |
918 | + { "[settings]\nfilters=foo;", 1, true }, |
919 | + { "[settings]\nfilters=foo;\ndisabled=true", 1, false } |
920 | +}; |
921 | + |
922 | +void test_adblock_config () { |
923 | + assert (new Adblock.Config (null, null).size == 0); |
924 | + |
925 | + foreach (var conf in configs) { |
926 | + var config = new Adblock.Config (get_test_file (conf.content), null); |
927 | + if (config.size != conf.size) |
928 | + error ("Wrong size %s rather than %s:\n%s", |
929 | + config.size.to_string (), conf.size.to_string (), conf.content); |
930 | + if (config.enabled != conf.enabled) |
931 | + error ("Wrongly got enabled=%s rather than %s:\n%s", |
932 | + config.enabled.to_string (), conf.enabled.to_string (), conf.content); |
933 | + } |
934 | +} |
935 | + |
936 | +struct TestCaseSub { |
937 | + public string uri; |
938 | + public bool active; |
939 | +} |
940 | + |
941 | +const TestCaseSub[] subs = { |
942 | + { "http://foo.com", true }, |
943 | + { "http://bar.com", false }, |
944 | + { "https://spam.com", true }, |
945 | + { "https://eggs.com", false }, |
946 | + { "file:///bla", true }, |
947 | + { "file:///blub", false } |
948 | +}; |
949 | + |
950 | +void test_adblock_subs () { |
951 | + var config = new Adblock.Config (get_test_file (""" |
952 | +[settings] |
953 | +filters=http://foo.com;http-//bar.com;https://spam.com;http-://eggs.com;file:///bla;file-///blub;http://foo.com; |
954 | +"""), null); |
955 | + |
956 | + assert (config.enabled); |
957 | + foreach (var sub in subs) { |
958 | + bool found = false; |
959 | + foreach (var subscription in config) { |
960 | + if (subscription.uri == sub.uri) { |
961 | + assert (subscription.active == sub.active); |
962 | + found = true; |
963 | + } |
964 | + } |
965 | + if (!found) |
966 | + error ("%s not found", sub.uri); |
967 | + } |
968 | + |
969 | + /* 6 unique URLs, 1 duplicate */ |
970 | + assert (config.size == 6); |
971 | + /* Duplicates aren't added again either */ |
972 | + assert (!config.add (new Adblock.Subscription ("https://spam.com"))); |
973 | + |
974 | + /* Saving the config and loading it should give back identical results */ |
975 | + config.save (); |
976 | + var copy = new Adblock.Config (config.path, null); |
977 | + assert (copy.size == config.size); |
978 | + assert (copy.enabled == config.enabled); |
979 | + for (int i = 0; i < config.size; i++) { |
980 | + assert (copy[i].uri == config[i].uri); |
981 | + assert (copy[i].active == config[i].active); |
982 | + } |
983 | + /* Enabled status should be saved and loaded */ |
984 | + config.enabled = false; |
985 | + copy = new Adblock.Config (config.path, null); |
986 | + assert (copy.enabled == config.enabled); |
987 | + /* Flipping individual active values should be retained after saving */ |
988 | + foreach (var sub in config) |
989 | + sub.active = !sub.active; |
990 | + copy = new Adblock.Config (config.path, null); |
991 | + for (uint i = 0; i < config.size; i++) { |
992 | + if (config[i].active != copy[i].active) { |
993 | + string contents; |
994 | + try { |
995 | + FileUtils.get_contents (config.path, out contents, null); |
996 | + } catch (Error file_error) { |
997 | + error (file_error.message); |
998 | + } |
999 | + error ("%s is %s but should be %s:\n%s", |
1000 | + copy[i].uri, copy[i].active ? "active" : "disabled", config[i].active ? "active" : "disabled", contents); |
1001 | + } |
1002 | + } |
1003 | + |
1004 | + /* Adding and removing works, changes size */ |
1005 | + var s = new Adblock.Subscription ("http://en.de"); |
1006 | + assert (config.add (s)); |
1007 | + assert (config.size == 7); |
1008 | + config.remove (s); |
1009 | + assert (config.size == 6); |
1010 | + /* If it was removed before we should be able to add it again */ |
1011 | + assert (config.add (s)); |
1012 | + assert (config.size == 7); |
1013 | +} |
1014 | + |
1015 | +void test_adblock_init () { |
1016 | + /* No config */ |
1017 | + var extension = new Adblock.Extension (); |
1018 | + extension.init (); |
1019 | + assert (extension.config.enabled); |
1020 | + /* Defaults plus custom */ |
1021 | + if (extension.config.size != 3) |
1022 | + error ("Expected 3 initial subs, got %s".printf ( |
1023 | + extension.config.size.to_string ())); |
1024 | + assert (extension.cache.size () == 0); |
1025 | + |
1026 | + /* Add new subscription */ |
1027 | + string path = Midori.Paths.get_res_filename ("adblock.list"); |
1028 | + string uri; |
1029 | + try { |
1030 | + uri = Filename.to_uri (path, null); |
1031 | + } catch (Error error) { |
1032 | + GLib.error (error.message); |
1033 | + } |
1034 | + var sub = new Adblock.Subscription (uri); |
1035 | + extension.config.add (sub); |
1036 | + assert (extension.cache.size () == 0); |
1037 | + assert (extension.config.size == 4); |
1038 | + try { |
1039 | + sub.parse (); |
1040 | + } catch (GLib.Error error) { |
1041 | + GLib.error (error.message); |
1042 | + } |
1043 | + /* The page itself never hits */ |
1044 | + assert (!extension.request_handled ("https://ads.bogus.name/blub", "https://ads.bogus.name/blub")); |
1045 | + /* Favicons don't either */ |
1046 | + assert (!extension.request_handled ("https://foo.com", "https://ads.bogus.name/blub/favicon.ico")); |
1047 | + assert (extension.cache.size () == 0); |
1048 | + /* Some sanity checks to be sure there's no earlier problem */ |
1049 | + assert (sub.title == "Exercise"); |
1050 | + assert (sub.get_directive ("https://ads.bogus.name/blub", "") == Adblock.Directive.BLOCK); |
1051 | + /* A rule hit should add to the cache */ |
1052 | + assert (extension.request_handled ("https://foo.com", "https://ads.bogus.name/blub")); |
1053 | + assert (extension.cache.size () > 0); |
1054 | + /* Disabled means no request should be handled */ |
1055 | + extension.config.enabled = false; |
1056 | + assert (!extension.request_handled ("https://foo.com", "https://ads.bogus.name/blub")); |
1057 | + /* Removing a subscription should clear the cache */ |
1058 | + extension.config.remove (sub); |
1059 | + assert (extension.cache.size () == 0); |
1060 | + assert (extension.config.size == 3); |
1061 | + /* Now let's add a custom rule */ |
1062 | + extension.config.enabled = true; |
1063 | + extension.custom.add_rule ("*.png"); |
1064 | + assert (!extension.request_handled ("https://foo.com", "http://alpha.beta.com/images/yota.png")); |
1065 | + assert (extension.cache.size () > 0); |
1066 | + } |
1067 | + |
1068 | struct TestCaseLine { |
1069 | public string line; |
1070 | public string fixed; |
1071 | @@ -499,19 +673,27 @@ |
1072 | } |
1073 | } |
1074 | |
1075 | +string pretty_date (DateTime? date) { |
1076 | + if (date == null) |
1077 | + return "N/A"; |
1078 | + return date.to_string (); |
1079 | +} |
1080 | + |
1081 | struct TestUpdateExample { |
1082 | public string content; |
1083 | public bool result; |
1084 | + public bool valid; |
1085 | } |
1086 | |
1087 | const TestUpdateExample[] examples = { |
1088 | - { "[Adblock Plus 1.1]\n! Last modified: 05 Sep 2010 11:00 UTC\n! This list expires after 48 hours\n", true }, |
1089 | - { "[Adblock Plus 1.1]\n! Last modified: 05.09.2010 11:00 UTC\n! Expires: 2 days (update frequency)\n", true }, |
1090 | - { "[Adblock Plus 1.1]\n! Updated: 05 Nov 2024 11:00 UTC\n! Expires: 5 days (update frequency)\n", false }, |
1091 | - { "[Adblock]\n! dutchblock v3\n! This list expires after 14 days\n|http://b*.mookie1.com/\n", false }, |
1092 | - { "[Adblock Plus 2.0]\n! Last modification time (GMT): 2012.11.05 13:33\n! Expires: 5 days (update frequency)\n", true }, |
1093 | - { "[Adblock Plus 2.0]\n! Last modification time (GMT): 2012.11.05 13:33\n", true }, |
1094 | - { "[Adblock]\n ! dummy, i dont have any dates\n", false } |
1095 | + { "[Adblock Plus 1.1]\n! Last modified: 05 Sep 2010 11:00 UTC\n! This list expires after 48 hours\n", true, true }, |
1096 | + { "[Adblock Plus 1.1]\n! Last modified: 05.09.2010 11:00 UTC\n! Expires: 2 days (update frequency)\n", true, true }, |
1097 | + { "[Adblock Plus 1.1]\n! Updated: 05 Nov 2024 11:00 UTC\n! Expires: 5 days (update frequency)\n", false, true }, |
1098 | + { "[Adblock]\n! dutchblock v3\n! This list expires after 14 days\n|http://b*.mookie1.com/\n", false, true }, |
1099 | + { "[Adblock Plus 2.0]\n! Last modification time (GMT): 2012.11.05 13:33\n! Expires: 5 days (update frequency)\n", true, true }, |
1100 | + { "[Adblock Plus 2.0]\n! Last modification time (GMT): 2012.11.05 13:33\n", true, true }, |
1101 | + { "[Adblock]\n ! dummy, i dont have any dates\n", false, true }, |
1102 | + { "\n", false, false } |
1103 | }; |
1104 | |
1105 | void test_subscription_update () { |
1106 | @@ -531,23 +713,52 @@ |
1107 | foreach (var example in examples) { |
1108 | try { |
1109 | file.replace_contents (example.content.data, null, false, FileCreateFlags.NONE, null); |
1110 | - updater.last_mod_meta = null; |
1111 | - updater.expires_meta = null; |
1112 | + sub.clear (); |
1113 | sub.parse (); |
1114 | } catch (Error error) { |
1115 | GLib.error (error.message); |
1116 | } |
1117 | - if (example.result == true) |
1118 | - assert (updater.needs_updating()); |
1119 | - else |
1120 | - assert (!updater.needs_updating()); |
1121 | + if (example.valid != sub.valid) |
1122 | + error ("Subscription expected to be %svalid but %svalid:\n%s", |
1123 | + example.valid ? "" : "in", sub.valid ? "" : "in", example.content); |
1124 | + if (example.result != updater.needs_update) |
1125 | + error ("Update%s expected for:\n%s\nLast Updated: %s\nExpires: %s", |
1126 | + example.result ? "" : " not", example.content, |
1127 | + pretty_date (updater.last_updated), pretty_date (updater.expires)); |
1128 | + } |
1129 | +} |
1130 | + |
1131 | +struct TestSubUri { |
1132 | + public string? src_uri; |
1133 | + public string? dst_uri; |
1134 | +} |
1135 | + |
1136 | +const TestSubUri[] suburis = |
1137 | +{ |
1138 | + { null, null }, |
1139 | + { "not-a-link", null }, |
1140 | + { "http://some.uri", "http://some.uri" }, |
1141 | + { "abp:subscribe?location=https%3A%2F%2Feasylist-downloads.adblockplus.org%2Fabpindo%2Beasylist.txt&title=ABPindo%2BEasyList", "https://easylist-downloads.adblockplus.org/abpindo+easylist.txt" } |
1142 | +}; |
1143 | + |
1144 | +void test_subscription_uri_parsing () { |
1145 | + string? parsed_uri; |
1146 | + foreach (var example in suburis) { |
1147 | + parsed_uri = Adblock.parse_subscription_uri (example.src_uri); |
1148 | + if (parsed_uri != example.dst_uri) |
1149 | + error ("Subscription expected to be %svalid but %svalid:\n%s", |
1150 | + example.dst_uri, parsed_uri, example.src_uri); |
1151 | } |
1152 | } |
1153 | |
1154 | public void extension_test () { |
1155 | + Test.add_func ("/extensions/adblock2/config", test_adblock_config); |
1156 | + Test.add_func ("/extensions/adblock2/subs", test_adblock_subs); |
1157 | + Test.add_func ("/extensions/adblock2/init", test_adblock_init); |
1158 | Test.add_func ("/extensions/adblock2/parse", test_adblock_fixup_regexp); |
1159 | Test.add_func ("/extensions/adblock2/pattern", test_adblock_pattern); |
1160 | Test.add_func ("/extensions/adblock2/update", test_subscription_update); |
1161 | + Test.add_func ("/extensions/adblock2/subsparse", test_subscription_uri_parsing); |
1162 | } |
1163 | #endif |
1164 | |
1165 | |
1166 | === modified file 'extensions/adblock/subscriptions.vala' |
1167 | --- extensions/adblock/subscriptions.vala 2014-02-20 18:27:01 +0000 |
1168 | +++ extensions/adblock/subscriptions.vala 2014-03-10 10:27:25 +0000 |
1169 | @@ -15,6 +15,9 @@ |
1170 | public virtual bool header (string key, string value) { |
1171 | return false; |
1172 | } |
1173 | + public virtual bool parsed (File file) { |
1174 | + return true; |
1175 | + } |
1176 | public virtual Directive? match (string request_uri, string page_uri) throws Error { |
1177 | return null; |
1178 | } |
1179 | @@ -24,8 +27,12 @@ |
1180 | |
1181 | public class Subscription : GLib.Object { |
1182 | public string? path; |
1183 | + bool debug_parse; |
1184 | public string uri { get; set; default = null; } |
1185 | + public string title { get; set; default = null; } |
1186 | public bool active { get; set; default = true; } |
1187 | + public bool mutable { get; set; default = true; } |
1188 | + public bool valid { get; private set; default = true; } |
1189 | List<Feature> features; |
1190 | public Pattern pattern; |
1191 | public Keys keys; |
1192 | @@ -35,6 +42,8 @@ |
1193 | WebKit.Download? download; |
1194 | |
1195 | public Subscription (string uri) { |
1196 | + debug_parse = "adblock:parse" in (Environment.get_variable ("MIDORI_DEBUG") ?? ""); |
1197 | + |
1198 | this.uri = uri; |
1199 | |
1200 | this.optslist = new Options (); |
1201 | @@ -172,7 +181,8 @@ |
1202 | return; |
1203 | |
1204 | string format_patt = fixup_regex (prefix, patt); |
1205 | - debug ("got: %s opts %s", format_patt, opts); |
1206 | + if (debug_parse) |
1207 | + stdout.printf ("got: %s opts %s\n", format_patt, opts); |
1208 | compile_regexp (format_patt, opts); |
1209 | /* return format_patt */ |
1210 | } |
1211 | @@ -186,7 +196,8 @@ |
1212 | if (Regex.match_simple ("^/.*[\\^\\$\\*].*/$", patt, |
1213 | RegexCompileFlags.UNGREEDY, RegexMatchFlags.NOTEMPTY) |
1214 | || opts != null && opts.contains ("whitelist")) { |
1215 | - debug ("patt: %s", patt); |
1216 | + if (debug_parse) |
1217 | + stdout.printf ("patt: %s\n", patt); |
1218 | if (opts.contains ("whitelist")) |
1219 | this.whitelist.insert (patt, regex); |
1220 | else |
1221 | @@ -233,12 +244,15 @@ |
1222 | string value = ""; |
1223 | if (header.contains (":")) { |
1224 | string[] parts = header.split (":", 2); |
1225 | - if (parts[0] != null) { |
1226 | + if (parts[0] != null && parts[0] != "" |
1227 | + && parts[1] != null && parts[1] != "") { |
1228 | key = parts[0].substring (2, -1); |
1229 | value = parts[1].substring (1, -1); |
1230 | } |
1231 | } |
1232 | debug ("Header '%s' says '%s'", key, value); |
1233 | + if (key == "Title") |
1234 | + title = value; |
1235 | foreach (var feature in features) { |
1236 | if (feature.header (key, value)) |
1237 | break; |
1238 | @@ -283,18 +297,25 @@ |
1239 | #if HAVE_WEBKIT2 |
1240 | /* TODO */ |
1241 | #else |
1242 | - if (download != null) |
1243 | - return; |
1244 | + /* Don't bother trying to download local files */ |
1245 | + if (!uri.has_prefix ("file://")) { |
1246 | + if (download != null) |
1247 | + return; |
1248 | |
1249 | - download = new WebKit.Download (new WebKit.NetworkRequest (uri)); |
1250 | - download.destination_uri = Filename.to_uri (path, null); |
1251 | - download.notify["status"].connect (download_status); |
1252 | - debug ("Fetching %s to %s now", uri, download.destination_uri); |
1253 | - download.start (); |
1254 | + string destination_uri = Filename.to_uri (path, null); |
1255 | + debug ("Fetching %s to %s now", uri, destination_uri); |
1256 | + download = new WebKit.Download (new WebKit.NetworkRequest (uri)); |
1257 | + if (!Midori.Download.has_enough_space (download, destination_uri, true)) |
1258 | + throw new FileError.EXIST ("Can't download to \"%s\"", path); |
1259 | + download.destination_uri = destination_uri; |
1260 | + download.notify["status"].connect (download_status); |
1261 | + download.start (); |
1262 | #endif |
1263 | + } |
1264 | return; |
1265 | } |
1266 | |
1267 | + valid = false; |
1268 | string? line; |
1269 | while ((line = stream.read_line (null)) != null) { |
1270 | if (line == null) |
1271 | @@ -306,6 +327,13 @@ |
1272 | parse_header (chomped); |
1273 | else |
1274 | parse_line (chomped); |
1275 | + /* The file isn't completely empty */ |
1276 | + valid = true; |
1277 | + } |
1278 | + |
1279 | + foreach (var feature in features) { |
1280 | + if (!feature.parsed (filter_file)) |
1281 | + valid = false; |
1282 | } |
1283 | } |
1284 | |
1285 | @@ -324,5 +352,15 @@ |
1286 | } |
1287 | return null; |
1288 | } |
1289 | + |
1290 | + public void add_rule (string rule) { |
1291 | + try { |
1292 | + var file = File.new_for_uri (uri); |
1293 | + file.append_to (FileCreateFlags.NONE).write (("%s\n".printf (rule)).data); |
1294 | + parse (); |
1295 | + } catch (Error error) { |
1296 | + warning ("Failed to add custom rule: %s", error.message); |
1297 | + } |
1298 | + } |
1299 | } |
1300 | } |
1301 | |
1302 | === modified file 'extensions/adblock/updater.vala' |
1303 | --- extensions/adblock/updater.vala 2014-02-20 00:14:15 +0000 |
1304 | +++ extensions/adblock/updater.vala 2014-03-10 10:27:25 +0000 |
1305 | @@ -12,15 +12,23 @@ |
1306 | |
1307 | namespace Adblock { |
1308 | public class Updater : Feature { |
1309 | - public string expires_meta { get; set; default = null; } |
1310 | - public string last_mod_meta { get; set; default = null; } |
1311 | - public int64 update_tstamp { get; set; default = 0; } |
1312 | - public int64 last_mod_tstamp { get; set; default = 0; } |
1313 | - public int64 last_check_tstamp { get; set; default = 0; } |
1314 | + string expires_meta; |
1315 | + string last_mod_meta; |
1316 | + public DateTime last_updated { get; set; } |
1317 | + public DateTime expires { get; set; } |
1318 | + public bool needs_update { get; set; } |
1319 | |
1320 | public Updater () { |
1321 | } |
1322 | |
1323 | + public override void clear () { |
1324 | + expires_meta = null; |
1325 | + last_mod_meta = null; |
1326 | + last_updated = null; |
1327 | + expires = null; |
1328 | + needs_update = false; |
1329 | + } |
1330 | + |
1331 | public override bool header (string key, string value) { |
1332 | if (key.has_prefix ("Last mod") || key == "Updated") { |
1333 | last_mod_meta = value; |
1334 | @@ -37,6 +45,12 @@ |
1335 | return false; |
1336 | } |
1337 | |
1338 | + public override bool parsed (File file) { |
1339 | + process_dates (file); |
1340 | + /* It's not an error to have no update headers, we go for defaults */ |
1341 | + return true; |
1342 | + } |
1343 | + |
1344 | int get_month_from_string (string? month) { |
1345 | if (month == null) |
1346 | return 0; |
1347 | @@ -50,19 +64,17 @@ |
1348 | return 0; |
1349 | } |
1350 | |
1351 | - public bool needs_updating () { |
1352 | + void process_dates (File file) { |
1353 | DateTime now = new DateTime.now_local (); |
1354 | - DateTime expire_date = null; |
1355 | - DateTime last_mod_date = null; |
1356 | - string? last_mod = last_mod_meta; |
1357 | - string? expires = expires_meta; |
1358 | + last_updated = null; |
1359 | + expires = null; |
1360 | |
1361 | /* We have "last modification" metadata */ |
1362 | - if (last_mod != null) { |
1363 | + if (last_mod_meta != null) { |
1364 | int h = 0, min = 0, d, m, y; |
1365 | /* Date in a form of: 20.08.2012 12:34 */ |
1366 | - if (last_mod.contains (".") || last_mod.contains("-")) { |
1367 | - string[] parts = last_mod.split (" ", 2); |
1368 | + if (last_mod_meta.contains (".") || last_mod_meta.contains("-")) { |
1369 | + string[] parts = last_mod_meta.split (" ", 2); |
1370 | string[] date_parts; |
1371 | string split_char = " "; |
1372 | |
1373 | @@ -89,7 +101,7 @@ |
1374 | d = int.parse(date_parts[2]); |
1375 | } |
1376 | } else { /* Date in a form of: 20 Mar 2012 12:34 */ |
1377 | - string[] parts = last_mod.split (" ", 4); |
1378 | + string[] parts = last_mod_meta.split (" ", 4); |
1379 | /* contains time part ? */ |
1380 | if (parts[3] != null && parts[3].contains (":")) { |
1381 | string[] time_parts = parts[3].split (":", 2); |
1382 | @@ -107,33 +119,37 @@ |
1383 | } |
1384 | } |
1385 | |
1386 | - last_mod_date = new DateTime.local (y, m, d, h, min, 0.0); |
1387 | + last_updated = new DateTime.local (y, m, d, h, min, 0.0); |
1388 | + } else { |
1389 | + /* FIXME: use file modification date if there's no update header |
1390 | + try { |
1391 | + string modified = FileAttribute.TIME_MODIFIED; |
1392 | + var info = file.query_filesystem_info (modified); |
1393 | + last_updated = new DateTime.from_timeval_local (info.get_modification_time ()); |
1394 | + } catch (Error error) { |
1395 | + last_updated = now; |
1396 | + } |
1397 | + */ |
1398 | + last_updated = now; |
1399 | } |
1400 | |
1401 | - if (last_mod_date == null) |
1402 | - last_mod_date = now; |
1403 | - |
1404 | /* We have "expires" metadata */ |
1405 | - if (expires != null) { |
1406 | - if (expires.contains ("days")) { |
1407 | - string[] parts = expires.split (" "); |
1408 | - expire_date = last_mod_date.add_days (int.parse (parts[0])); |
1409 | - } else if (expires.contains ("hours")) { |
1410 | - string[] parts = expires.split (" "); |
1411 | - expire_date = last_mod_date.add_hours (int.parse (parts[0])); |
1412 | + if (expires_meta != null) { |
1413 | + if (expires_meta.contains ("days")) { |
1414 | + string[] parts = expires_meta.split (" "); |
1415 | + expires = last_updated.add_days (int.parse (parts[0])); |
1416 | + } else if (expires_meta.contains ("hours")) { |
1417 | + string[] parts = expires_meta.split (" "); |
1418 | + expires = last_updated.add_hours (int.parse (parts[0])); |
1419 | } |
1420 | } else { |
1421 | /* No expire metadata found, assume x days */ |
1422 | int days_to_expire = 7; |
1423 | - expire_date = last_mod_date.add_days (days_to_expire); |
1424 | + expires = last_updated.add_days (days_to_expire); |
1425 | } |
1426 | |
1427 | - last_mod_tstamp = last_mod_date.to_unix (); |
1428 | - last_check_tstamp = now.to_unix (); |
1429 | - update_tstamp = expire_date.to_unix (); |
1430 | - |
1431 | /* Check if we are past expire date */ |
1432 | - return now.compare (expire_date) == 1; |
1433 | + needs_update = now.compare (expires) == 1; |
1434 | } |
1435 | } |
1436 | } |
1437 | |
1438 | === added file 'extensions/adblock/widgets.vala' |
1439 | --- extensions/adblock/widgets.vala 1970-01-01 00:00:00 +0000 |
1440 | +++ extensions/adblock/widgets.vala 2014-03-10 10:27:25 +0000 |
1441 | @@ -0,0 +1,310 @@ |
1442 | +/* |
1443 | + Copyright (C) 2009-2014 Christian Dywan <christian@twotoasts.de> |
1444 | + Copyright (C) 2009-2012 Alexander Butenko <a.butenka@gmail.com> |
1445 | + |
1446 | + This library is free software; you can redistribute it and/or |
1447 | + modify it under the terms of the GNU Lesser General Public |
1448 | + License as published by the Free Software Foundation; either |
1449 | + version 2.1 of the License, or (at your option) any later version. |
1450 | + |
1451 | + See the file COPYING for the full license text. |
1452 | +*/ |
1453 | + |
1454 | +namespace Adblock { |
1455 | + |
1456 | + |
1457 | + public class StatusIcon { |
1458 | + Config config; |
1459 | + State state; |
1460 | + public bool debug_element_toggled; |
1461 | + public List<IconButton> toggle_buttons; |
1462 | + |
1463 | + public StatusIcon (Adblock.Config config) { |
1464 | + this.config = config; |
1465 | + this.debug_element_toggled = false; |
1466 | + } |
1467 | + |
1468 | + public void set_state (Adblock.State state) { |
1469 | + this.state = state; |
1470 | + update_buttons (); |
1471 | + } |
1472 | + |
1473 | + public class IconButton : Gtk.Button { |
1474 | + Gtk.Image icon; |
1475 | + |
1476 | + public IconButton () { |
1477 | + icon = new Gtk.Image (); |
1478 | + add (icon); |
1479 | + icon.show (); |
1480 | + } |
1481 | + |
1482 | + public void set_status (string status) { |
1483 | + string filename = Midori.Paths.get_res_filename ("adblock/%s.svg".printf (status)); |
1484 | + icon.set_from_file (filename); |
1485 | + } |
1486 | + } |
1487 | + |
1488 | + public void update_buttons () { |
1489 | + string state = ""; |
1490 | + foreach (var toggle_button in toggle_buttons) { |
1491 | + if (this.state == State.BLOCKED) { |
1492 | + toggle_button.set_status ("blocked"); |
1493 | + state = _("Blocking"); |
1494 | + } |
1495 | + if (this.state == State.ENABLED) { |
1496 | + toggle_button.set_status ("enabled"); |
1497 | + state = _("Enabled"); |
1498 | + } |
1499 | + if (this.state == State.DISABLED) { |
1500 | + toggle_button.set_status ("disabled"); |
1501 | + state = _("Disabled"); |
1502 | + } |
1503 | + toggle_button.set_tooltip_text (_("Adblock state: %s").printf (state)); |
1504 | + } |
1505 | + } |
1506 | + |
1507 | + public void icon_clicked (Gtk.Button toggle_button) { |
1508 | + var menu = new Gtk.Menu (); |
1509 | + var checkitem = new Gtk.CheckMenuItem.with_label (_("Disabled")); |
1510 | + checkitem.set_active (!config.enabled); |
1511 | + checkitem.toggled.connect (() => { |
1512 | + config.enabled = !checkitem.active; |
1513 | + set_state (config.enabled ? Adblock.State.ENABLED : Adblock.State.DISABLED); |
1514 | + }); |
1515 | + menu.append (checkitem); |
1516 | + |
1517 | + var hideritem = new Gtk.CheckMenuItem.with_label (_("Display hidden elements")); |
1518 | + hideritem.set_active (debug_element_toggled); |
1519 | + hideritem.toggled.connect (() => { |
1520 | + this.debug_element_toggled = hideritem.active; |
1521 | + }); |
1522 | + menu.append (hideritem); |
1523 | + |
1524 | + var menuitem = new Gtk.ImageMenuItem.with_label (_("Preferences")); |
1525 | + var image = new Gtk.Image.from_stock (Gtk.STOCK_PREFERENCES, Gtk.IconSize.MENU); |
1526 | + menuitem.always_show_image = true; |
1527 | + menuitem.set_image (image); |
1528 | + menuitem.activate.connect (() => { |
1529 | + SubscriptionManager manager = new SubscriptionManager (config); |
1530 | + manager.add_subscription (null); |
1531 | + }); |
1532 | + menu.append (menuitem); |
1533 | + |
1534 | + menu.show_all (); |
1535 | + Katze.widget_popup (toggle_button, menu, null, Katze.MenuPos.CURSOR); |
1536 | + } |
1537 | + } |
1538 | + |
1539 | + public class SubscriptionManager { |
1540 | + Gtk.TreeView treeview; |
1541 | + Gtk.ListStore liststore; |
1542 | + Adblock.Config config; |
1543 | + public Gtk.Label description_label; |
1544 | + string description; |
1545 | + |
1546 | + public SubscriptionManager (Config config) { |
1547 | + this.config = config; |
1548 | + this.liststore = new Gtk.ListStore (1, typeof (Subscription)); |
1549 | + this.description_label = new Gtk.Label (null); |
1550 | + this.description = _("Type the address of a preconfigured filter list in the text entry and hit Enter.\n"); |
1551 | + this.description += _("You can find more lists by visiting following sites:\n %s, %s\n".printf ( |
1552 | + "<a href=\"http://adblockplus.org/en/subscriptions\">adblockplus.org/en/subscriptions</a>", |
1553 | + "<a href=\"http://easylist.adblockplus.org/\">easylist.adblockplus.org</a>" |
1554 | + )); |
1555 | + } |
1556 | + |
1557 | + public void add_subscription (string? uri) { |
1558 | + var dialog = new Gtk.Dialog.with_buttons (_("Configure Advertisement filters"), |
1559 | + null, |
1560 | +#if !HAVE_GTK3 |
1561 | + Gtk.DialogFlags.NO_SEPARATOR | |
1562 | +#endif |
1563 | + Gtk.DialogFlags.DESTROY_WITH_PARENT, |
1564 | + Gtk.STOCK_HELP, Gtk.ResponseType.HELP, |
1565 | + Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE); |
1566 | +#if HAVE_GTK3 |
1567 | + dialog.get_widget_for_response (Gtk.ResponseType.HELP).get_style_context ().add_class ("help_button"); |
1568 | +#endif |
1569 | + dialog.set_icon_name (Gtk.STOCK_PROPERTIES); |
1570 | + dialog.set_response_sensitive (Gtk.ResponseType.HELP, false); |
1571 | + |
1572 | + var hbox = new Gtk.HBox (false, 0); |
1573 | + (dialog.get_content_area () as Gtk.Box).pack_start (hbox, true, true, 12); |
1574 | + var vbox = new Gtk.VBox (false, 0); |
1575 | + hbox.pack_start (vbox, true, true, 4); |
1576 | + this.description_label.set_markup (this.description); |
1577 | + this.description_label.set_line_wrap (true); |
1578 | + vbox.pack_start (this.description_label, false, false, 4); |
1579 | + |
1580 | + var entry = new Gtk.Entry (); |
1581 | + if (uri != null) |
1582 | + entry.set_text (uri); |
1583 | + vbox.pack_start (entry, false, false, 4); |
1584 | + |
1585 | + liststore = new Gtk.ListStore (1, typeof (Subscription)); |
1586 | + treeview = new Gtk.TreeView.with_model (liststore); |
1587 | + treeview.set_headers_visible (false); |
1588 | + var column = new Gtk.TreeViewColumn (); |
1589 | + var renderer_toggle = new Gtk.CellRendererToggle (); |
1590 | + column.pack_start (renderer_toggle, false); |
1591 | + column.set_cell_data_func (renderer_toggle, (column, renderer, model, iter) => { |
1592 | + Subscription sub; |
1593 | + liststore.get (iter, 0, out sub); |
1594 | + renderer.set ("active", sub.active, |
1595 | + "sensitive", sub.mutable); |
1596 | + }); |
1597 | + renderer_toggle.toggled.connect ((path) => { |
1598 | + Gtk.TreeIter iter; |
1599 | + if (liststore.get_iter_from_string (out iter, path)) { |
1600 | + Subscription sub; |
1601 | + liststore.get (iter, 0, out sub); |
1602 | + sub.active = !sub.active; |
1603 | + } |
1604 | + }); |
1605 | + treeview.append_column (column); |
1606 | + |
1607 | + column = new Gtk.TreeViewColumn (); |
1608 | + var renderer_text = new Gtk.CellRendererText (); |
1609 | + column.pack_start (renderer_text, false); |
1610 | + renderer_text.set ("editable", true); |
1611 | + // TODO: renderer_text.edited.connect |
1612 | + column.set_cell_data_func (renderer_text, (column, renderer, model, iter) => { |
1613 | + Subscription sub; |
1614 | + liststore.get (iter, 0, out sub); |
1615 | + string status = ""; |
1616 | + foreach (var feature in sub) { |
1617 | + if (feature is Adblock.Updater) { |
1618 | + var updater = feature as Adblock.Updater; |
1619 | + if (updater.last_updated != null) |
1620 | + status = updater.last_updated.format (_("Last update: %x %X")); |
1621 | + } |
1622 | + } |
1623 | + if (!sub.valid) |
1624 | + status = _("File incomplete - broken download?"); |
1625 | + renderer.set ("markup", (Markup.printf_escaped ("<b>%s</b>\n%s", |
1626 | + sub.title ?? sub.uri, status))); |
1627 | + }); |
1628 | + treeview.append_column (column); |
1629 | + |
1630 | + column = new Gtk.TreeViewColumn (); |
1631 | + Gtk.CellRendererPixbuf renderer_button = new Gtk.CellRendererPixbuf (); |
1632 | + column.pack_start (renderer_button, false); |
1633 | + column.set_cell_data_func (renderer_button, on_render_button); |
1634 | + treeview.append_column (column); |
1635 | + |
1636 | + var scrolled = new Gtk.ScrolledWindow (null, null); |
1637 | + scrolled.set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); |
1638 | + scrolled.add (treeview); |
1639 | + vbox.pack_start (scrolled); |
1640 | + |
1641 | + foreach (Subscription sub in config) |
1642 | + liststore.insert_with_values (null, 0, 0, sub); |
1643 | + treeview.button_release_event.connect (button_released); |
1644 | + |
1645 | + entry.activate.connect (() => { |
1646 | + string? parsed_uri = Adblock.parse_subscription_uri (entry.text); |
1647 | + if (parsed_uri != null) { |
1648 | + var sub = new Subscription (parsed_uri); |
1649 | + if (config.add (sub)) { |
1650 | + liststore.insert_with_values (null, 0, 0, sub); |
1651 | + try { |
1652 | + sub.parse (); |
1653 | + } catch (GLib.Error error) { |
1654 | + warning ("Error parsing %s: %s", sub.uri, error.message); |
1655 | + } |
1656 | + } |
1657 | + } |
1658 | + entry.text = ""; |
1659 | + }); |
1660 | + |
1661 | + dialog.get_content_area ().show_all (); |
1662 | + |
1663 | + dialog.response.connect ((response)=>{ dialog.destroy (); }); |
1664 | + dialog.show (); |
1665 | + } |
1666 | + |
1667 | + void on_render_button (Gtk.CellLayout column, Gtk.CellRenderer renderer, |
1668 | + Gtk.TreeModel model, Gtk.TreeIter iter) { |
1669 | + |
1670 | + Subscription sub; |
1671 | + liststore.get (iter, 0, out sub); |
1672 | + |
1673 | + renderer.set ("stock-id", sub.mutable ? Gtk.STOCK_DELETE : null, |
1674 | + "stock-size", Gtk.IconSize.MENU); |
1675 | + } |
1676 | + |
1677 | + public bool button_released (Gdk.EventButton event) { |
1678 | + Gtk.TreePath? path; |
1679 | + Gtk.TreeViewColumn column; |
1680 | + if (treeview.get_path_at_pos ((int)event.x, (int)event.y, out path, out column, null, null)) { |
1681 | + if (path != null) { |
1682 | + if (column == treeview.get_column (2)) { |
1683 | + Gtk.TreeIter iter; |
1684 | + if (liststore.get_iter (out iter, path)) { |
1685 | + Subscription sub; |
1686 | + liststore.get (iter, 0, out sub); |
1687 | + if (sub.mutable) { |
1688 | + config.remove (sub); |
1689 | + liststore.remove (iter); |
1690 | + return true; |
1691 | + } |
1692 | + } |
1693 | + } |
1694 | + } |
1695 | + } |
1696 | + return false; |
1697 | + } |
1698 | + } |
1699 | + |
1700 | + class CustomRulesEditor { |
1701 | + Gtk.Dialog dialog; |
1702 | + Subscription custom; |
1703 | + public string? rule { get; set; } |
1704 | + |
1705 | + public CustomRulesEditor (Subscription custom) { |
1706 | + this.custom = custom; |
1707 | + } |
1708 | + |
1709 | + public void set_uri (string uri) { |
1710 | + this.rule = uri; |
1711 | + } |
1712 | + |
1713 | + public void show () { |
1714 | + this.dialog = new Gtk.Dialog.with_buttons (_("Edit rule"), |
1715 | + null, |
1716 | +#if !HAVE_GTK3 |
1717 | + Gtk.DialogFlags.NO_SEPARATOR | |
1718 | +#endif |
1719 | + Gtk.DialogFlags.DESTROY_WITH_PARENT, |
1720 | + Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, |
1721 | + Gtk.STOCK_ADD, Gtk.ResponseType.ACCEPT); |
1722 | + dialog.set_icon_name (Gtk.STOCK_ADD); |
1723 | + dialog.resizable = false; |
1724 | + |
1725 | + var hbox = new Gtk.HBox (false, 8); |
1726 | + var sizegroup = new Gtk.SizeGroup (Gtk.SizeGroupMode.HORIZONTAL); |
1727 | + hbox.border_width = 5; |
1728 | + var label = new Gtk.Label.with_mnemonic (_("_Rule:")); |
1729 | + sizegroup.add_widget (label); |
1730 | + hbox.pack_start (label, false, false, 0); |
1731 | + (dialog.get_content_area () as Gtk.Box).pack_start (hbox, false, true, 0); |
1732 | + |
1733 | + var entry = new Gtk.Entry (); |
1734 | + sizegroup.add_widget (entry); |
1735 | + entry.activates_default = true; |
1736 | + entry.set_text (this.rule); |
1737 | + hbox.pack_start (entry, true, true, 0); |
1738 | + |
1739 | + dialog.get_content_area ().show_all (); |
1740 | + |
1741 | + dialog.set_default_response (Gtk.ResponseType.ACCEPT); |
1742 | + if (dialog.run () != Gtk.ResponseType.ACCEPT) |
1743 | + return; |
1744 | + |
1745 | + this.rule = entry.get_text (); |
1746 | + this.dialog.destroy (); |
1747 | + custom.add_rule (this.rule); |
1748 | + } |
1749 | + } |
1750 | + |
1751 | +} |
1752 | |
1753 | === modified file 'katze/midori-paths.vala' |
1754 | --- katze/midori-paths.vala 2014-02-20 18:27:01 +0000 |
1755 | +++ katze/midori-paths.vala 2014-03-10 10:27:25 +0000 |
1756 | @@ -366,17 +366,24 @@ |
1757 | if (Posix.access (path, Posix.F_OK) == 0) |
1758 | return path; |
1759 | |
1760 | + return build_folder ("data", null, filename) ?? |
1761 | + Path.build_filename (MDATADIR, PACKAGE_NAME, "res", filename); |
1762 | + #endif |
1763 | + } |
1764 | + |
1765 | + string? build_folder (string folder, string? middle, string filename) { |
1766 | /* Fallback to build folder */ |
1767 | File? parent = File.new_for_path (exec_path); |
1768 | while (parent != null) { |
1769 | - var data = parent.get_child ("data"); |
1770 | + var data = parent.get_child (folder); |
1771 | + if (middle != null) |
1772 | + data = data.get_child (middle); |
1773 | var child = data.get_child (filename); |
1774 | if (child.query_exists ()) |
1775 | return child.get_path (); |
1776 | parent = parent.get_parent (); |
1777 | } |
1778 | - return Path.build_filename (MDATADIR, PACKAGE_NAME, "res", filename); |
1779 | - #endif |
1780 | + return null; |
1781 | } |
1782 | |
1783 | /* returns the path to a file containing read-only data installed with the application |
1784 | @@ -416,7 +423,8 @@ |
1785 | return path; |
1786 | } |
1787 | |
1788 | - return Path.build_filename (SYSCONFDIR, "xdg", PACKAGE_NAME, folder ?? "", filename); |
1789 | + return build_folder ("config", folder, filename) ?? |
1790 | + Path.build_filename (SYSCONFDIR, "xdg", PACKAGE_NAME, folder ?? "", filename); |
1791 | #endif |
1792 | } |
1793 | |
1794 | |
1795 | === modified file 'midori/midori-app.c' |
1796 | --- midori/midori-app.c 2014-02-24 22:16:00 +0000 |
1797 | +++ midori/midori-app.c 2014-03-10 10:27:25 +0000 |
1798 | @@ -1257,7 +1257,7 @@ |
1799 | midori_debug (const gchar* token) |
1800 | { |
1801 | static const gchar* debug_token = NULL; |
1802 | - const gchar* debug_tokens = "adblock:match adblock:time adblock:element startup headers body referer cookies paths hsts unarmed bookmarks mouse app "; |
1803 | + const gchar* debug_tokens = "adblock:match adblock:parse adblock:time adblock:element startup headers body referer cookies paths hsts unarmed bookmarks mouse app "; |
1804 | if (debug_token == NULL) |
1805 | { |
1806 | gchar* found_token; |
1807 | |
1808 | === modified file 'midori/midori-browser.c' |
1809 | --- midori/midori-browser.c 2014-03-03 21:28:53 +0000 |
1810 | +++ midori/midori-browser.c 2014-03-10 10:27:25 +0000 |
1811 | @@ -1237,7 +1237,7 @@ |
1812 | |
1813 | { |
1814 | #ifndef HAVE_WEBKIT2 |
1815 | - if (!midori_download_has_enough_space (download, uri)) |
1816 | + if (!midori_download_has_enough_space (download, uri, FALSE)) |
1817 | return FALSE; |
1818 | webkit_download_set_destination_uri (download, uri); |
1819 | g_signal_emit (browser, signals[ADD_DOWNLOAD], 0, download); |
1820 | |
1821 | === modified file 'midori/midori-download.vala' |
1822 | --- midori/midori-download.vala 2014-03-05 07:17:45 +0000 |
1823 | +++ midori/midori-download.vala 2014-03-10 10:27:25 +0000 |
1824 | @@ -348,7 +348,7 @@ |
1825 | * Returns whether it seems possible to save @download to the path specified by |
1826 | * @destination_uri, considering space on disk and permissions |
1827 | */ |
1828 | - public static bool has_enough_space (WebKit.Download download, string destination_uri) { |
1829 | + public static bool has_enough_space (WebKit.Download download, string destination_uri, bool quiet=false) { |
1830 | #if !HAVE_WEBKIT2 |
1831 | var folder = File.new_for_uri (destination_uri).get_parent (); |
1832 | bool can_write; |
1833 | @@ -380,7 +380,8 @@ |
1834 | } |
1835 | else |
1836 | assert_not_reached (); |
1837 | - Sokoke.message_dialog (Gtk.MessageType.ERROR, message, detailed_message, false); |
1838 | + if (!quiet) |
1839 | + Sokoke.message_dialog (Gtk.MessageType.ERROR, message, detailed_message, false); |
1840 | return false; |
1841 | } |
1842 | #endif |
1843 | |
1844 | === modified file 'po/POTFILES.in' |
1845 | --- po/POTFILES.in 2014-03-02 23:15:34 +0000 |
1846 | +++ po/POTFILES.in 2014-03-10 10:27:25 +0000 |
1847 | @@ -102,4 +102,5 @@ |
1848 | extensions/adblock/config.vala |
1849 | extensions/adblock/updater.vala |
1850 | extensions/adblock/element.vala |
1851 | +extensions/adblock/widgets.vala |
1852 | extensions/domain-keys.vala |