Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Cris Dywan | ||||
Approved revision: | 6180 | ||||
Merged at revision: | 6291 | ||||
Proposed branch: | lp:~tuxator/midori/nojs | ||||
Merge into: | lp:midori | ||||
Diff against target: |
2975 lines (+2917/-0) 9 files modified
extensions/nojs/README.md (+1/-0) extensions/nojs/main.c (+79/-0) extensions/nojs/nojs-preferences.c (+746/-0) extensions/nojs/nojs-preferences.h (+55/-0) extensions/nojs/nojs-view.c (+804/-0) extensions/nojs/nojs-view.h (+71/-0) extensions/nojs/nojs.c (+1069/-0) extensions/nojs/nojs.h (+89/-0) po/POTFILES.in (+3/-0) |
||||
To merge this branch: | bzr merge lp:~tuxator/midori/nojs | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Cris Dywan | Approve | ||
Review via email:
|
Commit message
Introduce extension for managing javascript execution policy per domain
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added directory 'data/nojs' | |||
2 | === added file 'data/nojs/nojs-statusicon-allowed.png' | |||
3 | 0 | Binary files data/nojs/nojs-statusicon-allowed.png 1970-01-01 00:00:00 +0000 and data/nojs/nojs-statusicon-allowed.png 2013-07-29 19:51:25 +0000 differ | 0 | Binary files data/nojs/nojs-statusicon-allowed.png 1970-01-01 00:00:00 +0000 and data/nojs/nojs-statusicon-allowed.png 2013-07-29 19:51:25 +0000 differ |
4 | === added file 'data/nojs/nojs-statusicon-denied.png' | |||
5 | 1 | Binary files data/nojs/nojs-statusicon-denied.png 1970-01-01 00:00:00 +0000 and data/nojs/nojs-statusicon-denied.png 2013-07-29 19:51:25 +0000 differ | 1 | Binary files data/nojs/nojs-statusicon-denied.png 1970-01-01 00:00:00 +0000 and data/nojs/nojs-statusicon-denied.png 2013-07-29 19:51:25 +0000 differ |
6 | === added file 'data/nojs/nojs-statusicon-mixed.png' | |||
7 | 2 | Binary files data/nojs/nojs-statusicon-mixed.png 1970-01-01 00:00:00 +0000 and data/nojs/nojs-statusicon-mixed.png 2013-07-29 19:51:25 +0000 differ | 2 | Binary files data/nojs/nojs-statusicon-mixed.png 1970-01-01 00:00:00 +0000 and data/nojs/nojs-statusicon-mixed.png 2013-07-29 19:51:25 +0000 differ |
8 | === added directory 'extensions/nojs' | |||
9 | === added file 'extensions/nojs/README.md' | |||
10 | --- extensions/nojs/README.md 1970-01-01 00:00:00 +0000 | |||
11 | +++ extensions/nojs/README.md 2013-07-29 19:51:25 +0000 | |||
12 | @@ -0,0 +1,1 @@ | |||
13 | 1 | This is an extension for Midori web browser. With this extension you can manage which sites are allowed to execute javascript. | ||
14 | 0 | 2 | ||
15 | === added file 'extensions/nojs/main.c' | |||
16 | --- extensions/nojs/main.c 1970-01-01 00:00:00 +0000 | |||
17 | +++ extensions/nojs/main.c 2013-07-29 19:51:25 +0000 | |||
18 | @@ -0,0 +1,79 @@ | |||
19 | 1 | /* | ||
20 | 2 | Copyright (C) 2013 Stephan Haller <nomad@froevel.de> | ||
21 | 3 | |||
22 | 4 | This library is free software; you can redistribute it and/or | ||
23 | 5 | modify it under the terms of the GNU Lesser General Public | ||
24 | 6 | License as published by the Free Software Foundation; either | ||
25 | 7 | version 2.1 of the License, or (at your option) any later version. | ||
26 | 8 | |||
27 | 9 | See the file COPYING for the full license text. | ||
28 | 10 | */ | ||
29 | 11 | |||
30 | 12 | #include "nojs.h" | ||
31 | 13 | #include "nojs-preferences.h" | ||
32 | 14 | |||
33 | 15 | /* Global instance */ | ||
34 | 16 | NoJS *noJS=NULL; | ||
35 | 17 | |||
36 | 18 | /* This extension was activated */ | ||
37 | 19 | static void _nojs_on_activate(MidoriExtension *inExtension, MidoriApp *inApp, gpointer inUserData) | ||
38 | 20 | { | ||
39 | 21 | g_return_if_fail(noJS==NULL); | ||
40 | 22 | |||
41 | 23 | noJS=nojs_new(inExtension, inApp); | ||
42 | 24 | nojs_set_policy_for_unknown_domain(noJS, midori_extension_get_integer(inExtension, "unknown-domain-policy")); | ||
43 | 25 | nojs_set_allow_all_sites(noJS, midori_extension_get_boolean(inExtension, "allow-all-sites")); | ||
44 | 26 | nojs_set_only_second_level_domain(noJS, midori_extension_get_boolean(inExtension, "only-second-level")); | ||
45 | 27 | } | ||
46 | 28 | |||
47 | 29 | /* This extension was deactivated */ | ||
48 | 30 | static void _nojs_on_deactivate(MidoriExtension *inExtension, gpointer inUserData) | ||
49 | 31 | { | ||
50 | 32 | g_return_if_fail(noJS); | ||
51 | 33 | |||
52 | 34 | g_object_unref(noJS); | ||
53 | 35 | noJS=NULL; | ||
54 | 36 | } | ||
55 | 37 | |||
56 | 38 | /* Preferences of this extension should be opened */ | ||
57 | 39 | static void _nojs_on_preferences_response(GtkWidget* inDialog, | ||
58 | 40 | gint inResponse, | ||
59 | 41 | gpointer *inUserData) | ||
60 | 42 | { | ||
61 | 43 | gtk_widget_destroy(inDialog); | ||
62 | 44 | } | ||
63 | 45 | |||
64 | 46 | static void _nojs_on_open_preferences(MidoriExtension *inExtension) | ||
65 | 47 | { | ||
66 | 48 | g_return_if_fail(noJS); | ||
67 | 49 | |||
68 | 50 | /* Show preferences window */ | ||
69 | 51 | GtkWidget* dialog; | ||
70 | 52 | |||
71 | 53 | dialog=nojs_preferences_new(noJS); | ||
72 | 54 | gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); | ||
73 | 55 | g_signal_connect(dialog, "response", G_CALLBACK (_nojs_on_preferences_response), NULL); | ||
74 | 56 | gtk_widget_show_all(dialog); | ||
75 | 57 | } | ||
76 | 58 | |||
77 | 59 | /* Main entry for extension */ | ||
78 | 60 | MidoriExtension *extension_init(void) | ||
79 | 61 | { | ||
80 | 62 | /* Set up extension */ | ||
81 | 63 | MidoriExtension *extension=g_object_new(MIDORI_TYPE_EXTENSION, | ||
82 | 64 | "name", _("NoJS"), | ||
83 | 65 | "description", _("Manage javascript permission per site"), | ||
84 | 66 | "version", "0.1" MIDORI_VERSION_SUFFIX, | ||
85 | 67 | "authors", "Stephan Haller <nomad@froevel.de>", | ||
86 | 68 | NULL); | ||
87 | 69 | |||
88 | 70 | midori_extension_install_integer(extension, "unknown-domain-policy", NOJS_POLICY_BLOCK); | ||
89 | 71 | midori_extension_install_boolean(extension, "allow-all-sites", FALSE); | ||
90 | 72 | midori_extension_install_boolean(extension, "only-second-level", TRUE); | ||
91 | 73 | |||
92 | 74 | g_signal_connect(extension, "activate", G_CALLBACK(_nojs_on_activate), NULL); | ||
93 | 75 | g_signal_connect(extension, "deactivate", G_CALLBACK(_nojs_on_deactivate), NULL); | ||
94 | 76 | g_signal_connect(extension, "open-preferences", G_CALLBACK(_nojs_on_open_preferences), NULL); | ||
95 | 77 | |||
96 | 78 | return(extension); | ||
97 | 79 | } | ||
98 | 0 | 80 | ||
99 | === added file 'extensions/nojs/nojs-preferences.c' | |||
100 | --- extensions/nojs/nojs-preferences.c 1970-01-01 00:00:00 +0000 | |||
101 | +++ extensions/nojs/nojs-preferences.c 2013-07-29 19:51:25 +0000 | |||
102 | @@ -0,0 +1,746 @@ | |||
103 | 1 | /* | ||
104 | 2 | Copyright (C) 2013 Stephan Haller <nomad@froevel.de> | ||
105 | 3 | |||
106 | 4 | This library is free software; you can redistribute it and/or | ||
107 | 5 | modify it under the terms of the GNU Lesser General Public | ||
108 | 6 | License as published by the Free Software Foundation; either | ||
109 | 7 | version 2.1 of the License, or (at your option) any later version. | ||
110 | 8 | |||
111 | 9 | See the file COPYING for the full license text. | ||
112 | 10 | */ | ||
113 | 11 | |||
114 | 12 | #include "nojs-preferences.h" | ||
115 | 13 | |||
116 | 14 | /* Define this class in GObject system */ | ||
117 | 15 | G_DEFINE_TYPE(NoJSPreferences, | ||
118 | 16 | nojs_preferences, | ||
119 | 17 | GTK_TYPE_DIALOG) | ||
120 | 18 | |||
121 | 19 | /* Properties */ | ||
122 | 20 | enum | ||
123 | 21 | { | ||
124 | 22 | PROP_0, | ||
125 | 23 | |||
126 | 24 | PROP_MANAGER, | ||
127 | 25 | |||
128 | 26 | PROP_LAST | ||
129 | 27 | }; | ||
130 | 28 | |||
131 | 29 | static GParamSpec* NoJSPreferencesProperties[PROP_LAST]={ 0, }; | ||
132 | 30 | |||
133 | 31 | /* Private structure - access only by public API if needed */ | ||
134 | 32 | #define NOJS_PREFERENCES_GET_PRIVATE(obj) \ | ||
135 | 33 | (G_TYPE_INSTANCE_GET_PRIVATE((obj), TYPE_NOJS_PREFERENCES, NoJSPreferencesPrivate)) | ||
136 | 34 | |||
137 | 35 | struct _NoJSPreferencesPrivate | ||
138 | 36 | { | ||
139 | 37 | /* Extension related */ | ||
140 | 38 | NoJS *manager; | ||
141 | 39 | sqlite3 *database; | ||
142 | 40 | |||
143 | 41 | /* Dialog related */ | ||
144 | 42 | GtkWidget *contentArea; | ||
145 | 43 | GtkListStore *listStore; | ||
146 | 44 | GtkWidget *list; | ||
147 | 45 | GtkTreeSelection *listSelection; | ||
148 | 46 | GtkWidget *deleteButton; | ||
149 | 47 | GtkWidget *deleteAllButton; | ||
150 | 48 | GtkWidget *allowAllSitesCheckbox; | ||
151 | 49 | GtkWidget *blockUnknownDomainsCheckbox; | ||
152 | 50 | GtkWidget *checkSecondLevelOnlyCheckbox; | ||
153 | 51 | |||
154 | 52 | gint signalAllowAllSitesToggledID; | ||
155 | 53 | gint signalBlockUnknownDomainsToggledID; | ||
156 | 54 | gint signalCheckSecondLevelOnlyToggledID; | ||
157 | 55 | |||
158 | 56 | gint signalManagerChangedDatabaseID; | ||
159 | 57 | gint signalManagerChangedAllowAllSitesID; | ||
160 | 58 | gint signalManagerChangedUnknownDomainPolicyID; | ||
161 | 59 | gint signalManagerChangedCheckSecondLevelID; | ||
162 | 60 | }; | ||
163 | 61 | |||
164 | 62 | enum | ||
165 | 63 | { | ||
166 | 64 | DOMAIN_COLUMN, | ||
167 | 65 | POLICY_COLUMN, | ||
168 | 66 | N_COLUMN | ||
169 | 67 | }; | ||
170 | 68 | |||
171 | 69 | |||
172 | 70 | /* IMPLEMENTATION: Private variables and methods */ | ||
173 | 71 | |||
174 | 72 | /* Fill domain list with stored policies */ | ||
175 | 73 | static void _nojs_preferences_fill(NoJSPreferences *self) | ||
176 | 74 | { | ||
177 | 75 | NoJSPreferencesPrivate *priv=self->priv; | ||
178 | 76 | gint success; | ||
179 | 77 | sqlite3_stmt *statement=NULL; | ||
180 | 78 | |||
181 | 79 | /* Clear tree/list view */ | ||
182 | 80 | gtk_list_store_clear(priv->listStore); | ||
183 | 81 | |||
184 | 82 | /* If no database is present return here */ | ||
185 | 83 | if(!priv->database) return; | ||
186 | 84 | |||
187 | 85 | /* Fill list store with policies from database */ | ||
188 | 86 | success=sqlite3_prepare_v2(priv->database, | ||
189 | 87 | "SELECT site, value FROM policies;", | ||
190 | 88 | -1, | ||
191 | 89 | &statement, | ||
192 | 90 | NULL); | ||
193 | 91 | if(statement && success==SQLITE_OK) | ||
194 | 92 | { | ||
195 | 93 | gchar *domain; | ||
196 | 94 | gint policy; | ||
197 | 95 | gchar *policyName; | ||
198 | 96 | GtkTreeIter iter; | ||
199 | 97 | |||
200 | 98 | while(sqlite3_step(statement)==SQLITE_ROW) | ||
201 | 99 | { | ||
202 | 100 | /* Get values */ | ||
203 | 101 | domain=(gchar*)sqlite3_column_text(statement, 0); | ||
204 | 102 | policy=sqlite3_column_int(statement, 1); | ||
205 | 103 | |||
206 | 104 | switch(policy) | ||
207 | 105 | { | ||
208 | 106 | case NOJS_POLICY_ACCEPT: | ||
209 | 107 | policyName=_("Accept"); | ||
210 | 108 | break; | ||
211 | 109 | |||
212 | 110 | case NOJS_POLICY_ACCEPT_TEMPORARILY: | ||
213 | 111 | policyName=_("Accept for session"); | ||
214 | 112 | break; | ||
215 | 113 | |||
216 | 114 | case NOJS_POLICY_BLOCK: | ||
217 | 115 | policyName=_("Block"); | ||
218 | 116 | break; | ||
219 | 117 | |||
220 | 118 | default: | ||
221 | 119 | policyName=NULL; | ||
222 | 120 | break; | ||
223 | 121 | } | ||
224 | 122 | |||
225 | 123 | if(policyName) | ||
226 | 124 | { | ||
227 | 125 | gtk_list_store_append(priv->listStore, &iter); | ||
228 | 126 | gtk_list_store_set(priv->listStore, | ||
229 | 127 | &iter, | ||
230 | 128 | DOMAIN_COLUMN, domain, | ||
231 | 129 | POLICY_COLUMN, policyName, | ||
232 | 130 | -1); | ||
233 | 131 | } | ||
234 | 132 | } | ||
235 | 133 | } | ||
236 | 134 | else g_warning(_("SQL fails: %s"), sqlite3_errmsg(priv->database)); | ||
237 | 135 | |||
238 | 136 | sqlite3_finalize(statement); | ||
239 | 137 | } | ||
240 | 138 | |||
241 | 139 | /* Database instance in manager changed */ | ||
242 | 140 | static void _nojs_preferences_on_manager_database_changed(NoJSPreferences *self, | ||
243 | 141 | GParamSpec *inSpec, | ||
244 | 142 | gpointer inUserData) | ||
245 | 143 | { | ||
246 | 144 | NoJSPreferencesPrivate *priv=self->priv; | ||
247 | 145 | NoJS *manager=NOJS(inUserData); | ||
248 | 146 | gchar *databaseFile; | ||
249 | 147 | |||
250 | 148 | /* Close connection to any open database */ | ||
251 | 149 | if(priv->database) sqlite3_close(priv->database); | ||
252 | 150 | priv->database=NULL; | ||
253 | 151 | |||
254 | 152 | /* Get pointer to new database and open database */ | ||
255 | 153 | g_object_get(manager, "database-filename", &databaseFile, NULL); | ||
256 | 154 | if(databaseFile) | ||
257 | 155 | { | ||
258 | 156 | gint success; | ||
259 | 157 | |||
260 | 158 | success=sqlite3_open(databaseFile, &priv->database); | ||
261 | 159 | if(success!=SQLITE_OK) | ||
262 | 160 | { | ||
263 | 161 | g_warning(_("Could not open database of extension: %s"), sqlite3_errmsg(priv->database)); | ||
264 | 162 | |||
265 | 163 | if(priv->database) sqlite3_close(priv->database); | ||
266 | 164 | priv->database=NULL; | ||
267 | 165 | } | ||
268 | 166 | |||
269 | 167 | g_free(databaseFile); | ||
270 | 168 | } | ||
271 | 169 | |||
272 | 170 | /* Fill list with new database */ | ||
273 | 171 | _nojs_preferences_fill(self); | ||
274 | 172 | |||
275 | 173 | /* Set up availability of management buttons */ | ||
276 | 174 | gtk_widget_set_sensitive(priv->deleteAllButton, priv->database!=NULL); | ||
277 | 175 | gtk_widget_set_sensitive(priv->list, priv->database!=NULL); | ||
278 | 176 | |||
279 | 177 | return; | ||
280 | 178 | } | ||
281 | 179 | |||
282 | 180 | /* Allow-all-sites changed in check-box or manager */ | ||
283 | 181 | static void _nojs_preferences_on_allow_all_sites_changed(NoJSPreferences *self, | ||
284 | 182 | gpointer *inUserData) | ||
285 | 183 | { | ||
286 | 184 | NoJSPreferencesPrivate *priv=self->priv; | ||
287 | 185 | gboolean state; | ||
288 | 186 | |||
289 | 187 | /* Get toggle state of widget (but block signal for manager) and set in manager */ | ||
290 | 188 | g_signal_handler_block(priv->manager, priv->signalManagerChangedAllowAllSitesID); | ||
291 | 189 | |||
292 | 190 | state=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->allowAllSitesCheckbox)); | ||
293 | 191 | nojs_set_allow_all_sites(priv->manager, state); | ||
294 | 192 | |||
295 | 193 | g_signal_handler_unblock(priv->manager, priv->signalManagerChangedAllowAllSitesID); | ||
296 | 194 | } | ||
297 | 195 | |||
298 | 196 | static void _nojs_preferences_on_manager_allow_all_sites_changed(NoJSPreferences *self, | ||
299 | 197 | GParamSpec *inSpec, | ||
300 | 198 | gpointer inUserData) | ||
301 | 199 | { | ||
302 | 200 | NoJSPreferencesPrivate *priv=self->priv; | ||
303 | 201 | NoJS *manager=NOJS(inUserData); | ||
304 | 202 | gboolean state; | ||
305 | 203 | |||
306 | 204 | /* Get new value from manager */ | ||
307 | 205 | state=nojs_get_allow_all_sites(manager); | ||
308 | 206 | |||
309 | 207 | /* Set toggle in widget (but block signal for toggle) */ | ||
310 | 208 | g_signal_handler_block(priv->allowAllSitesCheckbox, priv->signalAllowAllSitesToggledID); | ||
311 | 209 | |||
312 | 210 | gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->allowAllSitesCheckbox), state); | ||
313 | 211 | |||
314 | 212 | g_signal_handler_unblock(priv->allowAllSitesCheckbox, priv->signalAllowAllSitesToggledID); | ||
315 | 213 | } | ||
316 | 214 | |||
317 | 215 | /* Block-unknown-domains changed in check-box or manager */ | ||
318 | 216 | static void _nojs_preferences_on_block_unknown_domains_changed(NoJSPreferences *self, | ||
319 | 217 | gpointer *inUserData) | ||
320 | 218 | { | ||
321 | 219 | NoJSPreferencesPrivate *priv=self->priv; | ||
322 | 220 | gboolean state; | ||
323 | 221 | NoJSPolicy policy; | ||
324 | 222 | |||
325 | 223 | /* Get toggle state of widget (but block signal for manager) and set in manager */ | ||
326 | 224 | g_signal_handler_block(priv->manager, priv->signalManagerChangedUnknownDomainPolicyID); | ||
327 | 225 | |||
328 | 226 | state=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->blockUnknownDomainsCheckbox)); | ||
329 | 227 | policy=(state ? NOJS_POLICY_BLOCK : NOJS_POLICY_ACCEPT); | ||
330 | 228 | nojs_set_policy_for_unknown_domain(priv->manager, policy); | ||
331 | 229 | |||
332 | 230 | g_signal_handler_unblock(priv->manager, priv->signalManagerChangedUnknownDomainPolicyID); | ||
333 | 231 | } | ||
334 | 232 | |||
335 | 233 | static void _nojs_preferences_on_manager_unknown_domain_policy_changed(NoJSPreferences *self, | ||
336 | 234 | GParamSpec *inSpec, | ||
337 | 235 | gpointer inUserData) | ||
338 | 236 | { | ||
339 | 237 | NoJSPreferencesPrivate *priv=self->priv; | ||
340 | 238 | NoJS *manager=NOJS(inUserData); | ||
341 | 239 | NoJSPolicy policy; | ||
342 | 240 | gboolean state; | ||
343 | 241 | |||
344 | 242 | /* Get new value from manager */ | ||
345 | 243 | policy=nojs_get_policy_for_unknown_domain(manager); | ||
346 | 244 | |||
347 | 245 | /* Set toggle in widget (but block signal for toggle) */ | ||
348 | 246 | g_signal_handler_block(priv->blockUnknownDomainsCheckbox, priv->signalBlockUnknownDomainsToggledID); | ||
349 | 247 | |||
350 | 248 | state=(policy==NOJS_POLICY_BLOCK ? TRUE : FALSE); | ||
351 | 249 | gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->blockUnknownDomainsCheckbox), state); | ||
352 | 250 | |||
353 | 251 | g_signal_handler_unblock(priv->blockUnknownDomainsCheckbox, priv->signalBlockUnknownDomainsToggledID); | ||
354 | 252 | } | ||
355 | 253 | |||
356 | 254 | /* Only-second-level changed in check-box or manager */ | ||
357 | 255 | static void _nojs_preferences_on_check_second_level_only_changed(NoJSPreferences *self, | ||
358 | 256 | gpointer *inUserData) | ||
359 | 257 | { | ||
360 | 258 | NoJSPreferencesPrivate *priv=self->priv; | ||
361 | 259 | gboolean state; | ||
362 | 260 | |||
363 | 261 | /* Get toggle state of widget (but block signal for manager) and set in manager */ | ||
364 | 262 | g_signal_handler_block(priv->manager, priv->signalManagerChangedCheckSecondLevelID); | ||
365 | 263 | |||
366 | 264 | state=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->checkSecondLevelOnlyCheckbox)); | ||
367 | 265 | nojs_set_only_second_level_domain(priv->manager, state); | ||
368 | 266 | |||
369 | 267 | g_signal_handler_unblock(priv->manager, priv->signalManagerChangedCheckSecondLevelID); | ||
370 | 268 | } | ||
371 | 269 | |||
372 | 270 | static void _nojs_preferences_on_manager_only_second_level_changed(NoJSPreferences *self, | ||
373 | 271 | GParamSpec *inSpec, | ||
374 | 272 | gpointer inUserData) | ||
375 | 273 | { | ||
376 | 274 | NoJSPreferencesPrivate *priv=self->priv; | ||
377 | 275 | NoJS *manager=NOJS(inUserData); | ||
378 | 276 | gboolean state; | ||
379 | 277 | |||
380 | 278 | /* Get new value from manager */ | ||
381 | 279 | state=nojs_get_only_second_level_domain(manager); | ||
382 | 280 | |||
383 | 281 | /* Set toggle in widget (but block signal for toggle) */ | ||
384 | 282 | g_signal_handler_block(priv->checkSecondLevelOnlyCheckbox, priv->signalCheckSecondLevelOnlyToggledID); | ||
385 | 283 | |||
386 | 284 | gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(priv->checkSecondLevelOnlyCheckbox), state); | ||
387 | 285 | |||
388 | 286 | g_signal_handler_unblock(priv->checkSecondLevelOnlyCheckbox, priv->signalCheckSecondLevelOnlyToggledID); | ||
389 | 287 | } | ||
390 | 288 | |||
391 | 289 | /* Selection in list changed */ | ||
392 | 290 | void _nojs_preferences_changed_selection(NoJSPreferences *self, | ||
393 | 291 | GtkTreeSelection *inSelection) | ||
394 | 292 | { | ||
395 | 293 | gboolean selected=(gtk_tree_selection_count_selected_rows(inSelection)>0 ? TRUE: FALSE); | ||
396 | 294 | |||
397 | 295 | gtk_widget_set_sensitive(self->priv->deleteButton, selected); | ||
398 | 296 | } | ||
399 | 297 | |||
400 | 298 | /* Delete button was clicked on selection */ | ||
401 | 299 | void _nojs_preferences_on_delete_selection(NoJSPreferences *self, | ||
402 | 300 | GtkButton *inButton) | ||
403 | 301 | { | ||
404 | 302 | NoJSPreferencesPrivate *priv=self->priv; | ||
405 | 303 | GList *rows, *row, *refs=NULL; | ||
406 | 304 | GtkTreeRowReference *ref; | ||
407 | 305 | GtkTreeModel *model=GTK_TREE_MODEL(priv->listStore); | ||
408 | 306 | GtkTreeIter iter; | ||
409 | 307 | GtkTreePath *path; | ||
410 | 308 | gchar *domain; | ||
411 | 309 | gchar *sql; | ||
412 | 310 | gint success; | ||
413 | 311 | gchar *error; | ||
414 | 312 | |||
415 | 313 | /* Get selected rows in list and create a row reference because | ||
416 | 314 | * we will modify the model while iterating through selected rows | ||
417 | 315 | */ | ||
418 | 316 | rows=gtk_tree_selection_get_selected_rows(priv->listSelection, &model); | ||
419 | 317 | for(row=rows; row; row=row->next) | ||
420 | 318 | { | ||
421 | 319 | ref=gtk_tree_row_reference_new(model, (GtkTreePath*)row->data); | ||
422 | 320 | refs=g_list_prepend(refs, ref); | ||
423 | 321 | } | ||
424 | 322 | g_list_foreach(rows,(GFunc)gtk_tree_path_free, NULL); | ||
425 | 323 | g_list_free(rows); | ||
426 | 324 | |||
427 | 325 | /* Delete each selected row by its reference */ | ||
428 | 326 | for(row=refs; row; row=row->next) | ||
429 | 327 | { | ||
430 | 328 | /* Get domain from selected row */ | ||
431 | 329 | path=gtk_tree_row_reference_get_path((GtkTreeRowReference*)row->data); | ||
432 | 330 | gtk_tree_model_get_iter(model, &iter, path); | ||
433 | 331 | gtk_tree_model_get(model, &iter, DOMAIN_COLUMN, &domain, -1); | ||
434 | 332 | |||
435 | 333 | /* Delete domain from database */ | ||
436 | 334 | sql=sqlite3_mprintf("DELETE FROM policies WHERE site='%q';", domain); | ||
437 | 335 | success=sqlite3_exec(priv->database, | ||
438 | 336 | sql, | ||
439 | 337 | NULL, | ||
440 | 338 | NULL, | ||
441 | 339 | &error); | ||
442 | 340 | if(success!=SQLITE_OK || error) | ||
443 | 341 | { | ||
444 | 342 | if(error) | ||
445 | 343 | { | ||
446 | 344 | g_critical(_("Failed to execute database statement: %s"), error); | ||
447 | 345 | sqlite3_free(error); | ||
448 | 346 | } | ||
449 | 347 | else g_critical(_("Failed to execute database statement: %s"), sqlite3_errmsg(priv->database)); | ||
450 | 348 | } | ||
451 | 349 | sqlite3_free(sql); | ||
452 | 350 | |||
453 | 351 | /* Delete row from model */ | ||
454 | 352 | gtk_list_store_remove(priv->listStore, &iter); | ||
455 | 353 | } | ||
456 | 354 | g_list_foreach(refs,(GFunc)gtk_tree_row_reference_free, NULL); | ||
457 | 355 | g_list_free(refs); | ||
458 | 356 | } | ||
459 | 357 | |||
460 | 358 | /* Delete all button was clicked */ | ||
461 | 359 | void _nojs_preferences_on_delete_all(NoJSPreferences *self, | ||
462 | 360 | GtkButton *inButton) | ||
463 | 361 | { | ||
464 | 362 | NoJSPreferencesPrivate *priv=self->priv; | ||
465 | 363 | gint success; | ||
466 | 364 | gchar *error=NULL; | ||
467 | 365 | GtkWidget *dialog; | ||
468 | 366 | gint dialogResponse; | ||
469 | 367 | |||
470 | 368 | /* Ask user if he really wants to delete all permissions */ | ||
471 | 369 | dialog=gtk_message_dialog_new(GTK_WINDOW(self), | ||
472 | 370 | GTK_DIALOG_MODAL, | ||
473 | 371 | GTK_MESSAGE_QUESTION, | ||
474 | 372 | GTK_BUTTONS_YES_NO, | ||
475 | 373 | _("Do you really want to delete all JavaScript permissions?")); | ||
476 | 374 | |||
477 | 375 | gtk_window_set_title(GTK_WINDOW(dialog), _("Delete all JavaScript permissions?")); | ||
478 | 376 | gtk_window_set_icon_name(GTK_WINDOW(dialog), GTK_STOCK_PROPERTIES); | ||
479 | 377 | |||
480 | 378 | gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), | ||
481 | 379 | _("This action will delete all JavaScript permissions. " | ||
482 | 380 | "You will be asked for permissions again for each web site visited.")); | ||
483 | 381 | |||
484 | 382 | dialogResponse=gtk_dialog_run(GTK_DIALOG(dialog)); | ||
485 | 383 | gtk_widget_destroy(dialog); | ||
486 | 384 | |||
487 | 385 | if(dialogResponse==GTK_RESPONSE_NO) return; | ||
488 | 386 | |||
489 | 387 | /* Delete all permission */ | ||
490 | 388 | success=sqlite3_exec(priv->database, | ||
491 | 389 | "DELETE FROM policies;", | ||
492 | 390 | NULL, | ||
493 | 391 | NULL, | ||
494 | 392 | &error); | ||
495 | 393 | |||
496 | 394 | if(success!=SQLITE_OK || error) | ||
497 | 395 | { | ||
498 | 396 | if(error) | ||
499 | 397 | { | ||
500 | 398 | g_critical(_("Failed to execute database statement: %s"), error); | ||
501 | 399 | sqlite3_free(error); | ||
502 | 400 | } | ||
503 | 401 | } | ||
504 | 402 | |||
505 | 403 | /* Re-setup list */ | ||
506 | 404 | _nojs_preferences_fill(self); | ||
507 | 405 | } | ||
508 | 406 | |||
509 | 407 | /* Sorting callbacks */ | ||
510 | 408 | static gint _nojs_preferences_sort_string_callback(GtkTreeModel *inModel, | ||
511 | 409 | GtkTreeIter *inLeft, | ||
512 | 410 | GtkTreeIter *inRight, | ||
513 | 411 | gpointer inUserData) | ||
514 | 412 | { | ||
515 | 413 | gchar *left, *right; | ||
516 | 414 | gint column=GPOINTER_TO_INT(inUserData); | ||
517 | 415 | gint result; | ||
518 | 416 | |||
519 | 417 | gtk_tree_model_get(inModel, inLeft, column, &left, -1); | ||
520 | 418 | gtk_tree_model_get(inModel, inRight, column, &right, -1); | ||
521 | 419 | |||
522 | 420 | result=g_strcmp0(left, right); | ||
523 | 421 | |||
524 | 422 | g_free(left); | ||
525 | 423 | g_free(right); | ||
526 | 424 | |||
527 | 425 | return(result); | ||
528 | 426 | } | ||
529 | 427 | |||
530 | 428 | /* IMPLEMENTATION: GObject */ | ||
531 | 429 | |||
532 | 430 | /* Finalize this object */ | ||
533 | 431 | static void nojs_preferences_finalize(GObject *inObject) | ||
534 | 432 | { | ||
535 | 433 | NoJSPreferencesPrivate *priv=NOJS_PREFERENCES(inObject)->priv; | ||
536 | 434 | |||
537 | 435 | /* Dispose allocated resources */ | ||
538 | 436 | if(priv->database) sqlite3_close(priv->database); | ||
539 | 437 | priv->database=NULL; | ||
540 | 438 | |||
541 | 439 | if(priv->manager) | ||
542 | 440 | { | ||
543 | 441 | if(priv->signalManagerChangedDatabaseID) g_signal_handler_disconnect(priv->manager, priv->signalManagerChangedDatabaseID); | ||
544 | 442 | priv->signalManagerChangedDatabaseID=0; | ||
545 | 443 | |||
546 | 444 | if(priv->signalManagerChangedAllowAllSitesID) g_signal_handler_disconnect(priv->manager, priv->signalManagerChangedAllowAllSitesID); | ||
547 | 445 | priv->signalManagerChangedAllowAllSitesID=0; | ||
548 | 446 | |||
549 | 447 | if(priv->signalManagerChangedUnknownDomainPolicyID) g_signal_handler_disconnect(priv->manager, priv->signalManagerChangedUnknownDomainPolicyID); | ||
550 | 448 | priv->signalManagerChangedUnknownDomainPolicyID=0; | ||
551 | 449 | |||
552 | 450 | if(priv->signalManagerChangedCheckSecondLevelID) g_signal_handler_disconnect(priv->manager, priv->signalManagerChangedCheckSecondLevelID); | ||
553 | 451 | priv->signalManagerChangedCheckSecondLevelID=0; | ||
554 | 452 | |||
555 | 453 | g_object_unref(priv->manager); | ||
556 | 454 | priv->manager=NULL; | ||
557 | 455 | } | ||
558 | 456 | |||
559 | 457 | /* Call parent's class finalize method */ | ||
560 | 458 | G_OBJECT_CLASS(nojs_preferences_parent_class)->finalize(inObject); | ||
561 | 459 | } | ||
562 | 460 | |||
563 | 461 | /* Set/get properties */ | ||
564 | 462 | static void nojs_preferences_set_property(GObject *inObject, | ||
565 | 463 | guint inPropID, | ||
566 | 464 | const GValue *inValue, | ||
567 | 465 | GParamSpec *inSpec) | ||
568 | 466 | { | ||
569 | 467 | NoJSPreferences *self=NOJS_PREFERENCES(inObject); | ||
570 | 468 | NoJSPreferencesPrivate *priv=self->priv; | ||
571 | 469 | GObject *manager; | ||
572 | 470 | |||
573 | 471 | switch(inPropID) | ||
574 | 472 | { | ||
575 | 473 | /* Construct-only properties */ | ||
576 | 474 | case PROP_MANAGER: | ||
577 | 475 | /* Release old manager if available and disconnect signals */ | ||
578 | 476 | if(priv->manager) | ||
579 | 477 | { | ||
580 | 478 | if(priv->signalManagerChangedDatabaseID) g_signal_handler_disconnect(priv->manager, priv->signalManagerChangedDatabaseID); | ||
581 | 479 | priv->signalManagerChangedDatabaseID=0; | ||
582 | 480 | |||
583 | 481 | if(priv->signalManagerChangedAllowAllSitesID) g_signal_handler_disconnect(priv->manager, priv->signalManagerChangedAllowAllSitesID); | ||
584 | 482 | priv->signalManagerChangedAllowAllSitesID=0; | ||
585 | 483 | |||
586 | 484 | if(priv->signalManagerChangedUnknownDomainPolicyID) g_signal_handler_disconnect(priv->manager, priv->signalManagerChangedUnknownDomainPolicyID); | ||
587 | 485 | priv->signalManagerChangedUnknownDomainPolicyID=0; | ||
588 | 486 | |||
589 | 487 | if(priv->signalManagerChangedCheckSecondLevelID) g_signal_handler_disconnect(priv->manager, priv->signalManagerChangedCheckSecondLevelID); | ||
590 | 488 | priv->signalManagerChangedCheckSecondLevelID=0; | ||
591 | 489 | |||
592 | 490 | g_object_unref(priv->manager); | ||
593 | 491 | priv->manager=NULL; | ||
594 | 492 | } | ||
595 | 493 | |||
596 | 494 | /* Set new JavaScript permission manager and | ||
597 | 495 | * listen to changes in database property | ||
598 | 496 | */ | ||
599 | 497 | manager=g_value_get_object(inValue); | ||
600 | 498 | if(manager) | ||
601 | 499 | { | ||
602 | 500 | priv->manager=g_object_ref(manager); | ||
603 | 501 | |||
604 | 502 | priv->signalManagerChangedDatabaseID= | ||
605 | 503 | g_signal_connect_swapped(priv->manager, | ||
606 | 504 | "notify::database-filename", | ||
607 | 505 | G_CALLBACK(_nojs_preferences_on_manager_database_changed), | ||
608 | 506 | self); | ||
609 | 507 | _nojs_preferences_on_manager_database_changed(self, NULL, priv->manager); | ||
610 | 508 | |||
611 | 509 | priv->signalManagerChangedAllowAllSitesID= | ||
612 | 510 | g_signal_connect_swapped(priv->manager, | ||
613 | 511 | "notify::allow-all-sites", | ||
614 | 512 | G_CALLBACK(_nojs_preferences_on_manager_allow_all_sites_changed), | ||
615 | 513 | self); | ||
616 | 514 | _nojs_preferences_on_manager_allow_all_sites_changed(self, NULL, priv->manager); | ||
617 | 515 | |||
618 | 516 | priv->signalManagerChangedUnknownDomainPolicyID= | ||
619 | 517 | g_signal_connect_swapped(priv->manager, | ||
620 | 518 | "notify::unknown-domain-policy", | ||
621 | 519 | G_CALLBACK(_nojs_preferences_on_manager_unknown_domain_policy_changed), | ||
622 | 520 | self); | ||
623 | 521 | _nojs_preferences_on_manager_unknown_domain_policy_changed(self, NULL, priv->manager); | ||
624 | 522 | |||
625 | 523 | priv->signalManagerChangedCheckSecondLevelID= | ||
626 | 524 | g_signal_connect_swapped(priv->manager, | ||
627 | 525 | "notify::only-second-level", | ||
628 | 526 | G_CALLBACK(_nojs_preferences_on_manager_only_second_level_changed), | ||
629 | 527 | self); | ||
630 | 528 | _nojs_preferences_on_manager_only_second_level_changed(self, NULL, priv->manager); | ||
631 | 529 | } | ||
632 | 530 | break; | ||
633 | 531 | |||
634 | 532 | default: | ||
635 | 533 | G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec); | ||
636 | 534 | break; | ||
637 | 535 | } | ||
638 | 536 | } | ||
639 | 537 | |||
640 | 538 | static void nojs_preferences_get_property(GObject *inObject, | ||
641 | 539 | guint inPropID, | ||
642 | 540 | GValue *outValue, | ||
643 | 541 | GParamSpec *inSpec) | ||
644 | 542 | { | ||
645 | 543 | NoJSPreferences *self=NOJS_PREFERENCES(inObject); | ||
646 | 544 | |||
647 | 545 | switch(inPropID) | ||
648 | 546 | { | ||
649 | 547 | case PROP_MANAGER: | ||
650 | 548 | g_value_set_object(outValue, self->priv->manager); | ||
651 | 549 | break; | ||
652 | 550 | |||
653 | 551 | default: | ||
654 | 552 | G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec); | ||
655 | 553 | break; | ||
656 | 554 | } | ||
657 | 555 | } | ||
658 | 556 | |||
659 | 557 | /* Class initialization | ||
660 | 558 | * Override functions in parent classes and define properties and signals | ||
661 | 559 | */ | ||
662 | 560 | static void nojs_preferences_class_init(NoJSPreferencesClass *klass) | ||
663 | 561 | { | ||
664 | 562 | GObjectClass *gobjectClass=G_OBJECT_CLASS(klass); | ||
665 | 563 | |||
666 | 564 | /* Override functions */ | ||
667 | 565 | gobjectClass->finalize=nojs_preferences_finalize; | ||
668 | 566 | gobjectClass->set_property=nojs_preferences_set_property; | ||
669 | 567 | gobjectClass->get_property=nojs_preferences_get_property; | ||
670 | 568 | |||
671 | 569 | /* Set up private structure */ | ||
672 | 570 | g_type_class_add_private(klass, sizeof(NoJSPreferencesPrivate)); | ||
673 | 571 | |||
674 | 572 | /* Define properties */ | ||
675 | 573 | NoJSPreferencesProperties[PROP_MANAGER]= | ||
676 | 574 | g_param_spec_object("manager", | ||
677 | 575 | _("Manager instance"), | ||
678 | 576 | _("Instance to global NoJS manager"), | ||
679 | 577 | TYPE_NOJS, | ||
680 | 578 | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); | ||
681 | 579 | |||
682 | 580 | g_object_class_install_properties(gobjectClass, PROP_LAST, NoJSPreferencesProperties); | ||
683 | 581 | } | ||
684 | 582 | |||
685 | 583 | /* Object initialization | ||
686 | 584 | * Create private structure and set up default values | ||
687 | 585 | */ | ||
688 | 586 | static void nojs_preferences_init(NoJSPreferences *self) | ||
689 | 587 | { | ||
690 | 588 | NoJSPreferencesPrivate *priv; | ||
691 | 589 | GtkTreeSortable *sortableList; | ||
692 | 590 | GtkCellRenderer *renderer; | ||
693 | 591 | GtkTreeViewColumn *column; | ||
694 | 592 | GtkWidget *widget; | ||
695 | 593 | gchar *dialogTitle; | ||
696 | 594 | GtkWidget *scrolled; | ||
697 | 595 | GtkWidget *vbox; | ||
698 | 596 | GtkWidget *hbox; | ||
699 | 597 | gint width, height; | ||
700 | 598 | |||
701 | 599 | priv=self->priv=NOJS_PREFERENCES_GET_PRIVATE(self); | ||
702 | 600 | |||
703 | 601 | /* Set up default values */ | ||
704 | 602 | priv->manager=NULL; | ||
705 | 603 | |||
706 | 604 | /* Get content area to add gui controls to */ | ||
707 | 605 | priv->contentArea=gtk_dialog_get_content_area(GTK_DIALOG(self)); | ||
708 | 606 | #if GTK_CHECK_VERSION (3, 0, 0) | ||
709 | 607 | vbox=gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); | ||
710 | 608 | gtk_box_set_homogeneous(GTK_BOX(vbox), FALSE); | ||
711 | 609 | #else | ||
712 | 610 | vbox=gtk_vbox_new(FALSE, 0); | ||
713 | 611 | #endif | ||
714 | 612 | |||
715 | 613 | /* Set up dialog */ | ||
716 | 614 | dialogTitle=_("Configure NoJS"); | ||
717 | 615 | |||
718 | 616 | gtk_window_set_title(GTK_WINDOW(self), dialogTitle); | ||
719 | 617 | gtk_window_set_icon_name(GTK_WINDOW(self), GTK_STOCK_PROPERTIES); | ||
720 | 618 | |||
721 | 619 | sokoke_widget_get_text_size(GTK_WIDGET(self), "M", &width, &height); | ||
722 | 620 | gtk_window_set_default_size(GTK_WINDOW(self), width*52, -1); | ||
723 | 621 | |||
724 | 622 | widget=sokoke_xfce_header_new(gtk_window_get_icon_name(GTK_WINDOW(self)), dialogTitle); | ||
725 | 623 | if(widget) gtk_box_pack_start(GTK_BOX(priv->contentArea), widget, FALSE, FALSE, 0); | ||
726 | 624 | |||
727 | 625 | gtk_dialog_add_button(GTK_DIALOG(self), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE); | ||
728 | 626 | |||
729 | 627 | /* Set up description */ | ||
730 | 628 | widget=gtk_label_new(NULL); | ||
731 | 629 | gtk_label_set_markup(GTK_LABEL(widget), | ||
732 | 630 | _("Below is a list of all web sites and the policy set for them. " | ||
733 | 631 | "You can delete policies by marking the entries and clicking on <i>Delete</i>.")); | ||
734 | 632 | gtk_label_set_line_wrap(GTK_LABEL(widget), TRUE); | ||
735 | 633 | gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, FALSE, 4); | ||
736 | 634 | |||
737 | 635 | /* Set up domain list */ | ||
738 | 636 | priv->listStore=gtk_list_store_new(N_COLUMN, | ||
739 | 637 | G_TYPE_STRING, /* DOMAIN_COLUMN */ | ||
740 | 638 | G_TYPE_STRING /* POLICY_COLUMN */); | ||
741 | 639 | |||
742 | 640 | sortableList=GTK_TREE_SORTABLE(priv->listStore); | ||
743 | 641 | gtk_tree_sortable_set_sort_func(sortableList, | ||
744 | 642 | DOMAIN_COLUMN, | ||
745 | 643 | (GtkTreeIterCompareFunc)_nojs_preferences_sort_string_callback, | ||
746 | 644 | GINT_TO_POINTER(DOMAIN_COLUMN), | ||
747 | 645 | NULL); | ||
748 | 646 | gtk_tree_sortable_set_sort_func(sortableList, | ||
749 | 647 | POLICY_COLUMN, | ||
750 | 648 | (GtkTreeIterCompareFunc)_nojs_preferences_sort_string_callback, | ||
751 | 649 | GINT_TO_POINTER(POLICY_COLUMN), | ||
752 | 650 | NULL); | ||
753 | 651 | gtk_tree_sortable_set_sort_column_id(sortableList, DOMAIN_COLUMN, GTK_SORT_ASCENDING); | ||
754 | 652 | |||
755 | 653 | /* Set up domain list view */ | ||
756 | 654 | priv->list=gtk_tree_view_new_with_model(GTK_TREE_MODEL(priv->listStore)); | ||
757 | 655 | |||
758 | 656 | #if !GTK_CHECK_VERSION (3, 0, 0) | ||
759 | 657 | gtk_widget_set_size_request(priv->list, -1, 300); | ||
760 | 658 | #endif | ||
761 | 659 | |||
762 | 660 | priv->listSelection=gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->list)); | ||
763 | 661 | gtk_tree_selection_set_mode(priv->listSelection, GTK_SELECTION_MULTIPLE); | ||
764 | 662 | g_signal_connect_swapped(priv->listSelection, "changed", G_CALLBACK(_nojs_preferences_changed_selection), self); | ||
765 | 663 | |||
766 | 664 | renderer=gtk_cell_renderer_text_new(); | ||
767 | 665 | column=gtk_tree_view_column_new_with_attributes(_("Domain"), | ||
768 | 666 | renderer, | ||
769 | 667 | "text", DOMAIN_COLUMN, | ||
770 | 668 | NULL); | ||
771 | 669 | gtk_tree_view_column_set_sort_column_id(column, DOMAIN_COLUMN); | ||
772 | 670 | gtk_tree_view_append_column(GTK_TREE_VIEW(priv->list), column); | ||
773 | 671 | |||
774 | 672 | renderer=gtk_cell_renderer_text_new(); | ||
775 | 673 | column=gtk_tree_view_column_new_with_attributes(_("Policy"), | ||
776 | 674 | renderer, | ||
777 | 675 | "text", POLICY_COLUMN, | ||
778 | 676 | NULL); | ||
779 | 677 | gtk_tree_view_column_set_sort_column_id(column, POLICY_COLUMN); | ||
780 | 678 | gtk_tree_view_append_column(GTK_TREE_VIEW(priv->list), column); | ||
781 | 679 | |||
782 | 680 | scrolled=gtk_scrolled_window_new(NULL, NULL); | ||
783 | 681 | #if GTK_CHECK_VERSION (3, 0, 0) | ||
784 | 682 | gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scrolled), height*10); | ||
785 | 683 | #endif | ||
786 | 684 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); | ||
787 | 685 | gtk_container_add(GTK_CONTAINER(scrolled), priv->list); | ||
788 | 686 | gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN); | ||
789 | 687 | gtk_box_pack_start(GTK_BOX(vbox), scrolled, TRUE, TRUE, 5); | ||
790 | 688 | |||
791 | 689 | /* Set up JavaScript domain list management buttons */ | ||
792 | 690 | #if GTK_CHECK_VERSION (3, 0, 0) | ||
793 | 691 | hbox=gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); | ||
794 | 692 | gtk_box_set_homogeneous(GTK_BOX(hbox), FALSE); | ||
795 | 693 | #else | ||
796 | 694 | hbox=gtk_hbox_new(FALSE, 0); | ||
797 | 695 | #endif | ||
798 | 696 | |||
799 | 697 | priv->deleteButton=gtk_button_new_from_stock(GTK_STOCK_DELETE); | ||
800 | 698 | gtk_widget_set_sensitive(priv->deleteButton, FALSE); | ||
801 | 699 | gtk_container_add(GTK_CONTAINER(hbox), priv->deleteButton); | ||
802 | 700 | g_signal_connect_swapped(priv->deleteButton, "clicked", G_CALLBACK(_nojs_preferences_on_delete_selection), self); | ||
803 | 701 | |||
804 | 702 | priv->deleteAllButton=gtk_button_new_with_mnemonic(_("Delete _all")); | ||
805 | 703 | gtk_button_set_image(GTK_BUTTON(priv->deleteAllButton), gtk_image_new_from_stock(GTK_STOCK_DELETE, GTK_ICON_SIZE_BUTTON)); | ||
806 | 704 | gtk_widget_set_sensitive(priv->deleteAllButton, FALSE); | ||
807 | 705 | gtk_container_add(GTK_CONTAINER(hbox), priv->deleteAllButton); | ||
808 | 706 | g_signal_connect_swapped(priv->deleteAllButton, "clicked", G_CALLBACK(_nojs_preferences_on_delete_all), self); | ||
809 | 707 | |||
810 | 708 | gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 5); | ||
811 | 709 | |||
812 | 710 | /* Add "allow-all-sites" checkbox */ | ||
813 | 711 | priv->allowAllSitesCheckbox=gtk_check_button_new_with_mnemonic(_("A_llow scripts at all sites")); | ||
814 | 712 | priv->signalAllowAllSitesToggledID=g_signal_connect_swapped(priv->allowAllSitesCheckbox, | ||
815 | 713 | "toggled", | ||
816 | 714 | G_CALLBACK(_nojs_preferences_on_allow_all_sites_changed), | ||
817 | 715 | self); | ||
818 | 716 | gtk_box_pack_start(GTK_BOX(vbox), priv->allowAllSitesCheckbox, TRUE, TRUE, 5); | ||
819 | 717 | |||
820 | 718 | /* Add "block-unknown-domains" checkbox */ | ||
821 | 719 | priv->blockUnknownDomainsCheckbox=gtk_check_button_new_with_mnemonic(_("Bloc_k scripts at unknown domains by default")); | ||
822 | 720 | priv->signalBlockUnknownDomainsToggledID=g_signal_connect_swapped(priv->blockUnknownDomainsCheckbox, | ||
823 | 721 | "toggled", | ||
824 | 722 | G_CALLBACK(_nojs_preferences_on_block_unknown_domains_changed), | ||
825 | 723 | self); | ||
826 | 724 | gtk_box_pack_start(GTK_BOX(vbox), priv->blockUnknownDomainsCheckbox, TRUE, TRUE, 5); | ||
827 | 725 | |||
828 | 726 | /* Add "check-second-level-only" checkbox */ | ||
829 | 727 | priv->checkSecondLevelOnlyCheckbox=gtk_check_button_new_with_mnemonic(_("S_et permissions on second-level domain")); | ||
830 | 728 | priv->signalCheckSecondLevelOnlyToggledID=g_signal_connect_swapped(priv->checkSecondLevelOnlyCheckbox, | ||
831 | 729 | "toggled", | ||
832 | 730 | G_CALLBACK(_nojs_preferences_on_check_second_level_only_changed), | ||
833 | 731 | self); | ||
834 | 732 | gtk_box_pack_start(GTK_BOX(vbox), priv->checkSecondLevelOnlyCheckbox, TRUE, TRUE, 5); | ||
835 | 733 | |||
836 | 734 | /* Finalize setup of content area */ | ||
837 | 735 | gtk_container_add(GTK_CONTAINER(priv->contentArea), vbox); | ||
838 | 736 | } | ||
839 | 737 | |||
840 | 738 | /* Implementation: Public API */ | ||
841 | 739 | |||
842 | 740 | /* Create new object */ | ||
843 | 741 | GtkWidget* nojs_preferences_new(NoJS *inManager) | ||
844 | 742 | { | ||
845 | 743 | return(g_object_new(TYPE_NOJS_PREFERENCES, | ||
846 | 744 | "manager", inManager, | ||
847 | 745 | NULL)); | ||
848 | 746 | } | ||
849 | 0 | 747 | ||
850 | === added file 'extensions/nojs/nojs-preferences.h' | |||
851 | --- extensions/nojs/nojs-preferences.h 1970-01-01 00:00:00 +0000 | |||
852 | +++ extensions/nojs/nojs-preferences.h 2013-07-29 19:51:25 +0000 | |||
853 | @@ -0,0 +1,55 @@ | |||
854 | 1 | /* | ||
855 | 2 | Copyright (C) 2013 Stephan Haller <nomad@froevel.de> | ||
856 | 3 | |||
857 | 4 | This library is free software; you can redistribute it and/or | ||
858 | 5 | modify it under the terms of the GNU Lesser General Public | ||
859 | 6 | License as published by the Free Software Foundation; either | ||
860 | 7 | version 2.1 of the License, or (at your option) any later version. | ||
861 | 8 | |||
862 | 9 | See the file COPYING for the full license text. | ||
863 | 10 | */ | ||
864 | 11 | |||
865 | 12 | #ifndef __NOJS_PREFERENCES__ | ||
866 | 13 | #define __NOJS_PREFERENCES__ | ||
867 | 14 | |||
868 | 15 | #include "config.h" | ||
869 | 16 | #include <midori/midori.h> | ||
870 | 17 | |||
871 | 18 | #include "nojs.h" | ||
872 | 19 | |||
873 | 20 | G_BEGIN_DECLS | ||
874 | 21 | |||
875 | 22 | #define TYPE_NOJS_PREFERENCES (nojs_preferences_get_type()) | ||
876 | 23 | #define NOJS_PREFERENCES(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_NOJS_PREFERENCES, NoJSPreferences)) | ||
877 | 24 | #define IS_NOJS_PREFERENCES(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_NOJS_PREFERENCES)) | ||
878 | 25 | #define NOJS_PREFERENCES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_NOJS_PREFERENCES, NoJSPreferencesClass)) | ||
879 | 26 | #define IS_NOJS_PREFERENCES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_NOJS_PREFERENCES)) | ||
880 | 27 | #define NOJS_PREFERENCES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_NOJS_PREFERENCES, NoJSPreferencesClass)) | ||
881 | 28 | |||
882 | 29 | typedef struct _NoJSPreferences NoJSPreferences; | ||
883 | 30 | typedef struct _NoJSPreferencesClass NoJSPreferencesClass; | ||
884 | 31 | typedef struct _NoJSPreferencesPrivate NoJSPreferencesPrivate; | ||
885 | 32 | |||
886 | 33 | struct _NoJSPreferences | ||
887 | 34 | { | ||
888 | 35 | /* Parent instance */ | ||
889 | 36 | GtkDialog parent_instance; | ||
890 | 37 | |||
891 | 38 | /* Private structure */ | ||
892 | 39 | NoJSPreferencesPrivate *priv; | ||
893 | 40 | }; | ||
894 | 41 | |||
895 | 42 | struct _NoJSPreferencesClass | ||
896 | 43 | { | ||
897 | 44 | /* Parent class */ | ||
898 | 45 | GtkDialogClass parent_class; | ||
899 | 46 | }; | ||
900 | 47 | |||
901 | 48 | /* Public API */ | ||
902 | 49 | GType nojs_preferences_get_type(void); | ||
903 | 50 | |||
904 | 51 | GtkWidget* nojs_preferences_new(NoJS *inManager); | ||
905 | 52 | |||
906 | 53 | G_END_DECLS | ||
907 | 54 | |||
908 | 55 | #endif /* __NOJS_PREFERENCES__ */ | ||
909 | 0 | 56 | ||
910 | === added file 'extensions/nojs/nojs-view.c' | |||
911 | --- extensions/nojs/nojs-view.c 1970-01-01 00:00:00 +0000 | |||
912 | +++ extensions/nojs/nojs-view.c 2013-07-29 19:51:25 +0000 | |||
913 | @@ -0,0 +1,804 @@ | |||
914 | 1 | /* | ||
915 | 2 | Copyright (C) 2013 Stephan Haller <nomad@froevel.de> | ||
916 | 3 | |||
917 | 4 | This library is free software; you can redistribute it and/or | ||
918 | 5 | modify it under the terms of the GNU Lesser General Public | ||
919 | 6 | License as published by the Free Software Foundation; either | ||
920 | 7 | version 2.1 of the License, or (at your option) any later version. | ||
921 | 8 | |||
922 | 9 | See the file COPYING for the full license text. | ||
923 | 10 | */ | ||
924 | 11 | |||
925 | 12 | #include "nojs-view.h" | ||
926 | 13 | #include "nojs-preferences.h" | ||
927 | 14 | |||
928 | 15 | /* Define this class in GObject system */ | ||
929 | 16 | G_DEFINE_TYPE(NoJSView, | ||
930 | 17 | nojs_view, | ||
931 | 18 | G_TYPE_OBJECT) | ||
932 | 19 | |||
933 | 20 | /* Properties */ | ||
934 | 21 | enum | ||
935 | 22 | { | ||
936 | 23 | PROP_0, | ||
937 | 24 | |||
938 | 25 | PROP_MANAGER, | ||
939 | 26 | PROP_BROWSER, | ||
940 | 27 | PROP_VIEW, | ||
941 | 28 | PROP_MENU_ICON_STATE, | ||
942 | 29 | |||
943 | 30 | PROP_LAST | ||
944 | 31 | }; | ||
945 | 32 | |||
946 | 33 | static GParamSpec* NoJSViewProperties[PROP_LAST]={ 0, }; | ||
947 | 34 | |||
948 | 35 | /* Private structure - access only by public API if needed */ | ||
949 | 36 | #define NOJS_VIEW_GET_PRIVATE(obj) \ | ||
950 | 37 | (G_TYPE_INSTANCE_GET_PRIVATE((obj), TYPE_NOJS_VIEW, NoJSViewPrivate)) | ||
951 | 38 | |||
952 | 39 | struct _NoJSViewPrivate | ||
953 | 40 | { | ||
954 | 41 | /* Extension related */ | ||
955 | 42 | NoJS *manager; | ||
956 | 43 | MidoriBrowser *browser; | ||
957 | 44 | MidoriView *view; | ||
958 | 45 | |||
959 | 46 | GtkWidget *menu; | ||
960 | 47 | gboolean menuPolicyWasChanged; | ||
961 | 48 | NoJSMenuIconState menuIconState; | ||
962 | 49 | |||
963 | 50 | GSList *resourceURIs; | ||
964 | 51 | }; | ||
965 | 52 | |||
966 | 53 | /* IMPLEMENTATION: Private variables and methods */ | ||
967 | 54 | |||
968 | 55 | /* Preferences of this extension should be opened */ | ||
969 | 56 | static void _nojs_view_on_preferences_response(GtkWidget* inDialog, | ||
970 | 57 | gint inResponse, | ||
971 | 58 | gpointer *inUserData) | ||
972 | 59 | { | ||
973 | 60 | gtk_widget_destroy(inDialog); | ||
974 | 61 | } | ||
975 | 62 | |||
976 | 63 | static void _nojs_view_on_open_preferences(NoJSView *self, gpointer inUserData) | ||
977 | 64 | { | ||
978 | 65 | g_return_if_fail(NOJS_IS_VIEW(self)); | ||
979 | 66 | |||
980 | 67 | NoJSViewPrivate *priv=self->priv; | ||
981 | 68 | |||
982 | 69 | /* Show preferences window */ | ||
983 | 70 | GtkWidget* dialog; | ||
984 | 71 | |||
985 | 72 | dialog=nojs_preferences_new(priv->manager); | ||
986 | 73 | gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); | ||
987 | 74 | g_signal_connect(dialog, "response", G_CALLBACK (_nojs_view_on_preferences_response), self); | ||
988 | 75 | gtk_widget_show_all(dialog); | ||
989 | 76 | } | ||
990 | 77 | |||
991 | 78 | /* Selection was done in menu */ | ||
992 | 79 | static void _nojs_view_on_menu_selection_done(NoJSView *self, gpointer inUserData) | ||
993 | 80 | { | ||
994 | 81 | g_return_if_fail(NOJS_IS_VIEW(self)); | ||
995 | 82 | |||
996 | 83 | NoJSViewPrivate *priv=self->priv; | ||
997 | 84 | |||
998 | 85 | /* Check if any policy was changed and reload page */ | ||
999 | 86 | if(priv->menuPolicyWasChanged!=FALSE) | ||
1000 | 87 | { | ||
1001 | 88 | /* Reset flag that any policy was changed */ | ||
1002 | 89 | priv->menuPolicyWasChanged=FALSE; | ||
1003 | 90 | |||
1004 | 91 | /* Reload page */ | ||
1005 | 92 | midori_view_reload(priv->view, FALSE); | ||
1006 | 93 | g_message("%s: Reloading page %s as policy has changed", __func__, midori_view_get_display_uri(priv->view)); | ||
1007 | 94 | } | ||
1008 | 95 | } | ||
1009 | 96 | |||
1010 | 97 | /* Destroy menu */ | ||
1011 | 98 | static void _nojs_view_destroy_menu(NoJSView *self) | ||
1012 | 99 | { | ||
1013 | 100 | g_return_if_fail(NOJS_IS_VIEW(self)); | ||
1014 | 101 | g_return_if_fail(self->priv->menu!=NULL); | ||
1015 | 102 | |||
1016 | 103 | NoJSViewPrivate *priv=self->priv; | ||
1017 | 104 | |||
1018 | 105 | /* Empty menu and list of domains added to menu */ | ||
1019 | 106 | gtk_widget_destroy(priv->menu); | ||
1020 | 107 | priv->menu=NULL; | ||
1021 | 108 | |||
1022 | 109 | /* Reset menu icon to default state */ | ||
1023 | 110 | priv->menuIconState=NOJS_MENU_ICON_STATE_UNDETERMINED; | ||
1024 | 111 | g_object_notify_by_pspec(G_OBJECT(self), NoJSViewProperties[PROP_MENU_ICON_STATE]); | ||
1025 | 112 | } | ||
1026 | 113 | |||
1027 | 114 | /* Create empty menu */ | ||
1028 | 115 | static void _nojs_view_create_empty_menu(NoJSView *self) | ||
1029 | 116 | { | ||
1030 | 117 | g_return_if_fail(NOJS_IS_VIEW(self)); | ||
1031 | 118 | g_return_if_fail(self->priv->menu==NULL); | ||
1032 | 119 | |||
1033 | 120 | NoJSViewPrivate *priv=self->priv; | ||
1034 | 121 | GtkWidget *item; | ||
1035 | 122 | |||
1036 | 123 | /* Create new menu and set up default items */ | ||
1037 | 124 | priv->menu=gtk_menu_new(); | ||
1038 | 125 | |||
1039 | 126 | item=gtk_image_menu_item_new_from_stock(GTK_STOCK_PREFERENCES, NULL); | ||
1040 | 127 | g_signal_connect_swapped(item, "activate", G_CALLBACK(_nojs_view_on_open_preferences), self); | ||
1041 | 128 | gtk_menu_shell_prepend(GTK_MENU_SHELL(priv->menu), item); | ||
1042 | 129 | gtk_widget_show_all(item); | ||
1043 | 130 | |||
1044 | 131 | /* Reset flag that any policy was changed */ | ||
1045 | 132 | priv->menuPolicyWasChanged=FALSE; | ||
1046 | 133 | |||
1047 | 134 | /* Reset menu icon to default state */ | ||
1048 | 135 | priv->menuIconState=NOJS_MENU_ICON_STATE_UNDETERMINED; | ||
1049 | 136 | g_object_notify_by_pspec(G_OBJECT(self), NoJSViewProperties[PROP_MENU_ICON_STATE]); | ||
1050 | 137 | |||
1051 | 138 | /* Connect signal to menu */ | ||
1052 | 139 | g_signal_connect_swapped(priv->menu, "selection-done", G_CALLBACK(_nojs_view_on_menu_selection_done), self); | ||
1053 | 140 | } | ||
1054 | 141 | |||
1055 | 142 | /* Change visibility state of menu item for a domain depending on policy */ | ||
1056 | 143 | static gboolean _nojs_view_menu_item_change_policy(NoJSView *self, const gchar *inDomain, NoJSPolicy inPolicy) | ||
1057 | 144 | { | ||
1058 | 145 | g_return_val_if_fail(NOJS_IS_VIEW(self), FALSE); | ||
1059 | 146 | g_return_val_if_fail(inDomain, FALSE); | ||
1060 | 147 | |||
1061 | 148 | NoJSViewPrivate *priv=self->priv; | ||
1062 | 149 | GList *items, *iter; | ||
1063 | 150 | gboolean updated; | ||
1064 | 151 | |||
1065 | 152 | /* Handle accept-for-session like accept when showing or hiding menu items */ | ||
1066 | 153 | if(inPolicy==NOJS_POLICY_ACCEPT_TEMPORARILY) inPolicy=NOJS_POLICY_ACCEPT; | ||
1067 | 154 | |||
1068 | 155 | /* Update menu items */ | ||
1069 | 156 | updated=FALSE; | ||
1070 | 157 | items=gtk_container_get_children(GTK_CONTAINER(priv->menu)); | ||
1071 | 158 | for(iter=items; iter; iter=iter->next) | ||
1072 | 159 | { | ||
1073 | 160 | /* Only check and update menu items (not separators and so on) */ | ||
1074 | 161 | if(GTK_IS_MENU_ITEM(iter->data)) | ||
1075 | 162 | { | ||
1076 | 163 | GtkMenuItem *item=GTK_MENU_ITEM(iter->data); | ||
1077 | 164 | const gchar *itemDomain; | ||
1078 | 165 | NoJSPolicy itemPolicy; | ||
1079 | 166 | |||
1080 | 167 | itemDomain=(const gchar*)g_object_get_data(G_OBJECT(item), "domain"); | ||
1081 | 168 | itemPolicy=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item), "policy")); | ||
1082 | 169 | |||
1083 | 170 | /* Handle accept-for-session like accept when showing or hiding menu items */ | ||
1084 | 171 | if(itemPolicy==NOJS_POLICY_ACCEPT_TEMPORARILY) itemPolicy=NOJS_POLICY_ACCEPT; | ||
1085 | 172 | |||
1086 | 173 | /* If menu item has "domain"-data update its visibility state | ||
1087 | 174 | * depending on matching policy | ||
1088 | 175 | */ | ||
1089 | 176 | if(g_strcmp0(itemDomain, inDomain)==0) | ||
1090 | 177 | { | ||
1091 | 178 | if(itemPolicy==inPolicy) gtk_widget_hide(GTK_WIDGET(item)); | ||
1092 | 179 | else gtk_widget_show_all(GTK_WIDGET(item)); | ||
1093 | 180 | |||
1094 | 181 | /* Set flag that at least one menu item was updated */ | ||
1095 | 182 | updated=TRUE; | ||
1096 | 183 | } | ||
1097 | 184 | } | ||
1098 | 185 | } | ||
1099 | 186 | g_list_free(items); | ||
1100 | 187 | |||
1101 | 188 | /* Return flag indicating if at least one menu item was updated */ | ||
1102 | 189 | return(updated); | ||
1103 | 190 | } | ||
1104 | 191 | |||
1105 | 192 | /* A menu item was selected */ | ||
1106 | 193 | static void _nojs_view_on_menu_item_activate(NoJSView *self, gpointer inUserData) | ||
1107 | 194 | { | ||
1108 | 195 | g_return_if_fail(NOJS_IS_VIEW(self)); | ||
1109 | 196 | g_return_if_fail(GTK_IS_MENU_ITEM(inUserData)); | ||
1110 | 197 | |||
1111 | 198 | NoJSViewPrivate *priv=self->priv; | ||
1112 | 199 | GtkMenuItem *item=GTK_MENU_ITEM(inUserData); | ||
1113 | 200 | const gchar *domain; | ||
1114 | 201 | NoJSPolicy policy; | ||
1115 | 202 | |||
1116 | 203 | /* Get domain and policy to set */ | ||
1117 | 204 | domain=(const gchar*)g_object_get_data(G_OBJECT(item), "domain"); | ||
1118 | 205 | policy=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item), "policy")); | ||
1119 | 206 | g_return_if_fail(domain); | ||
1120 | 207 | g_return_if_fail(policy>=NOJS_POLICY_ACCEPT && policy<=NOJS_POLICY_BLOCK); | ||
1121 | 208 | |||
1122 | 209 | /* Set policy for domain and update menu items */ | ||
1123 | 210 | _nojs_view_menu_item_change_policy(self, domain, policy); | ||
1124 | 211 | nojs_set_policy(priv->manager, domain, policy); | ||
1125 | 212 | |||
1126 | 213 | /* Set flag that a policy was changed */ | ||
1127 | 214 | priv->menuPolicyWasChanged=TRUE; | ||
1128 | 215 | } | ||
1129 | 216 | |||
1130 | 217 | /* Add site to menu */ | ||
1131 | 218 | static void _nojs_view_add_site_to_menu(NoJSView *self, const gchar *inDomain, NoJSPolicy inPolicy) | ||
1132 | 219 | { | ||
1133 | 220 | g_return_if_fail(NOJS_IS_VIEW(self)); | ||
1134 | 221 | g_return_if_fail(inDomain); | ||
1135 | 222 | |||
1136 | 223 | NoJSViewPrivate *priv=self->priv; | ||
1137 | 224 | GtkWidget *item; | ||
1138 | 225 | gchar *itemLabel; | ||
1139 | 226 | GtkWidget *itemImage; | ||
1140 | 227 | static gint INSERT_POSITION=1; | ||
1141 | 228 | NoJSMenuIconState newMenuIconState; | ||
1142 | 229 | |||
1143 | 230 | /* Create menu object if not available */ | ||
1144 | 231 | if(!priv->menu) _nojs_view_create_empty_menu(self); | ||
1145 | 232 | |||
1146 | 233 | /* Check if domain was already added to menu. If it exists just update it. */ | ||
1147 | 234 | if(_nojs_view_menu_item_change_policy(self, inDomain, inPolicy)==TRUE) return; | ||
1148 | 235 | |||
1149 | 236 | /* Add menu item(s) for domain */ | ||
1150 | 237 | itemLabel=g_strdup_printf(_("Deny %s"), inDomain); | ||
1151 | 238 | item=gtk_image_menu_item_new_with_label(itemLabel); | ||
1152 | 239 | itemImage=gtk_image_new_from_stock (GTK_STOCK_NO, GTK_ICON_SIZE_MENU); | ||
1153 | 240 | gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), itemImage); | ||
1154 | 241 | gtk_image_menu_item_set_always_show_image(GTK_IMAGE_MENU_ITEM(item), TRUE); | ||
1155 | 242 | gtk_menu_shell_insert(GTK_MENU_SHELL(priv->menu), item, INSERT_POSITION); | ||
1156 | 243 | if(inPolicy!=NOJS_POLICY_BLOCK) gtk_widget_show_all(item); | ||
1157 | 244 | g_object_set_data_full(G_OBJECT(item), "domain", g_strdup(inDomain), (GDestroyNotify)g_free); | ||
1158 | 245 | g_object_set_data(G_OBJECT(item), "policy", GINT_TO_POINTER(NOJS_POLICY_BLOCK)); | ||
1159 | 246 | g_signal_connect_swapped(item, "activate", G_CALLBACK(_nojs_view_on_menu_item_activate), self); | ||
1160 | 247 | g_free(itemLabel); | ||
1161 | 248 | |||
1162 | 249 | itemLabel=g_strdup_printf(_("Allow %s"), inDomain); | ||
1163 | 250 | item=gtk_image_menu_item_new_with_label(itemLabel); | ||
1164 | 251 | itemImage=gtk_image_new_from_stock (GTK_STOCK_YES, GTK_ICON_SIZE_MENU); | ||
1165 | 252 | gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), itemImage); | ||
1166 | 253 | gtk_image_menu_item_set_always_show_image(GTK_IMAGE_MENU_ITEM(item), TRUE); | ||
1167 | 254 | gtk_menu_shell_insert(GTK_MENU_SHELL(priv->menu), item, INSERT_POSITION); | ||
1168 | 255 | if(inPolicy!=NOJS_POLICY_ACCEPT && inPolicy!=NOJS_POLICY_ACCEPT_TEMPORARILY) gtk_widget_show_all(item); | ||
1169 | 256 | g_object_set_data_full(G_OBJECT(item), "domain", g_strdup(inDomain), (GDestroyNotify)g_free); | ||
1170 | 257 | g_object_set_data(G_OBJECT(item), "policy", GINT_TO_POINTER(NOJS_POLICY_ACCEPT)); | ||
1171 | 258 | g_signal_connect_swapped(item, "activate", G_CALLBACK(_nojs_view_on_menu_item_activate), self); | ||
1172 | 259 | g_free(itemLabel); | ||
1173 | 260 | |||
1174 | 261 | itemLabel=g_strdup_printf(_("Allow %s this session"), inDomain); | ||
1175 | 262 | item=gtk_image_menu_item_new_with_label(itemLabel); | ||
1176 | 263 | itemImage=gtk_image_new_from_stock (GTK_STOCK_OK, GTK_ICON_SIZE_MENU); | ||
1177 | 264 | gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), itemImage); | ||
1178 | 265 | gtk_image_menu_item_set_always_show_image(GTK_IMAGE_MENU_ITEM(item), TRUE); | ||
1179 | 266 | gtk_menu_shell_insert(GTK_MENU_SHELL(priv->menu), item, INSERT_POSITION); | ||
1180 | 267 | if(inPolicy!=NOJS_POLICY_ACCEPT && inPolicy!=NOJS_POLICY_ACCEPT_TEMPORARILY) gtk_widget_show_all(item); | ||
1181 | 268 | g_object_set_data_full(G_OBJECT(item), "domain", g_strdup(inDomain), (GDestroyNotify)g_free); | ||
1182 | 269 | g_object_set_data(G_OBJECT(item), "policy", GINT_TO_POINTER(NOJS_POLICY_ACCEPT_TEMPORARILY)); | ||
1183 | 270 | g_signal_connect_swapped(item, "activate", G_CALLBACK(_nojs_view_on_menu_item_activate), self); | ||
1184 | 271 | g_free(itemLabel); | ||
1185 | 272 | |||
1186 | 273 | /* Add seperator to seperate actions for this domain from the other domains */ | ||
1187 | 274 | item=gtk_separator_menu_item_new(); | ||
1188 | 275 | gtk_menu_shell_insert(GTK_MENU_SHELL(priv->menu), item, INSERT_POSITION); | ||
1189 | 276 | gtk_widget_show_all(item); | ||
1190 | 277 | |||
1191 | 278 | /* Determine state of status icon */ | ||
1192 | 279 | if(priv->menuIconState!=NOJS_MENU_ICON_STATE_MIXED) | ||
1193 | 280 | { | ||
1194 | 281 | switch(inPolicy) | ||
1195 | 282 | { | ||
1196 | 283 | case NOJS_POLICY_ACCEPT: | ||
1197 | 284 | case NOJS_POLICY_ACCEPT_TEMPORARILY: | ||
1198 | 285 | newMenuIconState=NOJS_MENU_ICON_STATE_ALLOWED; | ||
1199 | 286 | break; | ||
1200 | 287 | |||
1201 | 288 | case NOJS_POLICY_BLOCK: | ||
1202 | 289 | newMenuIconState=NOJS_MENU_ICON_STATE_DENIED; | ||
1203 | 290 | break; | ||
1204 | 291 | |||
1205 | 292 | default: | ||
1206 | 293 | newMenuIconState=NOJS_MENU_ICON_STATE_MIXED; | ||
1207 | 294 | break; | ||
1208 | 295 | } | ||
1209 | 296 | |||
1210 | 297 | if(priv->menuIconState==NOJS_MENU_ICON_STATE_UNDETERMINED || | ||
1211 | 298 | priv->menuIconState!=newMenuIconState) | ||
1212 | 299 | { | ||
1213 | 300 | priv->menuIconState=newMenuIconState; | ||
1214 | 301 | g_object_notify_by_pspec(G_OBJECT(self), NoJSViewProperties[PROP_MENU_ICON_STATE]); | ||
1215 | 302 | } | ||
1216 | 303 | } | ||
1217 | 304 | } | ||
1218 | 305 | |||
1219 | 306 | /* Status of loading a site has changed */ | ||
1220 | 307 | static void _nojs_view_on_load_status_changed(NoJSView *self, GParamSpec *inSpec, gpointer inUserData) | ||
1221 | 308 | { | ||
1222 | 309 | g_return_if_fail(NOJS_IS_VIEW(self)); | ||
1223 | 310 | g_return_if_fail(WEBKIT_IS_WEB_VIEW(inUserData)); | ||
1224 | 311 | |||
1225 | 312 | NoJSViewPrivate *priv=self->priv; | ||
1226 | 313 | WebKitWebView *webkitView=WEBKIT_WEB_VIEW(inUserData); | ||
1227 | 314 | WebKitWebSettings *settings=webkit_web_view_get_settings(webkitView); | ||
1228 | 315 | WebKitLoadStatus status; | ||
1229 | 316 | SoupURI *uri; | ||
1230 | 317 | |||
1231 | 318 | /* Get URI of document loading/loaded */ | ||
1232 | 319 | uri=soup_uri_new(webkit_web_view_get_uri(webkitView)); | ||
1233 | 320 | |||
1234 | 321 | /* Check load status */ | ||
1235 | 322 | status=webkit_web_view_get_load_status(webkitView); | ||
1236 | 323 | |||
1237 | 324 | /* Check if a view was emptied, e.g. for a new document going to be loaded soon */ | ||
1238 | 325 | if(status==WEBKIT_LOAD_PROVISIONAL) | ||
1239 | 326 | { | ||
1240 | 327 | /* Create a new empty menu */ | ||
1241 | 328 | _nojs_view_destroy_menu(self); | ||
1242 | 329 | _nojs_view_create_empty_menu(self); | ||
1243 | 330 | |||
1244 | 331 | /* Free list of resource URIs, that's the list of URIs for all resources | ||
1245 | 332 | * of a page | ||
1246 | 333 | */ | ||
1247 | 334 | if(priv->resourceURIs) | ||
1248 | 335 | { | ||
1249 | 336 | g_slist_free_full(priv->resourceURIs, (GDestroyNotify)g_free); | ||
1250 | 337 | priv->resourceURIs=NULL; | ||
1251 | 338 | } | ||
1252 | 339 | } | ||
1253 | 340 | |||
1254 | 341 | /* Check if document loading is going to start. Do not check special pages. */ | ||
1255 | 342 | if(status==WEBKIT_LOAD_COMMITTED && | ||
1256 | 343 | uri && | ||
1257 | 344 | uri->scheme && | ||
1258 | 345 | g_strcmp0(uri->scheme, "about")!=0) | ||
1259 | 346 | { | ||
1260 | 347 | /* Check if domain is black-listed or white-listed and enable or | ||
1261 | 348 | * disable javascript accordingly. But if settings match already | ||
1262 | 349 | * the state it should get do not set it again to avoid reloads of page. | ||
1263 | 350 | */ | ||
1264 | 351 | gchar *domain; | ||
1265 | 352 | NoJSPolicy policy; | ||
1266 | 353 | gboolean currentScriptsEnabled; | ||
1267 | 354 | gboolean newScriptsEnabled; | ||
1268 | 355 | |||
1269 | 356 | domain=nojs_get_domain(priv->manager, uri); | ||
1270 | 357 | policy=nojs_get_policy(priv->manager, domain); | ||
1271 | 358 | if(policy==NOJS_POLICY_UNDETERMINED) | ||
1272 | 359 | { | ||
1273 | 360 | policy=nojs_get_policy_for_unknown_domain(priv->manager); | ||
1274 | 361 | // TODO: Show nick_name of policy (enum) to use in warning | ||
1275 | 362 | g_warning("Got invalid policy. Using default policy for unknown domains."); | ||
1276 | 363 | } | ||
1277 | 364 | |||
1278 | 365 | newScriptsEnabled=(policy==NOJS_POLICY_BLOCK ? FALSE : TRUE); | ||
1279 | 366 | g_object_get(G_OBJECT(settings), "enable-scripts", ¤tScriptsEnabled, NULL); | ||
1280 | 367 | |||
1281 | 368 | if(newScriptsEnabled!=currentScriptsEnabled) | ||
1282 | 369 | { | ||
1283 | 370 | g_object_set(G_OBJECT(settings), "enable-scripts", newScriptsEnabled, NULL); | ||
1284 | 371 | // TODO: Set uri also to ensure this uri is going to be reloaded | ||
1285 | 372 | } | ||
1286 | 373 | |||
1287 | 374 | _nojs_view_add_site_to_menu(self, domain, policy); | ||
1288 | 375 | if(domain) g_free(domain); | ||
1289 | 376 | } | ||
1290 | 377 | |||
1291 | 378 | /* Free allocated resources */ | ||
1292 | 379 | if(uri) soup_uri_free(uri); | ||
1293 | 380 | } | ||
1294 | 381 | |||
1295 | 382 | /* A request is going to sent */ | ||
1296 | 383 | static void _nojs_view_on_resource_request_starting(NoJSView *self, | ||
1297 | 384 | WebKitWebFrame *inFrame, | ||
1298 | 385 | WebKitWebResource *inResource, | ||
1299 | 386 | WebKitNetworkRequest *inRequest, | ||
1300 | 387 | WebKitNetworkResponse *inResponse, | ||
1301 | 388 | gpointer inUserData) | ||
1302 | 389 | { | ||
1303 | 390 | g_return_if_fail(NOJS_IS_VIEW(self)); | ||
1304 | 391 | |||
1305 | 392 | NoJSViewPrivate *priv=self->priv; | ||
1306 | 393 | SoupMessage *message; | ||
1307 | 394 | SoupURI *uri; | ||
1308 | 395 | gchar *uriText; | ||
1309 | 396 | |||
1310 | 397 | /* Remember resource URIs requesting */ | ||
1311 | 398 | message=(inRequest ? webkit_network_request_get_message(inRequest) : NULL); | ||
1312 | 399 | if(message) | ||
1313 | 400 | { | ||
1314 | 401 | uri=soup_message_get_uri(message); | ||
1315 | 402 | if(uri) | ||
1316 | 403 | { | ||
1317 | 404 | uriText=soup_uri_to_string(uri, FALSE); | ||
1318 | 405 | priv->resourceURIs=g_slist_prepend(priv->resourceURIs, uriText); | ||
1319 | 406 | } | ||
1320 | 407 | } | ||
1321 | 408 | |||
1322 | 409 | message=(inResponse ? webkit_network_response_get_message(inResponse) : NULL); | ||
1323 | 410 | if(message) | ||
1324 | 411 | { | ||
1325 | 412 | uri=soup_message_get_uri(message); | ||
1326 | 413 | if(uri) | ||
1327 | 414 | { | ||
1328 | 415 | uriText=soup_uri_to_string(uri, FALSE); | ||
1329 | 416 | priv->resourceURIs=g_slist_prepend(priv->resourceURIs, uriText); | ||
1330 | 417 | } | ||
1331 | 418 | } | ||
1332 | 419 | } | ||
1333 | 420 | |||
1334 | 421 | /* A policy has changed */ | ||
1335 | 422 | static void _nojs_view_on_policy_changed(NoJSView *self, gchar *inDomain, gpointer inUserData) | ||
1336 | 423 | { | ||
1337 | 424 | g_return_if_fail(NOJS_IS_VIEW(self)); | ||
1338 | 425 | g_return_if_fail(inDomain); | ||
1339 | 426 | |||
1340 | 427 | NoJSViewPrivate *priv=self->priv; | ||
1341 | 428 | GList *items, *iter; | ||
1342 | 429 | gboolean reloaded; | ||
1343 | 430 | |||
1344 | 431 | /* Check if the policy of a domain has changed this view has referenced resources to */ | ||
1345 | 432 | reloaded=FALSE; | ||
1346 | 433 | items=gtk_container_get_children(GTK_CONTAINER(priv->menu)); | ||
1347 | 434 | for(iter=items; reloaded==FALSE && iter; iter=iter->next) | ||
1348 | 435 | { | ||
1349 | 436 | if(GTK_IS_MENU_ITEM(iter->data)) | ||
1350 | 437 | { | ||
1351 | 438 | const gchar *itemDomain; | ||
1352 | 439 | |||
1353 | 440 | /* Check if domain matches menu item */ | ||
1354 | 441 | itemDomain=(const gchar*)g_object_get_data(G_OBJECT(iter->data), "domain"); | ||
1355 | 442 | if(g_strcmp0(itemDomain, inDomain)==0) | ||
1356 | 443 | { | ||
1357 | 444 | /* Found domain in our menu so reload page */ | ||
1358 | 445 | midori_view_reload(priv->view, FALSE); | ||
1359 | 446 | reloaded=TRUE; | ||
1360 | 447 | } | ||
1361 | 448 | } | ||
1362 | 449 | } | ||
1363 | 450 | g_list_free(items); | ||
1364 | 451 | } | ||
1365 | 452 | |||
1366 | 453 | /* A javascript URI is going to loaded or blocked */ | ||
1367 | 454 | static void _nojs_view_on_uri_load_policy_status(NoJSView *self, gchar *inURI, NoJSPolicy inPolicy, gpointer inUserData) | ||
1368 | 455 | { | ||
1369 | 456 | g_return_if_fail(NOJS_IS_VIEW(self)); | ||
1370 | 457 | |||
1371 | 458 | NoJSViewPrivate *priv=self->priv; | ||
1372 | 459 | GSList *iter; | ||
1373 | 460 | gchar *checkURI; | ||
1374 | 461 | |||
1375 | 462 | /* Check if uri (accepted or blocked) might be one of ours */ | ||
1376 | 463 | for(iter=priv->resourceURIs; iter; iter=iter->next) | ||
1377 | 464 | { | ||
1378 | 465 | checkURI=(gchar*)iter->data; | ||
1379 | 466 | if(g_strcmp0(checkURI, inURI)==0) | ||
1380 | 467 | { | ||
1381 | 468 | SoupURI *uri; | ||
1382 | 469 | gchar *domain; | ||
1383 | 470 | |||
1384 | 471 | uri=soup_uri_new(inURI); | ||
1385 | 472 | domain=nojs_get_domain(priv->manager, uri); | ||
1386 | 473 | if(domain) | ||
1387 | 474 | { | ||
1388 | 475 | _nojs_view_add_site_to_menu(self, domain, inPolicy); | ||
1389 | 476 | g_free(domain); | ||
1390 | 477 | } | ||
1391 | 478 | |||
1392 | 479 | soup_uri_free(uri); | ||
1393 | 480 | break; | ||
1394 | 481 | } | ||
1395 | 482 | } | ||
1396 | 483 | } | ||
1397 | 484 | |||
1398 | 485 | /* Property "view" has changed */ | ||
1399 | 486 | static void _nojs_view_on_view_changed(NoJSView *self, MidoriView *inView) | ||
1400 | 487 | { | ||
1401 | 488 | NoJSViewPrivate *priv=self->priv; | ||
1402 | 489 | WebKitWebView *webkitView; | ||
1403 | 490 | |||
1404 | 491 | /* Disconnect signal on old view */ | ||
1405 | 492 | if(priv->view) | ||
1406 | 493 | { | ||
1407 | 494 | webkitView=WEBKIT_WEB_VIEW(midori_view_get_web_view(priv->view)); | ||
1408 | 495 | g_signal_handlers_disconnect_by_data(webkitView, self); | ||
1409 | 496 | g_object_set_data(G_OBJECT(priv->view), "nojs-view-instance", NULL); | ||
1410 | 497 | g_object_unref(priv->view); | ||
1411 | 498 | priv->view=NULL; | ||
1412 | 499 | } | ||
1413 | 500 | |||
1414 | 501 | /* Set new view if valid pointer */ | ||
1415 | 502 | if(!inView) return; | ||
1416 | 503 | |||
1417 | 504 | priv->view=g_object_ref(inView); | ||
1418 | 505 | g_object_set_data(G_OBJECT(priv->view), "nojs-view-instance", self); | ||
1419 | 506 | |||
1420 | 507 | /* Listen to changes of load-status in view */ | ||
1421 | 508 | webkitView=WEBKIT_WEB_VIEW(midori_view_get_web_view(priv->view)); | ||
1422 | 509 | g_signal_connect_swapped(webkitView, "notify::load-status", G_CALLBACK(_nojs_view_on_load_status_changed), self); | ||
1423 | 510 | g_signal_connect_swapped(webkitView, "resource-request-starting", G_CALLBACK(_nojs_view_on_resource_request_starting), self); | ||
1424 | 511 | |||
1425 | 512 | /* Create empty menu */ | ||
1426 | 513 | _nojs_view_destroy_menu(self); | ||
1427 | 514 | _nojs_view_create_empty_menu(self); | ||
1428 | 515 | |||
1429 | 516 | /* Release list of resource URIs */ | ||
1430 | 517 | if(priv->resourceURIs) | ||
1431 | 518 | { | ||
1432 | 519 | g_slist_free_full(priv->resourceURIs, (GDestroyNotify)g_free); | ||
1433 | 520 | priv->resourceURIs=NULL; | ||
1434 | 521 | } | ||
1435 | 522 | } | ||
1436 | 523 | |||
1437 | 524 | /* This extension is going to be deactivated */ | ||
1438 | 525 | static void _nojs_view_on_extension_deactivated(NoJSView *self, MidoriExtension *inExtension) | ||
1439 | 526 | { | ||
1440 | 527 | g_return_if_fail(NOJS_IS_VIEW(self)); | ||
1441 | 528 | |||
1442 | 529 | /* Dispose allocated resources by unreferencing ourselve */ | ||
1443 | 530 | g_object_unref(self); | ||
1444 | 531 | } | ||
1445 | 532 | |||
1446 | 533 | /* Property "manager" has changed */ | ||
1447 | 534 | static void _nojs_view_on_manager_changed(NoJSView *self, NoJS *inNoJS) | ||
1448 | 535 | { | ||
1449 | 536 | g_return_if_fail(NOJS_IS_VIEW(self)); | ||
1450 | 537 | g_return_if_fail(!inNoJS || IS_NOJS(inNoJS)); | ||
1451 | 538 | |||
1452 | 539 | NoJSViewPrivate *priv=self->priv; | ||
1453 | 540 | MidoriExtension *extension; | ||
1454 | 541 | |||
1455 | 542 | /* Release reference to old manager and clean up */ | ||
1456 | 543 | if(priv->manager) | ||
1457 | 544 | { | ||
1458 | 545 | g_object_get(priv->manager, "extension", &extension, NULL); | ||
1459 | 546 | g_signal_handlers_disconnect_by_data(extension, self); | ||
1460 | 547 | g_object_unref(extension); | ||
1461 | 548 | |||
1462 | 549 | g_signal_handlers_disconnect_by_data(priv->manager, self); | ||
1463 | 550 | g_object_unref(priv->manager); | ||
1464 | 551 | priv->manager=NULL; | ||
1465 | 552 | } | ||
1466 | 553 | |||
1467 | 554 | /* Set new view if valid pointer */ | ||
1468 | 555 | if(!inNoJS) return; | ||
1469 | 556 | |||
1470 | 557 | priv->manager=g_object_ref(inNoJS); | ||
1471 | 558 | |||
1472 | 559 | /* Connect signals to manager */ | ||
1473 | 560 | g_signal_connect_swapped(priv->manager, "uri-load-policy-status", G_CALLBACK(_nojs_view_on_uri_load_policy_status), self); | ||
1474 | 561 | g_signal_connect_swapped(priv->manager, "policy-changed", G_CALLBACK(_nojs_view_on_policy_changed), self); | ||
1475 | 562 | |||
1476 | 563 | /* Connect signal to get noticed when extension is going to be deactivated | ||
1477 | 564 | * to release all references to GObjects | ||
1478 | 565 | */ | ||
1479 | 566 | g_object_get(priv->manager, "extension", &extension, NULL); | ||
1480 | 567 | g_signal_connect_swapped(extension, "deactivate", G_CALLBACK(_nojs_view_on_extension_deactivated), self); | ||
1481 | 568 | g_object_unref(extension); | ||
1482 | 569 | } | ||
1483 | 570 | |||
1484 | 571 | /* IMPLEMENTATION: GObject */ | ||
1485 | 572 | |||
1486 | 573 | /* Finalize this object */ | ||
1487 | 574 | static void nojs_view_finalize(GObject *inObject) | ||
1488 | 575 | { | ||
1489 | 576 | NoJSView *self=NOJS_VIEW(inObject); | ||
1490 | 577 | NoJSViewPrivate *priv=self->priv; | ||
1491 | 578 | |||
1492 | 579 | /* Dispose allocated resources */ | ||
1493 | 580 | if(priv->manager) | ||
1494 | 581 | { | ||
1495 | 582 | MidoriExtension *extension; | ||
1496 | 583 | |||
1497 | 584 | g_object_get(priv->manager, "extension", &extension, NULL); | ||
1498 | 585 | g_signal_handlers_disconnect_by_data(extension, self); | ||
1499 | 586 | g_object_unref(extension); | ||
1500 | 587 | |||
1501 | 588 | g_signal_handlers_disconnect_by_data(priv->manager, self); | ||
1502 | 589 | g_object_unref(priv->manager); | ||
1503 | 590 | priv->manager=NULL; | ||
1504 | 591 | } | ||
1505 | 592 | |||
1506 | 593 | if(priv->browser) | ||
1507 | 594 | { | ||
1508 | 595 | g_object_unref(priv->browser); | ||
1509 | 596 | priv->browser=NULL; | ||
1510 | 597 | } | ||
1511 | 598 | |||
1512 | 599 | if(priv->view) | ||
1513 | 600 | { | ||
1514 | 601 | _nojs_view_on_view_changed(self, NULL); | ||
1515 | 602 | } | ||
1516 | 603 | |||
1517 | 604 | if(priv->menu) | ||
1518 | 605 | { | ||
1519 | 606 | gtk_widget_destroy(priv->menu); | ||
1520 | 607 | priv->menu=NULL; | ||
1521 | 608 | } | ||
1522 | 609 | |||
1523 | 610 | if(priv->resourceURIs) | ||
1524 | 611 | { | ||
1525 | 612 | g_slist_free_full(priv->resourceURIs, (GDestroyNotify)g_free); | ||
1526 | 613 | priv->resourceURIs=NULL; | ||
1527 | 614 | } | ||
1528 | 615 | |||
1529 | 616 | /* Call parent's class finalize method */ | ||
1530 | 617 | G_OBJECT_CLASS(nojs_view_parent_class)->finalize(inObject); | ||
1531 | 618 | } | ||
1532 | 619 | |||
1533 | 620 | /* Set/get properties */ | ||
1534 | 621 | static void nojs_view_set_property(GObject *inObject, | ||
1535 | 622 | guint inPropID, | ||
1536 | 623 | const GValue *inValue, | ||
1537 | 624 | GParamSpec *inSpec) | ||
1538 | 625 | { | ||
1539 | 626 | NoJSView *self=NOJS_VIEW(inObject); | ||
1540 | 627 | |||
1541 | 628 | switch(inPropID) | ||
1542 | 629 | { | ||
1543 | 630 | /* Construct-only properties */ | ||
1544 | 631 | case PROP_MANAGER: | ||
1545 | 632 | _nojs_view_on_manager_changed(self, NOJS(g_value_get_object(inValue))); | ||
1546 | 633 | break; | ||
1547 | 634 | |||
1548 | 635 | case PROP_BROWSER: | ||
1549 | 636 | if(self->priv->browser) g_object_unref(self->priv->browser); | ||
1550 | 637 | self->priv->browser=g_object_ref(g_value_get_object(inValue)); | ||
1551 | 638 | break; | ||
1552 | 639 | |||
1553 | 640 | case PROP_VIEW: | ||
1554 | 641 | _nojs_view_on_view_changed(self, MIDORI_VIEW(g_value_get_object(inValue))); | ||
1555 | 642 | break; | ||
1556 | 643 | |||
1557 | 644 | default: | ||
1558 | 645 | G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec); | ||
1559 | 646 | break; | ||
1560 | 647 | } | ||
1561 | 648 | } | ||
1562 | 649 | |||
1563 | 650 | static void nojs_view_get_property(GObject *inObject, | ||
1564 | 651 | guint inPropID, | ||
1565 | 652 | GValue *outValue, | ||
1566 | 653 | GParamSpec *inSpec) | ||
1567 | 654 | { | ||
1568 | 655 | NoJSView *self=NOJS_VIEW(inObject); | ||
1569 | 656 | |||
1570 | 657 | switch(inPropID) | ||
1571 | 658 | { | ||
1572 | 659 | case PROP_MANAGER: | ||
1573 | 660 | g_value_set_object(outValue, self->priv->manager); | ||
1574 | 661 | break; | ||
1575 | 662 | |||
1576 | 663 | case PROP_BROWSER: | ||
1577 | 664 | g_value_set_object(outValue, self->priv->browser); | ||
1578 | 665 | break; | ||
1579 | 666 | |||
1580 | 667 | case PROP_VIEW: | ||
1581 | 668 | g_value_set_object(outValue, self->priv->view); | ||
1582 | 669 | break; | ||
1583 | 670 | |||
1584 | 671 | case PROP_MENU_ICON_STATE: | ||
1585 | 672 | g_value_set_enum(outValue, self->priv->menuIconState); | ||
1586 | 673 | break; | ||
1587 | 674 | |||
1588 | 675 | default: | ||
1589 | 676 | G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec); | ||
1590 | 677 | break; | ||
1591 | 678 | } | ||
1592 | 679 | } | ||
1593 | 680 | |||
1594 | 681 | /* Class initialization | ||
1595 | 682 | * Override functions in parent classes and define properties and signals | ||
1596 | 683 | */ | ||
1597 | 684 | static void nojs_view_class_init(NoJSViewClass *klass) | ||
1598 | 685 | { | ||
1599 | 686 | GObjectClass *gobjectClass=G_OBJECT_CLASS(klass); | ||
1600 | 687 | |||
1601 | 688 | /* Override functions */ | ||
1602 | 689 | gobjectClass->finalize=nojs_view_finalize; | ||
1603 | 690 | gobjectClass->set_property=nojs_view_set_property; | ||
1604 | 691 | gobjectClass->get_property=nojs_view_get_property; | ||
1605 | 692 | |||
1606 | 693 | /* Set up private structure */ | ||
1607 | 694 | g_type_class_add_private(klass, sizeof(NoJSViewPrivate)); | ||
1608 | 695 | |||
1609 | 696 | /* Define properties */ | ||
1610 | 697 | NoJSViewProperties[PROP_MANAGER]= | ||
1611 | 698 | g_param_spec_object("manager", | ||
1612 | 699 | _("Manager instance"), | ||
1613 | 700 | _("Instance to global NoJS manager"), | ||
1614 | 701 | TYPE_NOJS, | ||
1615 | 702 | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); | ||
1616 | 703 | |||
1617 | 704 | NoJSViewProperties[PROP_BROWSER]= | ||
1618 | 705 | g_param_spec_object("browser", | ||
1619 | 706 | _("Browser window"), | ||
1620 | 707 | _("The Midori browser instance this view belongs to"), | ||
1621 | 708 | MIDORI_TYPE_BROWSER, | ||
1622 | 709 | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); | ||
1623 | 710 | |||
1624 | 711 | NoJSViewProperties[PROP_VIEW]= | ||
1625 | 712 | g_param_spec_object("view", | ||
1626 | 713 | _("View"), | ||
1627 | 714 | _("The Midori view instance this view belongs to"), | ||
1628 | 715 | MIDORI_TYPE_VIEW, | ||
1629 | 716 | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); | ||
1630 | 717 | |||
1631 | 718 | NoJSViewProperties[PROP_MENU_ICON_STATE]= | ||
1632 | 719 | g_param_spec_enum("menu-icon-state", | ||
1633 | 720 | _("Menu icon state"), | ||
1634 | 721 | _("State of menu icon to show in status bar"), | ||
1635 | 722 | NOJS_TYPE_MENU_ICON_STATE, | ||
1636 | 723 | NOJS_MENU_ICON_STATE_UNDETERMINED, | ||
1637 | 724 | G_PARAM_READABLE); | ||
1638 | 725 | |||
1639 | 726 | g_object_class_install_properties(gobjectClass, PROP_LAST, NoJSViewProperties); | ||
1640 | 727 | } | ||
1641 | 728 | |||
1642 | 729 | /* Object initialization | ||
1643 | 730 | * Create private structure and set up default values | ||
1644 | 731 | */ | ||
1645 | 732 | static void nojs_view_init(NoJSView *self) | ||
1646 | 733 | { | ||
1647 | 734 | NoJSViewPrivate *priv; | ||
1648 | 735 | |||
1649 | 736 | priv=self->priv=NOJS_VIEW_GET_PRIVATE(self); | ||
1650 | 737 | |||
1651 | 738 | /* Set up default values */ | ||
1652 | 739 | priv->manager=NULL; | ||
1653 | 740 | priv->browser=NULL; | ||
1654 | 741 | priv->view=NULL; | ||
1655 | 742 | |||
1656 | 743 | priv->menu=NULL; | ||
1657 | 744 | priv->menuPolicyWasChanged=FALSE; | ||
1658 | 745 | priv->menuIconState=NOJS_MENU_ICON_STATE_UNDETERMINED; | ||
1659 | 746 | |||
1660 | 747 | priv->resourceURIs=NULL; | ||
1661 | 748 | |||
1662 | 749 | /* Create empty menu */ | ||
1663 | 750 | _nojs_view_create_empty_menu(self); | ||
1664 | 751 | } | ||
1665 | 752 | |||
1666 | 753 | /* Implementation: Public API */ | ||
1667 | 754 | |||
1668 | 755 | /* Create new object */ | ||
1669 | 756 | NoJSView* nojs_view_new(NoJS *inNoJS, MidoriBrowser *inBrowser, MidoriView *inView) | ||
1670 | 757 | { | ||
1671 | 758 | return(g_object_new(TYPE_NOJS_VIEW, | ||
1672 | 759 | "manager", inNoJS, | ||
1673 | 760 | "browser", inBrowser, | ||
1674 | 761 | "view", inView, | ||
1675 | 762 | NULL)); | ||
1676 | 763 | } | ||
1677 | 764 | |||
1678 | 765 | /* Get menu widget for this view */ | ||
1679 | 766 | GtkMenu* nojs_view_get_menu(NoJSView *self) | ||
1680 | 767 | { | ||
1681 | 768 | g_return_val_if_fail(NOJS_IS_VIEW(self), NULL); | ||
1682 | 769 | |||
1683 | 770 | return(GTK_MENU(self->priv->menu)); | ||
1684 | 771 | } | ||
1685 | 772 | |||
1686 | 773 | /* Get image used for menu icon in status bar */ | ||
1687 | 774 | NoJSMenuIconState nojs_view_get_menu_icon_state(NoJSView *self) | ||
1688 | 775 | { | ||
1689 | 776 | g_return_val_if_fail(NOJS_IS_VIEW(self), NOJS_MENU_ICON_STATE_UNDETERMINED); | ||
1690 | 777 | |||
1691 | 778 | return(self->priv->menuIconState); | ||
1692 | 779 | } | ||
1693 | 780 | |||
1694 | 781 | /************************************************************************************/ | ||
1695 | 782 | |||
1696 | 783 | /* Implementation: Enumeration */ | ||
1697 | 784 | GType nojs_menu_icon_state_get_type(void) | ||
1698 | 785 | { | ||
1699 | 786 | static volatile gsize g_define_type_id__volatile=0; | ||
1700 | 787 | |||
1701 | 788 | if(g_once_init_enter(&g_define_type_id__volatile)) | ||
1702 | 789 | { | ||
1703 | 790 | static const GEnumValue values[]= | ||
1704 | 791 | { | ||
1705 | 792 | { NOJS_MENU_ICON_STATE_UNDETERMINED, "NOJS_MENU_ICON_STATE_UNDETERMINED", N_("Undetermined") }, | ||
1706 | 793 | { NOJS_MENU_ICON_STATE_ALLOWED, "NOJS_MENU_ICON_STATE_ALLOWED", N_("Allowed") }, | ||
1707 | 794 | { NOJS_MENU_ICON_STATE_MIXED, "NOJS_MENU_ICON_STATE_MIXED", N_("Mixed") }, | ||
1708 | 795 | { NOJS_MENU_ICON_STATE_DENIED, "NOJS_MENU_ICON_STATE_DENIED", N_("Denied") }, | ||
1709 | 796 | { 0, NULL, NULL } | ||
1710 | 797 | }; | ||
1711 | 798 | |||
1712 | 799 | GType g_define_type_id=g_enum_register_static(g_intern_static_string("NoJSMenuIconState"), values); | ||
1713 | 800 | g_once_init_leave(&g_define_type_id__volatile, g_define_type_id); | ||
1714 | 801 | } | ||
1715 | 802 | |||
1716 | 803 | return(g_define_type_id__volatile); | ||
1717 | 804 | } | ||
1718 | 0 | 805 | ||
1719 | === added file 'extensions/nojs/nojs-view.h' | |||
1720 | --- extensions/nojs/nojs-view.h 1970-01-01 00:00:00 +0000 | |||
1721 | +++ extensions/nojs/nojs-view.h 2013-07-29 19:51:25 +0000 | |||
1722 | @@ -0,0 +1,71 @@ | |||
1723 | 1 | /* | ||
1724 | 2 | Copyright (C) 2013 Stephan Haller <nomad@froevel.de> | ||
1725 | 3 | |||
1726 | 4 | This library is free software; you can redistribute it and/or | ||
1727 | 5 | modify it under the terms of the GNU Lesser General Public | ||
1728 | 6 | License as published by the Free Software Foundation; either | ||
1729 | 7 | version 2.1 of the License, or (at your option) any later version. | ||
1730 | 8 | |||
1731 | 9 | See the file COPYING for the full license text. | ||
1732 | 10 | */ | ||
1733 | 11 | |||
1734 | 12 | #ifndef __NOJS_VIEW__ | ||
1735 | 13 | #define __NOJS_VIEW__ | ||
1736 | 14 | |||
1737 | 15 | #include "config.h" | ||
1738 | 16 | #include "nojs.h" | ||
1739 | 17 | #include <midori/midori.h> | ||
1740 | 18 | |||
1741 | 19 | G_BEGIN_DECLS | ||
1742 | 20 | |||
1743 | 21 | /* NoJS view enums */ | ||
1744 | 22 | typedef enum | ||
1745 | 23 | { | ||
1746 | 24 | NOJS_MENU_ICON_STATE_UNDETERMINED, | ||
1747 | 25 | NOJS_MENU_ICON_STATE_ALLOWED, | ||
1748 | 26 | NOJS_MENU_ICON_STATE_MIXED, | ||
1749 | 27 | NOJS_MENU_ICON_STATE_DENIED | ||
1750 | 28 | } NoJSMenuIconState; | ||
1751 | 29 | |||
1752 | 30 | /* NoJS view object */ | ||
1753 | 31 | #define TYPE_NOJS_VIEW (nojs_view_get_type()) | ||
1754 | 32 | #define NOJS_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_NOJS_VIEW, NoJSView)) | ||
1755 | 33 | #define NOJS_IS_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_NOJS_VIEW)) | ||
1756 | 34 | #define NOJS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_NOJS_VIEW, NoJSViewClass)) | ||
1757 | 35 | #define NOJS_IS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_NOJS_VIEW)) | ||
1758 | 36 | #define NOJS_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_NOJS_VIEW, NoJSViewClass)) | ||
1759 | 37 | |||
1760 | 38 | typedef struct _NoJSView NoJSView; | ||
1761 | 39 | typedef struct _NoJSViewClass NoJSViewClass; | ||
1762 | 40 | typedef struct _NoJSViewPrivate NoJSViewPrivate; | ||
1763 | 41 | |||
1764 | 42 | struct _NoJSView | ||
1765 | 43 | { | ||
1766 | 44 | /* Parent instance */ | ||
1767 | 45 | GObject parent_instance; | ||
1768 | 46 | |||
1769 | 47 | /* Private structure */ | ||
1770 | 48 | NoJSViewPrivate *priv; | ||
1771 | 49 | }; | ||
1772 | 50 | |||
1773 | 51 | struct _NoJSViewClass | ||
1774 | 52 | { | ||
1775 | 53 | /* Parent class */ | ||
1776 | 54 | GObjectClass parent_class; | ||
1777 | 55 | }; | ||
1778 | 56 | |||
1779 | 57 | /* Public API */ | ||
1780 | 58 | GType nojs_view_get_type(void); | ||
1781 | 59 | |||
1782 | 60 | NoJSView* nojs_view_new(NoJS *inNoJS, MidoriBrowser *inBrowser, MidoriView *inView); | ||
1783 | 61 | |||
1784 | 62 | GtkMenu* nojs_view_get_menu(NoJSView *self); | ||
1785 | 63 | NoJSMenuIconState nojs_view_get_menu_icon_state(NoJSView *self); | ||
1786 | 64 | |||
1787 | 65 | /* Enumeration */ | ||
1788 | 66 | GType nojs_menu_icon_state_get_type(void) G_GNUC_CONST; | ||
1789 | 67 | #define NOJS_TYPE_MENU_ICON_STATE (nojs_menu_icon_state_get_type()) | ||
1790 | 68 | |||
1791 | 69 | G_END_DECLS | ||
1792 | 70 | |||
1793 | 71 | #endif /* __NOJS_VIEW__ */ | ||
1794 | 0 | 72 | ||
1795 | === added file 'extensions/nojs/nojs.c' | |||
1796 | --- extensions/nojs/nojs.c 1970-01-01 00:00:00 +0000 | |||
1797 | +++ extensions/nojs/nojs.c 2013-07-29 19:51:25 +0000 | |||
1798 | @@ -0,0 +1,1069 @@ | |||
1799 | 1 | /* | ||
1800 | 2 | Copyright (C) 2013 Stephan Haller <nomad@froevel.de> | ||
1801 | 3 | |||
1802 | 4 | This library is free software; you can redistribute it and/or | ||
1803 | 5 | modify it under the terms of the GNU Lesser General Public | ||
1804 | 6 | License as published by the Free Software Foundation; either | ||
1805 | 7 | version 2.1 of the License, or (at your option) any later version. | ||
1806 | 8 | |||
1807 | 9 | See the file COPYING for the full license text. | ||
1808 | 10 | */ | ||
1809 | 11 | |||
1810 | 12 | #include "nojs.h" | ||
1811 | 13 | #include "nojs-view.h" | ||
1812 | 14 | |||
1813 | 15 | #include <errno.h> | ||
1814 | 16 | |||
1815 | 17 | /* Define this class in GObject system */ | ||
1816 | 18 | G_DEFINE_TYPE(NoJS, | ||
1817 | 19 | nojs, | ||
1818 | 20 | G_TYPE_OBJECT) | ||
1819 | 21 | |||
1820 | 22 | /* Properties */ | ||
1821 | 23 | enum | ||
1822 | 24 | { | ||
1823 | 25 | PROP_0, | ||
1824 | 26 | |||
1825 | 27 | PROP_EXTENSION, | ||
1826 | 28 | PROP_APPLICATION, | ||
1827 | 29 | |||
1828 | 30 | PROP_DATABASE, | ||
1829 | 31 | PROP_DATABASE_FILENAME, | ||
1830 | 32 | PROP_ALLOW_ALL_SITES, | ||
1831 | 33 | PROP_ONLY_SECOND_LEVEL, | ||
1832 | 34 | PROP_UNKNOWN_DOMAIN_POLICY, | ||
1833 | 35 | |||
1834 | 36 | PROP_LAST | ||
1835 | 37 | }; | ||
1836 | 38 | |||
1837 | 39 | static GParamSpec* NoJSProperties[PROP_LAST]={ 0, }; | ||
1838 | 40 | |||
1839 | 41 | /* Signals */ | ||
1840 | 42 | enum | ||
1841 | 43 | { | ||
1842 | 44 | URI_LOAD_POLICY_STATUS, | ||
1843 | 45 | POLICY_CHANGED, | ||
1844 | 46 | |||
1845 | 47 | SIGNAL_LAST | ||
1846 | 48 | }; | ||
1847 | 49 | |||
1848 | 50 | static guint NoJSSignals[SIGNAL_LAST]={ 0, }; | ||
1849 | 51 | |||
1850 | 52 | /* Private structure - access only by public API if needed */ | ||
1851 | 53 | #define NOJS_GET_PRIVATE(obj) \ | ||
1852 | 54 | (G_TYPE_INSTANCE_GET_PRIVATE((obj), TYPE_NOJS, NoJSPrivate)) | ||
1853 | 55 | |||
1854 | 56 | struct _NoJSPrivate | ||
1855 | 57 | { | ||
1856 | 58 | /* Extension related */ | ||
1857 | 59 | MidoriExtension *extension; | ||
1858 | 60 | MidoriApp *application; | ||
1859 | 61 | sqlite3 *database; | ||
1860 | 62 | gchar *databaseFilename; | ||
1861 | 63 | gboolean allowAllSites; | ||
1862 | 64 | gboolean checkOnlySecondLevel; | ||
1863 | 65 | NoJSPolicy unknownDomainPolicy; | ||
1864 | 66 | |||
1865 | 67 | guint requestStartedSignalID; | ||
1866 | 68 | }; | ||
1867 | 69 | |||
1868 | 70 | /* Taken from http://www.w3.org/html/wg/drafts/html/master/scripting-1.html#scriptingLanguages | ||
1869 | 71 | * A list of javascript mime types | ||
1870 | 72 | */ | ||
1871 | 73 | static const gchar* javascriptTypes[]= { | ||
1872 | 74 | "application/ecmascript", | ||
1873 | 75 | "application/javascript", | ||
1874 | 76 | "application/x-ecmascript", | ||
1875 | 77 | "application/x-javascript", | ||
1876 | 78 | "text/ecmascript", | ||
1877 | 79 | "text/javascript", | ||
1878 | 80 | "text/javascript1.0", | ||
1879 | 81 | "text/javascript1.1", | ||
1880 | 82 | "text/javascript1.2", | ||
1881 | 83 | "text/javascript1.3", | ||
1882 | 84 | "text/javascript1.4", | ||
1883 | 85 | "text/javascript1.5", | ||
1884 | 86 | "text/jscript", | ||
1885 | 87 | "text/livescript", | ||
1886 | 88 | "text/x-ecmascript", | ||
1887 | 89 | "text/x-javascript", | ||
1888 | 90 | NULL | ||
1889 | 91 | }; | ||
1890 | 92 | |||
1891 | 93 | /* IMPLEMENTATION: Private variables and methods */ | ||
1892 | 94 | |||
1893 | 95 | /* Closure for: void (*closure)(NoJS *self, gchar *inURI, NoJSPolicy inPolicy) */ | ||
1894 | 96 | static void _nojs_closure_VOID__STRING_ENUM(GClosure *inClosure, | ||
1895 | 97 | GValue *ioReturnValue G_GNUC_UNUSED, | ||
1896 | 98 | guint inNumberValues, | ||
1897 | 99 | const GValue *inValues, | ||
1898 | 100 | gpointer inInvocationHint G_GNUC_UNUSED, | ||
1899 | 101 | gpointer inMarshalData) | ||
1900 | 102 | { | ||
1901 | 103 | typedef void (*GMarshalFunc_VOID__STRING_ENUM)(gpointer inObject, gpointer inArg1, gint inArg2, gpointer inUserData); | ||
1902 | 104 | |||
1903 | 105 | register GMarshalFunc_VOID__STRING_ENUM callback; | ||
1904 | 106 | register GCClosure *closure=(GCClosure*)inClosure; | ||
1905 | 107 | register gpointer object, userData; | ||
1906 | 108 | |||
1907 | 109 | g_return_if_fail(inNumberValues==3); | ||
1908 | 110 | |||
1909 | 111 | if(G_CCLOSURE_SWAP_DATA(inClosure)) | ||
1910 | 112 | { | ||
1911 | 113 | object=inClosure->data; | ||
1912 | 114 | userData=g_value_peek_pointer(inValues+0); | ||
1913 | 115 | } | ||
1914 | 116 | else | ||
1915 | 117 | { | ||
1916 | 118 | object=g_value_peek_pointer(inValues+0); | ||
1917 | 119 | userData=inClosure->data; | ||
1918 | 120 | } | ||
1919 | 121 | |||
1920 | 122 | callback=(GMarshalFunc_VOID__STRING_ENUM)(inMarshalData ? inMarshalData : closure->callback); | ||
1921 | 123 | |||
1922 | 124 | callback(object, | ||
1923 | 125 | (gchar*)g_value_get_string(inValues+1), | ||
1924 | 126 | g_value_get_enum(inValues+2), | ||
1925 | 127 | userData); | ||
1926 | 128 | } | ||
1927 | 129 | |||
1928 | 130 | /* Show common error dialog */ | ||
1929 | 131 | static void _nojs_error(NoJS *self, const gchar *inReason) | ||
1930 | 132 | { | ||
1931 | 133 | g_return_if_fail(IS_NOJS(self)); | ||
1932 | 134 | g_return_if_fail(inReason); | ||
1933 | 135 | |||
1934 | 136 | GtkWidget *dialog; | ||
1935 | 137 | |||
1936 | 138 | /* Show confirmation dialog for undetermined cookies */ | ||
1937 | 139 | dialog=gtk_message_dialog_new(NULL, | ||
1938 | 140 | GTK_DIALOG_MODAL, | ||
1939 | 141 | GTK_MESSAGE_ERROR, | ||
1940 | 142 | GTK_BUTTONS_OK, | ||
1941 | 143 | _("A fatal error occurred which prevents " | ||
1942 | 144 | "the NoJS extension to continue. " | ||
1943 | 145 | "You should disable it.")); | ||
1944 | 146 | |||
1945 | 147 | gtk_window_set_title(GTK_WINDOW(dialog), _("Error in NoJS extension")); | ||
1946 | 148 | gtk_window_set_icon_name(GTK_WINDOW (dialog), "midori"); | ||
1947 | 149 | |||
1948 | 150 | gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), | ||
1949 | 151 | "%s:\n%s", | ||
1950 | 152 | _("Reason"), | ||
1951 | 153 | inReason); | ||
1952 | 154 | |||
1953 | 155 | gtk_dialog_run(GTK_DIALOG(dialog)); | ||
1954 | 156 | |||
1955 | 157 | /* Free up allocated resources */ | ||
1956 | 158 | gtk_widget_destroy(dialog); | ||
1957 | 159 | } | ||
1958 | 160 | |||
1959 | 161 | /* Open database containing policies for javascript sites. | ||
1960 | 162 | * Create database and setup table structure if it does not exist yet. | ||
1961 | 163 | */ | ||
1962 | 164 | static void _nojs_open_database(NoJS *self) | ||
1963 | 165 | { | ||
1964 | 166 | g_return_if_fail(IS_NOJS(self)); | ||
1965 | 167 | |||
1966 | 168 | NoJSPrivate *priv=self->priv; | ||
1967 | 169 | const gchar *configDir; | ||
1968 | 170 | gchar *sql; | ||
1969 | 171 | gchar *error=NULL; | ||
1970 | 172 | gint success; | ||
1971 | 173 | |||
1972 | 174 | /* Close any open database */ | ||
1973 | 175 | if(priv->database) | ||
1974 | 176 | { | ||
1975 | 177 | priv->databaseFilename=NULL; | ||
1976 | 178 | |||
1977 | 179 | sqlite3_close(priv->database); | ||
1978 | 180 | priv->database=NULL; | ||
1979 | 181 | |||
1980 | 182 | g_object_notify_by_pspec(G_OBJECT(self), NoJSProperties[PROP_DATABASE]); | ||
1981 | 183 | g_object_notify_by_pspec(G_OBJECT(self), NoJSProperties[PROP_DATABASE_FILENAME]); | ||
1982 | 184 | } | ||
1983 | 185 | |||
1984 | 186 | /* Build path to database file */ | ||
1985 | 187 | configDir=midori_extension_get_config_dir(priv->extension); | ||
1986 | 188 | if(!configDir) | ||
1987 | 189 | { | ||
1988 | 190 | g_warning(_("Could not get path to configuration of extension: path is NULL")); | ||
1989 | 191 | |||
1990 | 192 | _nojs_error(self, _("Could not get path to configuration of extension.")); | ||
1991 | 193 | return; | ||
1992 | 194 | } | ||
1993 | 195 | |||
1994 | 196 | if(katze_mkdir_with_parents(configDir, 0700)) | ||
1995 | 197 | { | ||
1996 | 198 | g_warning(_("Could not create configuration folder for extension: %s"), g_strerror(errno)); | ||
1997 | 199 | |||
1998 | 200 | _nojs_error(self, _("Could not create configuration folder for extension.")); | ||
1999 | 201 | return; | ||
2000 | 202 | } | ||
2001 | 203 | |||
2002 | 204 | /* Open database */ | ||
2003 | 205 | priv->databaseFilename=g_build_filename(configDir, NOJS_DATABASE, NULL); | ||
2004 | 206 | success=sqlite3_open(priv->databaseFilename, &priv->database); | ||
2005 | 207 | if(success!=SQLITE_OK) | ||
2006 | 208 | { | ||
2007 | 209 | g_warning(_("Could not open database of extension: %s"), sqlite3_errmsg(priv->database)); | ||
2008 | 210 | |||
2009 | 211 | g_free(priv->databaseFilename); | ||
2010 | 212 | priv->databaseFilename=NULL; | ||
2011 | 213 | |||
2012 | 214 | if(priv->database) sqlite3_close(priv->database); | ||
2013 | 215 | priv->database=NULL; | ||
2014 | 216 | |||
2015 | 217 | _nojs_error(self, _("Could not open database of extension.")); | ||
2016 | 218 | return; | ||
2017 | 219 | } | ||
2018 | 220 | |||
2019 | 221 | /* Create table structure if it does not exist */ | ||
2020 | 222 | success=sqlite3_exec(priv->database, | ||
2021 | 223 | "CREATE TABLE IF NOT EXISTS " | ||
2022 | 224 | "policies(site text, value integer);", | ||
2023 | 225 | NULL, | ||
2024 | 226 | NULL, | ||
2025 | 227 | &error); | ||
2026 | 228 | |||
2027 | 229 | if(success==SQLITE_OK) | ||
2028 | 230 | { | ||
2029 | 231 | success=sqlite3_exec(priv->database, | ||
2030 | 232 | "CREATE UNIQUE INDEX IF NOT EXISTS " | ||
2031 | 233 | "site ON policies (site);", | ||
2032 | 234 | NULL, | ||
2033 | 235 | NULL, | ||
2034 | 236 | &error); | ||
2035 | 237 | } | ||
2036 | 238 | |||
2037 | 239 | if(success==SQLITE_OK) | ||
2038 | 240 | { | ||
2039 | 241 | success=sqlite3_exec(priv->database, | ||
2040 | 242 | "PRAGMA journal_mode=TRUNCATE;", | ||
2041 | 243 | NULL, | ||
2042 | 244 | NULL, | ||
2043 | 245 | &error); | ||
2044 | 246 | } | ||
2045 | 247 | |||
2046 | 248 | if(success!=SQLITE_OK || error) | ||
2047 | 249 | { | ||
2048 | 250 | _nojs_error(self, _("Could not set up database structure of extension.")); | ||
2049 | 251 | |||
2050 | 252 | if(error) | ||
2051 | 253 | { | ||
2052 | 254 | g_critical(_("Failed to execute database statement: %s"), error); | ||
2053 | 255 | sqlite3_free(error); | ||
2054 | 256 | } | ||
2055 | 257 | |||
2056 | 258 | g_free(priv->databaseFilename); | ||
2057 | 259 | priv->databaseFilename=NULL; | ||
2058 | 260 | |||
2059 | 261 | sqlite3_close(priv->database); | ||
2060 | 262 | priv->database=NULL; | ||
2061 | 263 | return; | ||
2062 | 264 | } | ||
2063 | 265 | |||
2064 | 266 | /* Delete all temporarily allowed sites */ | ||
2065 | 267 | sql=sqlite3_mprintf("DELETE FROM policies WHERE value=%d;", NOJS_POLICY_ACCEPT_TEMPORARILY); | ||
2066 | 268 | success=sqlite3_exec(priv->database, sql, NULL, NULL, &error); | ||
2067 | 269 | if(success!=SQLITE_OK) g_warning(_("SQL fails: %s"), error); | ||
2068 | 270 | if(error) sqlite3_free(error); | ||
2069 | 271 | sqlite3_free(sql); | ||
2070 | 272 | |||
2071 | 273 | g_object_notify_by_pspec(G_OBJECT(self), NoJSProperties[PROP_DATABASE]); | ||
2072 | 274 | g_object_notify_by_pspec(G_OBJECT(self), NoJSProperties[PROP_DATABASE_FILENAME]); | ||
2073 | 275 | } | ||
2074 | 276 | |||
2075 | 277 | /* A request through libsoup is going to start and http headers must be | ||
2076 | 278 | * checked for content type | ||
2077 | 279 | */ | ||
2078 | 280 | static void _nojs_on_got_headers(NoJS *self, gpointer inUserData) | ||
2079 | 281 | { | ||
2080 | 282 | g_return_if_fail(IS_NOJS(self)); | ||
2081 | 283 | g_return_if_fail(SOUP_IS_MESSAGE(inUserData)); | ||
2082 | 284 | |||
2083 | 285 | NoJSPrivate *priv=self->priv; | ||
2084 | 286 | SoupMessage *message=SOUP_MESSAGE(inUserData); | ||
2085 | 287 | SoupSession *session=webkit_get_default_session(); | ||
2086 | 288 | SoupMessageHeaders *headers; | ||
2087 | 289 | SoupMessageBody *body; | ||
2088 | 290 | const gchar *contentType; | ||
2089 | 291 | SoupURI *uri; | ||
2090 | 292 | gchar *uriText; | ||
2091 | 293 | gchar *domain; | ||
2092 | 294 | NoJSPolicy policy; | ||
2093 | 295 | gboolean isJS; | ||
2094 | 296 | const gchar **iter; | ||
2095 | 297 | |||
2096 | 298 | /* Get headers from message to retrieve content type */ | ||
2097 | 299 | g_object_get(message, "response-headers", &headers, NULL); | ||
2098 | 300 | if(!headers) | ||
2099 | 301 | { | ||
2100 | 302 | g_warning("Could not get headers from message to check for javascript."); | ||
2101 | 303 | return; | ||
2102 | 304 | } | ||
2103 | 305 | |||
2104 | 306 | /* Get content type of uri and check if it is a javascript resource */ | ||
2105 | 307 | contentType=soup_message_headers_get_content_type(headers, NULL); | ||
2106 | 308 | |||
2107 | 309 | isJS=FALSE; | ||
2108 | 310 | iter=javascriptTypes; | ||
2109 | 311 | while(*iter && !isJS) | ||
2110 | 312 | { | ||
2111 | 313 | isJS=(g_strcmp0(contentType, *iter)==0); | ||
2112 | 314 | iter++; | ||
2113 | 315 | } | ||
2114 | 316 | |||
2115 | 317 | if(!isJS) return; | ||
2116 | 318 | |||
2117 | 319 | /* The document being loaded is javascript so get URI from message, | ||
2118 | 320 | * get policy for domain of URI and emit signal | ||
2119 | 321 | */ | ||
2120 | 322 | uri=soup_message_get_uri(message); | ||
2121 | 323 | |||
2122 | 324 | domain=nojs_get_domain(self, uri); | ||
2123 | 325 | g_return_if_fail(domain); | ||
2124 | 326 | |||
2125 | 327 | policy=nojs_get_policy(self, domain); | ||
2126 | 328 | if(policy==NOJS_POLICY_UNDETERMINED) | ||
2127 | 329 | { | ||
2128 | 330 | g_warning("Got invalid policy. Using default policy for unknown domains."); | ||
2129 | 331 | policy=priv->unknownDomainPolicy; | ||
2130 | 332 | } | ||
2131 | 333 | |||
2132 | 334 | uriText=soup_uri_to_string(uri, FALSE); | ||
2133 | 335 | |||
2134 | 336 | g_signal_emit(self, NoJSSignals[URI_LOAD_POLICY_STATUS], 0, uriText, policy==NOJS_POLICY_UNDETERMINED ? NOJS_POLICY_BLOCK : policy); | ||
2135 | 337 | |||
2136 | 338 | g_free(uriText); | ||
2137 | 339 | g_free(domain); | ||
2138 | 340 | |||
2139 | 341 | /* Return here if policy is any type of accept */ | ||
2140 | 342 | if(policy!=NOJS_POLICY_UNDETERMINED && policy!=NOJS_POLICY_BLOCK) return; | ||
2141 | 343 | |||
2142 | 344 | /* Cancel this message */ | ||
2143 | 345 | soup_session_cancel_message(session, message, SOUP_STATUS_CANCELLED); | ||
2144 | 346 | |||
2145 | 347 | /* Discard any load data */ | ||
2146 | 348 | g_object_get(message, "response-body", &body, NULL); | ||
2147 | 349 | if(body) soup_message_body_truncate(body); | ||
2148 | 350 | } | ||
2149 | 351 | |||
2150 | 352 | static void _nojs_on_request_started(NoJS *self, | ||
2151 | 353 | SoupMessage *inMessage, | ||
2152 | 354 | SoupSocket *inSocket, | ||
2153 | 355 | gpointer inUserData) | ||
2154 | 356 | { | ||
2155 | 357 | g_return_if_fail(IS_NOJS(self)); | ||
2156 | 358 | g_return_if_fail(SOUP_IS_MESSAGE(inMessage)); | ||
2157 | 359 | |||
2158 | 360 | /* Connect to "got-headers" to cancel loading javascript documents early */ | ||
2159 | 361 | g_signal_connect_swapped(inMessage, "got-headers", G_CALLBACK(_nojs_on_got_headers), self); | ||
2160 | 362 | } | ||
2161 | 363 | |||
2162 | 364 | /* The icon in statusbar was clicked */ | ||
2163 | 365 | static void _nojs_on_statusbar_icon_clicked(MidoriBrowser *inBrowser, gpointer inUserData) | ||
2164 | 366 | { | ||
2165 | 367 | g_return_if_fail(MIDORI_IS_BROWSER(inBrowser)); | ||
2166 | 368 | |||
2167 | 369 | MidoriView *activeView; | ||
2168 | 370 | NoJSView *view; | ||
2169 | 371 | GtkMenu *menu; | ||
2170 | 372 | |||
2171 | 373 | /* Get current active midori view */ | ||
2172 | 374 | activeView=MIDORI_VIEW(midori_browser_get_current_tab(inBrowser)); | ||
2173 | 375 | g_return_if_fail(MIDORI_IS_VIEW(activeView)); | ||
2174 | 376 | |||
2175 | 377 | /* Get NoJS view of current active midori view */ | ||
2176 | 378 | view=NOJS_VIEW(g_object_get_data(G_OBJECT(activeView), "nojs-view-instance")); | ||
2177 | 379 | g_return_if_fail(NOJS_IS_VIEW(view)); | ||
2178 | 380 | |||
2179 | 381 | /* Get menu of current view */ | ||
2180 | 382 | menu=nojs_view_get_menu(view); | ||
2181 | 383 | g_return_if_fail(menu); | ||
2182 | 384 | |||
2183 | 385 | /* Show menu */ | ||
2184 | 386 | gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time()); | ||
2185 | 387 | } | ||
2186 | 388 | |||
2187 | 389 | gchar* nojs_get_icon_path (const gchar* icon) | ||
2188 | 390 | { | ||
2189 | 391 | gchar* res_dir = midori_paths_get_res_filename (""); | ||
2190 | 392 | return g_build_filename (res_dir, "nojs", icon, NULL); | ||
2191 | 393 | } | ||
2192 | 394 | |||
2193 | 395 | /* Menu icon of a view has changed */ | ||
2194 | 396 | static void _nojs_on_menu_icon_changed(MidoriBrowser *inBrowser, GParamSpec *inSpec, gpointer inUserData) | ||
2195 | 397 | { | ||
2196 | 398 | g_return_if_fail(MIDORI_IS_BROWSER(inBrowser)); | ||
2197 | 399 | g_return_if_fail(NOJS_IS_VIEW(inUserData)); | ||
2198 | 400 | |||
2199 | 401 | NoJSView *view=NOJS_VIEW(inUserData); | ||
2200 | 402 | NoJSMenuIconState menuIconState; | ||
2201 | 403 | GtkWidget *statusbarIcon; | ||
2202 | 404 | GtkWidget *buttonImage; | ||
2203 | 405 | gchar *imageFilename; | ||
2204 | 406 | |||
2205 | 407 | /* Get icon in status bar of this browser */ | ||
2206 | 408 | statusbarIcon=GTK_WIDGET(g_object_get_data(G_OBJECT(inBrowser), "nojs-statusicon")); | ||
2207 | 409 | g_return_if_fail(GTK_IS_WIDGET(statusbarIcon)); | ||
2208 | 410 | |||
2209 | 411 | /* Get menu icon state of view */ | ||
2210 | 412 | menuIconState=nojs_view_get_menu_icon_state(view); | ||
2211 | 413 | |||
2212 | 414 | /* Create image for statusbar button */ | ||
2213 | 415 | imageFilename=NULL; | ||
2214 | 416 | switch(menuIconState) | ||
2215 | 417 | { | ||
2216 | 418 | case NOJS_MENU_ICON_STATE_ALLOWED: | ||
2217 | 419 | imageFilename=nojs_get_icon_path("nojs-statusicon-allowed.png"); | ||
2218 | 420 | break; | ||
2219 | 421 | |||
2220 | 422 | case NOJS_MENU_ICON_STATE_MIXED: | ||
2221 | 423 | imageFilename=nojs_get_icon_path("nojs-statusicon-mixed.png"); | ||
2222 | 424 | break; | ||
2223 | 425 | |||
2224 | 426 | case NOJS_MENU_ICON_STATE_DENIED: | ||
2225 | 427 | case NOJS_MENU_ICON_STATE_UNDETERMINED: | ||
2226 | 428 | imageFilename=nojs_get_icon_path("nojs-statusicon-denied.png"); | ||
2227 | 429 | break; | ||
2228 | 430 | } | ||
2229 | 431 | |||
2230 | 432 | buttonImage=gtk_image_new_from_file(imageFilename); | ||
2231 | 433 | g_free(imageFilename); | ||
2232 | 434 | |||
2233 | 435 | /* Set image at statusbar button */ | ||
2234 | 436 | gtk_button_set_image(GTK_BUTTON(statusbarIcon), buttonImage); | ||
2235 | 437 | } | ||
2236 | 438 | |||
2237 | 439 | /* A tab in browser was activated */ | ||
2238 | 440 | static void _nojs_on_switch_tab(NoJS *self, MidoriView *inOldView, MidoriView *inNewView, gpointer inUserData) | ||
2239 | 441 | { | ||
2240 | 442 | g_return_if_fail(IS_NOJS(self)); | ||
2241 | 443 | g_return_if_fail(MIDORI_IS_BROWSER(inUserData)); | ||
2242 | 444 | |||
2243 | 445 | MidoriBrowser *browser=MIDORI_BROWSER(inUserData); | ||
2244 | 446 | NoJSView *view; | ||
2245 | 447 | |||
2246 | 448 | /* Disconnect signal handlers from old view */ | ||
2247 | 449 | if(inOldView) | ||
2248 | 450 | { | ||
2249 | 451 | /* Get NoJS view of old view */ | ||
2250 | 452 | view=(NoJSView*)g_object_get_data(G_OBJECT(inOldView), "nojs-view-instance"); | ||
2251 | 453 | g_return_if_fail(NOJS_IS_VIEW(view)); | ||
2252 | 454 | |||
2253 | 455 | /* Disconnect signal handlers */ | ||
2254 | 456 | g_signal_handlers_disconnect_by_func(view, G_CALLBACK(_nojs_on_menu_icon_changed), browser); | ||
2255 | 457 | } | ||
2256 | 458 | |||
2257 | 459 | /* Get NoJS view of new view */ | ||
2258 | 460 | view=(NoJSView*)g_object_get_data(G_OBJECT(inNewView), "nojs-view-instance"); | ||
2259 | 461 | g_return_if_fail(NOJS_IS_VIEW(view)); | ||
2260 | 462 | |||
2261 | 463 | /* Connect signals */ | ||
2262 | 464 | g_signal_connect_swapped(view, "notify::menu-icon-state", G_CALLBACK(_nojs_on_menu_icon_changed), browser); | ||
2263 | 465 | |||
2264 | 466 | /* Update menu icon*/ | ||
2265 | 467 | _nojs_on_menu_icon_changed(browser, NULL, view); | ||
2266 | 468 | } | ||
2267 | 469 | |||
2268 | 470 | /* A tab of a browser was removed */ | ||
2269 | 471 | static void _nojs_on_remove_tab(NoJS *self, MidoriView *inView, gpointer inUserData) | ||
2270 | 472 | { | ||
2271 | 473 | g_return_if_fail(IS_NOJS(self)); | ||
2272 | 474 | |||
2273 | 475 | NoJSView *view; | ||
2274 | 476 | |||
2275 | 477 | /* Get NoJS view of current active midori view */ | ||
2276 | 478 | view=NOJS_VIEW(g_object_get_data(G_OBJECT(inView), "nojs-view-instance")); | ||
2277 | 479 | g_return_if_fail(NOJS_IS_VIEW(view)); | ||
2278 | 480 | |||
2279 | 481 | g_object_unref(view); | ||
2280 | 482 | } | ||
2281 | 483 | |||
2282 | 484 | /* A tab of a browser was added */ | ||
2283 | 485 | static void _nojs_on_add_tab(NoJS *self, MidoriView *inView, gpointer inUserData) | ||
2284 | 486 | { | ||
2285 | 487 | g_return_if_fail(IS_NOJS(self)); | ||
2286 | 488 | g_return_if_fail(MIDORI_IS_BROWSER(inUserData)); | ||
2287 | 489 | |||
2288 | 490 | /* Create nojs view and add to tab */ | ||
2289 | 491 | MidoriBrowser *browser=MIDORI_BROWSER(inUserData); | ||
2290 | 492 | |||
2291 | 493 | nojs_view_new(self, browser, inView); | ||
2292 | 494 | } | ||
2293 | 495 | |||
2294 | 496 | /* A browser window was added */ | ||
2295 | 497 | static void _nojs_on_add_browser(NoJS *self, MidoriBrowser *inBrowser, gpointer inUserData) | ||
2296 | 498 | { | ||
2297 | 499 | g_return_if_fail(IS_NOJS(self)); | ||
2298 | 500 | g_return_if_fail(MIDORI_IS_BROWSER(inBrowser)); | ||
2299 | 501 | |||
2300 | 502 | GList *tabs, *iter; | ||
2301 | 503 | GtkWidget *statusbar; | ||
2302 | 504 | GtkWidget *statusbarIcon; | ||
2303 | 505 | MidoriView *view; | ||
2304 | 506 | NoJSView *nojsView; | ||
2305 | 507 | |||
2306 | 508 | /* Set up all current available tabs in browser */ | ||
2307 | 509 | tabs=midori_browser_get_tabs(inBrowser); | ||
2308 | 510 | for(iter=tabs; iter; iter=g_list_next(iter)) _nojs_on_add_tab(self, iter->data, inBrowser); | ||
2309 | 511 | g_list_free(tabs); | ||
2310 | 512 | |||
2311 | 513 | /* Add status bar icon to browser */ | ||
2312 | 514 | g_object_get(inBrowser, "statusbar", &statusbar, NULL); | ||
2313 | 515 | if(statusbar) | ||
2314 | 516 | { | ||
2315 | 517 | /* Create and set up status icon */ | ||
2316 | 518 | statusbarIcon=gtk_button_new(); | ||
2317 | 519 | gtk_button_set_relief(GTK_BUTTON(statusbarIcon), GTK_RELIEF_NONE); | ||
2318 | 520 | gtk_widget_show_all(statusbarIcon); | ||
2319 | 521 | gtk_box_pack_end(GTK_BOX(statusbar), statusbarIcon, FALSE, FALSE, 0); | ||
2320 | 522 | g_object_set_data_full(G_OBJECT(inBrowser), "nojs-statusicon", g_object_ref(statusbarIcon), (GDestroyNotify)gtk_widget_destroy); | ||
2321 | 523 | |||
2322 | 524 | /* Connect signals */ | ||
2323 | 525 | g_signal_connect_swapped(statusbarIcon, "clicked", G_CALLBACK(_nojs_on_statusbar_icon_clicked), inBrowser); | ||
2324 | 526 | |||
2325 | 527 | /* Release our reference to statusbar and status icon */ | ||
2326 | 528 | g_object_unref(statusbarIcon); | ||
2327 | 529 | g_object_unref(statusbar); | ||
2328 | 530 | |||
2329 | 531 | /* Update menu icon*/ | ||
2330 | 532 | view=MIDORI_VIEW(midori_browser_get_current_tab(inBrowser)); | ||
2331 | 533 | if(view) | ||
2332 | 534 | { | ||
2333 | 535 | nojsView=(NoJSView*)g_object_get_data(G_OBJECT(view), "nojs-view-instance"); | ||
2334 | 536 | if(nojsView) _nojs_on_menu_icon_changed(inBrowser, NULL, nojsView); | ||
2335 | 537 | } | ||
2336 | 538 | } | ||
2337 | 539 | |||
2338 | 540 | /* Listen to new tabs opened in browser */ | ||
2339 | 541 | g_signal_connect_swapped(inBrowser, "add-tab", G_CALLBACK(_nojs_on_add_tab), self); | ||
2340 | 542 | g_signal_connect_swapped(inBrowser, "switch-tab", G_CALLBACK(_nojs_on_switch_tab), self); | ||
2341 | 543 | g_signal_connect_swapped(inBrowser, "remove-tab", G_CALLBACK(_nojs_on_remove_tab), self); | ||
2342 | 544 | } | ||
2343 | 545 | |||
2344 | 546 | /* Application property has changed */ | ||
2345 | 547 | static void _nojs_on_application_changed(NoJS *self) | ||
2346 | 548 | { | ||
2347 | 549 | g_return_if_fail(IS_NOJS(self)); | ||
2348 | 550 | |||
2349 | 551 | NoJSPrivate *priv=NOJS(self)->priv; | ||
2350 | 552 | GList *browsers, *iter; | ||
2351 | 553 | |||
2352 | 554 | /* Set up all current open browser windows */ | ||
2353 | 555 | browsers=midori_app_get_browsers(priv->application); | ||
2354 | 556 | for(iter=browsers; iter; iter=g_list_next(iter)) _nojs_on_add_browser(self, MIDORI_BROWSER(iter->data), priv->application); | ||
2355 | 557 | g_list_free(browsers); | ||
2356 | 558 | |||
2357 | 559 | /* Listen to new browser windows opened */ | ||
2358 | 560 | g_signal_connect_swapped(priv->application, "add-browser", G_CALLBACK(_nojs_on_add_browser), self); | ||
2359 | 561 | |||
2360 | 562 | /* Notify about property change */ | ||
2361 | 563 | g_object_notify_by_pspec(G_OBJECT(self), NoJSProperties[PROP_APPLICATION]); | ||
2362 | 564 | } | ||
2363 | 565 | |||
2364 | 566 | /* IMPLEMENTATION: GObject */ | ||
2365 | 567 | |||
2366 | 568 | /* Finalize this object */ | ||
2367 | 569 | static void nojs_finalize(GObject *inObject) | ||
2368 | 570 | { | ||
2369 | 571 | NoJS *self=NOJS(inObject); | ||
2370 | 572 | NoJSPrivate *priv=self->priv; | ||
2371 | 573 | GList *browsers, *browser; | ||
2372 | 574 | GList *tabs, *tab; | ||
2373 | 575 | WebKitWebView *webkitView; | ||
2374 | 576 | SoupSession *session; | ||
2375 | 577 | |||
2376 | 578 | /* Dispose allocated resources */ | ||
2377 | 579 | session=webkit_get_default_session(); | ||
2378 | 580 | g_signal_handlers_disconnect_by_data(session, self); | ||
2379 | 581 | |||
2380 | 582 | if(priv->databaseFilename) | ||
2381 | 583 | { | ||
2382 | 584 | g_free(priv->databaseFilename); | ||
2383 | 585 | priv->databaseFilename=NULL; | ||
2384 | 586 | } | ||
2385 | 587 | |||
2386 | 588 | if(priv->database) | ||
2387 | 589 | { | ||
2388 | 590 | sqlite3_close(priv->database); | ||
2389 | 591 | priv->database=NULL; | ||
2390 | 592 | } | ||
2391 | 593 | |||
2392 | 594 | if(priv->application) | ||
2393 | 595 | { | ||
2394 | 596 | g_signal_handlers_disconnect_by_data(priv->application, self); | ||
2395 | 597 | |||
2396 | 598 | browsers=midori_app_get_browsers(priv->application); | ||
2397 | 599 | for(browser=browsers; browser; browser=g_list_next(browser)) | ||
2398 | 600 | { | ||
2399 | 601 | g_signal_handlers_disconnect_by_data(browser->data, self); | ||
2400 | 602 | g_object_set_data(G_OBJECT(browser->data), "nojs-statusicon", NULL); | ||
2401 | 603 | |||
2402 | 604 | tabs=midori_browser_get_tabs(MIDORI_BROWSER(browser->data)); | ||
2403 | 605 | for(tab=tabs; tab; tab=g_list_next(tab)) | ||
2404 | 606 | { | ||
2405 | 607 | g_signal_handlers_disconnect_by_data(tab->data, self); | ||
2406 | 608 | |||
2407 | 609 | webkitView=WEBKIT_WEB_VIEW(midori_view_get_web_view(MIDORI_VIEW(tab->data))); | ||
2408 | 610 | g_signal_handlers_disconnect_by_data(webkitView, self); | ||
2409 | 611 | } | ||
2410 | 612 | g_list_free(tabs); | ||
2411 | 613 | } | ||
2412 | 614 | g_list_free(browsers); | ||
2413 | 615 | |||
2414 | 616 | priv->application=NULL; | ||
2415 | 617 | } | ||
2416 | 618 | |||
2417 | 619 | /* Call parent's class finalize method */ | ||
2418 | 620 | G_OBJECT_CLASS(nojs_parent_class)->finalize(inObject); | ||
2419 | 621 | } | ||
2420 | 622 | |||
2421 | 623 | /* Set/get properties */ | ||
2422 | 624 | static void nojs_set_property(GObject *inObject, | ||
2423 | 625 | guint inPropID, | ||
2424 | 626 | const GValue *inValue, | ||
2425 | 627 | GParamSpec *inSpec) | ||
2426 | 628 | { | ||
2427 | 629 | NoJS *self=NOJS(inObject); | ||
2428 | 630 | |||
2429 | 631 | switch(inPropID) | ||
2430 | 632 | { | ||
2431 | 633 | /* Construct-only properties */ | ||
2432 | 634 | case PROP_EXTENSION: | ||
2433 | 635 | self->priv->extension=g_value_get_object(inValue); | ||
2434 | 636 | _nojs_open_database(self); | ||
2435 | 637 | break; | ||
2436 | 638 | |||
2437 | 639 | case PROP_APPLICATION: | ||
2438 | 640 | self->priv->application=g_value_get_object(inValue); | ||
2439 | 641 | _nojs_on_application_changed(self); | ||
2440 | 642 | break; | ||
2441 | 643 | |||
2442 | 644 | case PROP_ALLOW_ALL_SITES: | ||
2443 | 645 | self->priv->allowAllSites=g_value_get_boolean(inValue); | ||
2444 | 646 | g_object_notify_by_pspec(G_OBJECT(self), NoJSProperties[PROP_ALLOW_ALL_SITES]); | ||
2445 | 647 | break; | ||
2446 | 648 | |||
2447 | 649 | case PROP_ONLY_SECOND_LEVEL: | ||
2448 | 650 | self->priv->checkOnlySecondLevel=g_value_get_boolean(inValue); | ||
2449 | 651 | g_object_notify_by_pspec(G_OBJECT(self), NoJSProperties[PROP_ONLY_SECOND_LEVEL]); | ||
2450 | 652 | break; | ||
2451 | 653 | |||
2452 | 654 | case PROP_UNKNOWN_DOMAIN_POLICY: | ||
2453 | 655 | self->priv->unknownDomainPolicy=g_value_get_enum(inValue); | ||
2454 | 656 | g_object_notify_by_pspec(G_OBJECT(self), NoJSProperties[PROP_UNKNOWN_DOMAIN_POLICY]); | ||
2455 | 657 | break; | ||
2456 | 658 | |||
2457 | 659 | default: | ||
2458 | 660 | G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec); | ||
2459 | 661 | break; | ||
2460 | 662 | } | ||
2461 | 663 | } | ||
2462 | 664 | |||
2463 | 665 | static void nojs_get_property(GObject *inObject, | ||
2464 | 666 | guint inPropID, | ||
2465 | 667 | GValue *outValue, | ||
2466 | 668 | GParamSpec *inSpec) | ||
2467 | 669 | { | ||
2468 | 670 | NoJS *self=NOJS(inObject); | ||
2469 | 671 | |||
2470 | 672 | switch(inPropID) | ||
2471 | 673 | { | ||
2472 | 674 | case PROP_EXTENSION: | ||
2473 | 675 | g_value_set_object(outValue, self->priv->extension); | ||
2474 | 676 | break; | ||
2475 | 677 | |||
2476 | 678 | case PROP_APPLICATION: | ||
2477 | 679 | g_value_set_object(outValue, self->priv->application); | ||
2478 | 680 | break; | ||
2479 | 681 | |||
2480 | 682 | case PROP_DATABASE: | ||
2481 | 683 | g_value_set_pointer(outValue, self->priv->database); | ||
2482 | 684 | break; | ||
2483 | 685 | |||
2484 | 686 | case PROP_DATABASE_FILENAME: | ||
2485 | 687 | g_value_set_string(outValue, self->priv->databaseFilename); | ||
2486 | 688 | break; | ||
2487 | 689 | |||
2488 | 690 | case PROP_ALLOW_ALL_SITES: | ||
2489 | 691 | g_value_set_boolean(outValue, self->priv->allowAllSites); | ||
2490 | 692 | break; | ||
2491 | 693 | |||
2492 | 694 | case PROP_ONLY_SECOND_LEVEL: | ||
2493 | 695 | g_value_set_boolean(outValue, self->priv->checkOnlySecondLevel); | ||
2494 | 696 | break; | ||
2495 | 697 | |||
2496 | 698 | case PROP_UNKNOWN_DOMAIN_POLICY: | ||
2497 | 699 | g_value_set_enum(outValue, self->priv->unknownDomainPolicy); | ||
2498 | 700 | break; | ||
2499 | 701 | |||
2500 | 702 | default: | ||
2501 | 703 | G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec); | ||
2502 | 704 | break; | ||
2503 | 705 | } | ||
2504 | 706 | } | ||
2505 | 707 | |||
2506 | 708 | /* Class initialization | ||
2507 | 709 | * Override functions in parent classes and define properties and signals | ||
2508 | 710 | */ | ||
2509 | 711 | static void nojs_class_init(NoJSClass *klass) | ||
2510 | 712 | { | ||
2511 | 713 | GObjectClass *gobjectClass=G_OBJECT_CLASS(klass); | ||
2512 | 714 | |||
2513 | 715 | /* Override functions */ | ||
2514 | 716 | gobjectClass->finalize=nojs_finalize; | ||
2515 | 717 | gobjectClass->set_property=nojs_set_property; | ||
2516 | 718 | gobjectClass->get_property=nojs_get_property; | ||
2517 | 719 | |||
2518 | 720 | /* Set up private structure */ | ||
2519 | 721 | g_type_class_add_private(klass, sizeof(NoJSPrivate)); | ||
2520 | 722 | |||
2521 | 723 | /* Define properties */ | ||
2522 | 724 | NoJSProperties[PROP_EXTENSION]= | ||
2523 | 725 | g_param_spec_object("extension", | ||
2524 | 726 | _("Extension instance"), | ||
2525 | 727 | _("The Midori extension instance for this extension"), | ||
2526 | 728 | MIDORI_TYPE_EXTENSION, | ||
2527 | 729 | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); | ||
2528 | 730 | |||
2529 | 731 | NoJSProperties[PROP_APPLICATION]= | ||
2530 | 732 | g_param_spec_object("application", | ||
2531 | 733 | _("Application instance"), | ||
2532 | 734 | _("The Midori application instance this extension belongs to"), | ||
2533 | 735 | MIDORI_TYPE_APP, | ||
2534 | 736 | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); | ||
2535 | 737 | |||
2536 | 738 | NoJSProperties[PROP_DATABASE]= | ||
2537 | 739 | g_param_spec_pointer("database", | ||
2538 | 740 | _("Database instance"), | ||
2539 | 741 | _("Pointer to sqlite database instance used by this extension"), | ||
2540 | 742 | G_PARAM_READABLE); | ||
2541 | 743 | |||
2542 | 744 | NoJSProperties[PROP_DATABASE_FILENAME]= | ||
2543 | 745 | g_param_spec_string("database-filename", | ||
2544 | 746 | _("Database path"), | ||
2545 | 747 | _("Path to sqlite database instance used by this extension"), | ||
2546 | 748 | NULL, | ||
2547 | 749 | G_PARAM_READABLE); | ||
2548 | 750 | |||
2549 | 751 | NoJSProperties[PROP_ALLOW_ALL_SITES]= | ||
2550 | 752 | g_param_spec_boolean("allow-all-sites", | ||
2551 | 753 | _("Allow all sites"), | ||
2552 | 754 | _("If true this extension will not check policy for each site but allow them."), | ||
2553 | 755 | FALSE, | ||
2554 | 756 | G_PARAM_READWRITE | G_PARAM_CONSTRUCT); | ||
2555 | 757 | |||
2556 | 758 | NoJSProperties[PROP_ONLY_SECOND_LEVEL]= | ||
2557 | 759 | g_param_spec_boolean("only-second-level", | ||
2558 | 760 | _("Only second level"), | ||
2559 | 761 | _("If true this extension will reduce each domain to its second-level (www.example.org will reduced to example.org)"), | ||
2560 | 762 | TRUE, | ||
2561 | 763 | G_PARAM_READWRITE | G_PARAM_CONSTRUCT); | ||
2562 | 764 | |||
2563 | 765 | NoJSProperties[PROP_UNKNOWN_DOMAIN_POLICY]= | ||
2564 | 766 | g_param_spec_enum("unknown-domain-policy", | ||
2565 | 767 | _("Unknown domain policy"), | ||
2566 | 768 | _("Policy to use for unknown domains."), | ||
2567 | 769 | NOJS_TYPE_POLICY, | ||
2568 | 770 | NOJS_POLICY_BLOCK, | ||
2569 | 771 | G_PARAM_READWRITE | G_PARAM_CONSTRUCT); | ||
2570 | 772 | |||
2571 | 773 | g_object_class_install_properties(gobjectClass, PROP_LAST, NoJSProperties); | ||
2572 | 774 | |||
2573 | 775 | /* Define signals */ | ||
2574 | 776 | |||
2575 | 777 | /* Why does this signal exist? | ||
2576 | 778 | * | ||
2577 | 779 | * The problem I faced when developing this extension was | ||
2578 | 780 | * that I needed to cancel a SoupMessage as soon as possible | ||
2579 | 781 | * (when http headers were received). | ||
2580 | 782 | * I tried to connect to signal "resource-response-received" | ||
2581 | 783 | * of WebKitWebView but the SoupMessage instance was not | ||
2582 | 784 | * exactly the same which were sent or received by SoupSession. | ||
2583 | 785 | * So I could not cancel the SoupMessage or better: I cancelled | ||
2584 | 786 | * a SoupMessage which is not be handled so it had no effect. | ||
2585 | 787 | * The body of SoupMessage was still being loaded and javascript | ||
2586 | 788 | * was executed. I think the problem is that webkit-gtk creates | ||
2587 | 789 | * a copy of the real SoupMessage which is going to be sent and | ||
2588 | 790 | * received. | ||
2589 | 791 | * | ||
2590 | 792 | * So I decided to connect to signal "got-headers" of every | ||
2591 | 793 | * SoupMessage sent by the default SoupSession which I notice | ||
2592 | 794 | * by connecting to signal "request-started" of SoupSession. Each | ||
2593 | 795 | * NoJSView connects to signal "resource-request-starting" of | ||
2594 | 796 | * WebKitWebView to remember each URI going to be loaded. When | ||
2595 | 797 | * a SoupMessage hits "got-headers" and is a javascript resource | ||
2596 | 798 | * I can cancel the message immediately and clear the body which | ||
2597 | 799 | * causes webkit-gtk to copy a empty body if it does at all as the | ||
2598 | 800 | * SoupMessage was cancelled. Then I emit this signal | ||
2599 | 801 | * "uri-load-policy-status" to notify each view but the cancellation. | ||
2600 | 802 | * (It also notifies all views if it is going to load to keep the | ||
2601 | 803 | * menu in right state.) Each view will check if it _could_ be a | ||
2602 | 804 | * resource itself requested and will update its menu accordingly. | ||
2603 | 805 | * It might happen that a request will match two views because only | ||
2604 | 806 | * the URI will be checked by the view because I cannot determine | ||
2605 | 807 | * to which view the SoupMessage belongs to. But it doesn't matter | ||
2606 | 808 | * because if a javascript resource was denied or allowed in one view | ||
2607 | 809 | * it is likely be denied or allowed in other views too ;) | ||
2608 | 810 | */ | ||
2609 | 811 | NoJSSignals[URI_LOAD_POLICY_STATUS]= | ||
2610 | 812 | g_signal_new("uri-load-policy-status", | ||
2611 | 813 | G_TYPE_FROM_CLASS(klass), | ||
2612 | 814 | G_SIGNAL_RUN_LAST, | ||
2613 | 815 | G_STRUCT_OFFSET(NoJSClass, uri_load_policy_status), | ||
2614 | 816 | NULL, | ||
2615 | 817 | NULL, | ||
2616 | 818 | _nojs_closure_VOID__STRING_ENUM, | ||
2617 | 819 | G_TYPE_NONE, | ||
2618 | 820 | 2, | ||
2619 | 821 | G_TYPE_STRING, | ||
2620 | 822 | NOJS_TYPE_POLICY); | ||
2621 | 823 | |||
2622 | 824 | NoJSSignals[POLICY_CHANGED]= | ||
2623 | 825 | g_signal_new("policy-changed", | ||
2624 | 826 | G_TYPE_FROM_CLASS(klass), | ||
2625 | 827 | G_SIGNAL_RUN_LAST, | ||
2626 | 828 | G_STRUCT_OFFSET(NoJSClass, policy_changed), | ||
2627 | 829 | NULL, | ||
2628 | 830 | NULL, | ||
2629 | 831 | g_cclosure_marshal_VOID__STRING, | ||
2630 | 832 | G_TYPE_NONE, | ||
2631 | 833 | 1, | ||
2632 | 834 | G_TYPE_STRING); | ||
2633 | 835 | } | ||
2634 | 836 | |||
2635 | 837 | /* Object initialization | ||
2636 | 838 | * Create private structure and set up default values | ||
2637 | 839 | */ | ||
2638 | 840 | |||
2639 | 841 | static void nojs_init(NoJS *self) | ||
2640 | 842 | { | ||
2641 | 843 | NoJSPrivate *priv; | ||
2642 | 844 | SoupSession *session; | ||
2643 | 845 | |||
2644 | 846 | priv=self->priv=NOJS_GET_PRIVATE(self); | ||
2645 | 847 | |||
2646 | 848 | /* Set up default values */ | ||
2647 | 849 | priv->database=NULL; | ||
2648 | 850 | priv->databaseFilename=NULL; | ||
2649 | 851 | priv->allowAllSites=FALSE; | ||
2650 | 852 | priv->checkOnlySecondLevel=TRUE; | ||
2651 | 853 | priv->unknownDomainPolicy=NOJS_POLICY_BLOCK; | ||
2652 | 854 | |||
2653 | 855 | /* Connect to signals on session to be able to cancel messages | ||
2654 | 856 | * loading javascript documents | ||
2655 | 857 | */ | ||
2656 | 858 | session=webkit_get_default_session(); | ||
2657 | 859 | g_signal_connect_swapped(session, "request-started", G_CALLBACK(_nojs_on_request_started), self); | ||
2658 | 860 | } | ||
2659 | 861 | |||
2660 | 862 | /* Implementation: Public API */ | ||
2661 | 863 | |||
2662 | 864 | /* Create new object */ | ||
2663 | 865 | NoJS* nojs_new(MidoriExtension *inExtension, MidoriApp *inApp) | ||
2664 | 866 | { | ||
2665 | 867 | return(g_object_new(TYPE_NOJS, | ||
2666 | 868 | "extension", inExtension, | ||
2667 | 869 | "application", inApp, | ||
2668 | 870 | NULL)); | ||
2669 | 871 | } | ||
2670 | 872 | |||
2671 | 873 | /* Retrieves domain from uri depending on preferences (e.g. only second level domain) */ | ||
2672 | 874 | gchar* nojs_get_domain(NoJS *self, SoupURI *inURI) | ||
2673 | 875 | { | ||
2674 | 876 | g_return_val_if_fail(IS_NOJS(self), NULL); | ||
2675 | 877 | g_return_val_if_fail(inURI, NULL); | ||
2676 | 878 | |||
2677 | 879 | NoJSPrivate *priv=self->priv; | ||
2678 | 880 | const gchar *realDomain; | ||
2679 | 881 | gchar *asciiDomain, *domain; | ||
2680 | 882 | gchar *finalDomain; | ||
2681 | 883 | |||
2682 | 884 | /* Get domain of site to lookup */ | ||
2683 | 885 | realDomain=soup_uri_get_host(inURI); | ||
2684 | 886 | |||
2685 | 887 | domain=asciiDomain=g_hostname_to_ascii(realDomain); | ||
2686 | 888 | |||
2687 | 889 | if(priv->checkOnlySecondLevel) | ||
2688 | 890 | { | ||
2689 | 891 | /* Only get second level domain if host is not an IP address */ | ||
2690 | 892 | if(!g_hostname_is_ip_address(asciiDomain)) | ||
2691 | 893 | { | ||
2692 | 894 | gint numberDots=0; | ||
2693 | 895 | |||
2694 | 896 | domain=asciiDomain+strlen(asciiDomain)-1; | ||
2695 | 897 | while(domain>=asciiDomain && numberDots<2) | ||
2696 | 898 | { | ||
2697 | 899 | if(*domain=='.') numberDots++; | ||
2698 | 900 | domain--; | ||
2699 | 901 | } | ||
2700 | 902 | domain++; | ||
2701 | 903 | if(*domain=='.') domain++; | ||
2702 | 904 | } | ||
2703 | 905 | } | ||
2704 | 906 | |||
2705 | 907 | /* Create copy for return value */ | ||
2706 | 908 | if(strlen(domain)>0) finalDomain=g_strdup(domain); | ||
2707 | 909 | else finalDomain=NULL; | ||
2708 | 910 | |||
2709 | 911 | /* Free allocated resources */ | ||
2710 | 912 | g_free(asciiDomain); | ||
2711 | 913 | |||
2712 | 914 | /* Return domain */ | ||
2713 | 915 | return(finalDomain); | ||
2714 | 916 | } | ||
2715 | 917 | |||
2716 | 918 | /* Get/set policy for javascript from site */ | ||
2717 | 919 | gint nojs_get_policy(NoJS *self, const gchar *inDomain) | ||
2718 | 920 | { | ||
2719 | 921 | g_return_val_if_fail(IS_NOJS(self), NOJS_POLICY_UNDETERMINED); | ||
2720 | 922 | g_return_val_if_fail(inDomain, NOJS_POLICY_UNDETERMINED); | ||
2721 | 923 | |||
2722 | 924 | NoJSPrivate *priv=self->priv; | ||
2723 | 925 | sqlite3_stmt *statement=NULL; | ||
2724 | 926 | gint error; | ||
2725 | 927 | gint policy=NOJS_POLICY_UNDETERMINED; | ||
2726 | 928 | |||
2727 | 929 | /* Check to allow all sites */ | ||
2728 | 930 | if(priv->allowAllSites) return(NOJS_POLICY_ACCEPT); | ||
2729 | 931 | |||
2730 | 932 | /* Check for open database */ | ||
2731 | 933 | g_return_val_if_fail(priv->database, policy); | ||
2732 | 934 | |||
2733 | 935 | /* Lookup policy for site in database */ | ||
2734 | 936 | error=sqlite3_prepare_v2(priv->database, | ||
2735 | 937 | "SELECT site, value FROM policies WHERE site LIKE ? LIMIT 1;", | ||
2736 | 938 | -1, | ||
2737 | 939 | &statement, | ||
2738 | 940 | NULL); | ||
2739 | 941 | if(statement && error==SQLITE_OK) error=sqlite3_bind_text(statement, 1, inDomain, -1, NULL); | ||
2740 | 942 | if(statement && error==SQLITE_OK) | ||
2741 | 943 | { | ||
2742 | 944 | if(sqlite3_step(statement)==SQLITE_ROW) policy=sqlite3_column_int(statement, 1); | ||
2743 | 945 | } | ||
2744 | 946 | else g_warning(_("SQL fails: %s"), sqlite3_errmsg(priv->database)); | ||
2745 | 947 | |||
2746 | 948 | sqlite3_finalize(statement); | ||
2747 | 949 | |||
2748 | 950 | /* If we have not found a policy for the domain then it is an unknown domain. | ||
2749 | 951 | * Get default policy for unknown domains. | ||
2750 | 952 | */ | ||
2751 | 953 | if(policy==NOJS_POLICY_UNDETERMINED) policy=priv->unknownDomainPolicy; | ||
2752 | 954 | |||
2753 | 955 | return(policy); | ||
2754 | 956 | } | ||
2755 | 957 | |||
2756 | 958 | void nojs_set_policy(NoJS *self, const gchar *inDomain, NoJSPolicy inPolicy) | ||
2757 | 959 | { | ||
2758 | 960 | g_return_if_fail(IS_NOJS(self)); | ||
2759 | 961 | g_return_if_fail(inDomain); | ||
2760 | 962 | g_return_if_fail(inPolicy>=NOJS_POLICY_ACCEPT && inPolicy<=NOJS_POLICY_BLOCK); | ||
2761 | 963 | |||
2762 | 964 | NoJSPrivate *priv=self->priv; | ||
2763 | 965 | gchar *sql; | ||
2764 | 966 | gchar *error=NULL; | ||
2765 | 967 | gint success; | ||
2766 | 968 | |||
2767 | 969 | /* Check for open database */ | ||
2768 | 970 | g_return_if_fail(priv->database); | ||
2769 | 971 | |||
2770 | 972 | /* Update policy in database */ | ||
2771 | 973 | sql=sqlite3_mprintf("INSERT OR REPLACE INTO policies (site, value) VALUES ('%q', %d);", | ||
2772 | 974 | inDomain, | ||
2773 | 975 | inPolicy); | ||
2774 | 976 | success=sqlite3_exec(priv->database, sql, NULL, NULL, &error); | ||
2775 | 977 | if(success!=SQLITE_OK) g_warning(_("SQL fails: %s"), error); | ||
2776 | 978 | if(error) sqlite3_free(error); | ||
2777 | 979 | sqlite3_free(sql); | ||
2778 | 980 | |||
2779 | 981 | /* Emit signal to notify about policy change */ | ||
2780 | 982 | if(success==SQLITE_OK) g_signal_emit(self, NoJSSignals[POLICY_CHANGED], 0, inDomain); | ||
2781 | 983 | } | ||
2782 | 984 | |||
2783 | 985 | /* Get/set default policy for unknown domains */ | ||
2784 | 986 | NoJSPolicy nojs_get_policy_for_unknown_domain(NoJS *self) | ||
2785 | 987 | { | ||
2786 | 988 | g_return_val_if_fail(IS_NOJS(self), NOJS_POLICY_UNDETERMINED); | ||
2787 | 989 | |||
2788 | 990 | return(self->priv->unknownDomainPolicy); | ||
2789 | 991 | } | ||
2790 | 992 | |||
2791 | 993 | void nojs_set_policy_for_unknown_domain(NoJS *self, NoJSPolicy inPolicy) | ||
2792 | 994 | { | ||
2793 | 995 | g_return_if_fail(IS_NOJS(self)); | ||
2794 | 996 | g_return_if_fail(inPolicy>=NOJS_POLICY_ACCEPT && inPolicy<=NOJS_POLICY_BLOCK); | ||
2795 | 997 | |||
2796 | 998 | if(self->priv->unknownDomainPolicy!=inPolicy) | ||
2797 | 999 | { | ||
2798 | 1000 | self->priv->unknownDomainPolicy=inPolicy; | ||
2799 | 1001 | midori_extension_set_integer(self->priv->extension, "unknown-domain-policy", inPolicy); | ||
2800 | 1002 | g_object_notify_by_pspec(G_OBJECT(self), NoJSProperties[PROP_UNKNOWN_DOMAIN_POLICY]); | ||
2801 | 1003 | } | ||
2802 | 1004 | } | ||
2803 | 1005 | |||
2804 | 1006 | /* Get/set flag to allow javascript at all sites */ | ||
2805 | 1007 | gboolean nojs_get_allow_all_sites(NoJS *self) | ||
2806 | 1008 | { | ||
2807 | 1009 | g_return_val_if_fail(IS_NOJS(self), TRUE); | ||
2808 | 1010 | |||
2809 | 1011 | return(self->priv->allowAllSites); | ||
2810 | 1012 | } | ||
2811 | 1013 | |||
2812 | 1014 | void nojs_set_allow_all_sites(NoJS *self, gboolean inAllow) | ||
2813 | 1015 | { | ||
2814 | 1016 | g_return_if_fail(IS_NOJS(self)); | ||
2815 | 1017 | |||
2816 | 1018 | if(self->priv->allowAllSites!=inAllow) | ||
2817 | 1019 | { | ||
2818 | 1020 | self->priv->allowAllSites=inAllow; | ||
2819 | 1021 | midori_extension_set_boolean(self->priv->extension, "allow-all-sites", inAllow); | ||
2820 | 1022 | g_object_notify_by_pspec(G_OBJECT(self), NoJSProperties[PROP_ALLOW_ALL_SITES]); | ||
2821 | 1023 | } | ||
2822 | 1024 | } | ||
2823 | 1025 | |||
2824 | 1026 | /* Get/set flag to check for second-level domains only */ | ||
2825 | 1027 | gboolean nojs_get_only_second_level_domain(NoJS *self) | ||
2826 | 1028 | { | ||
2827 | 1029 | g_return_val_if_fail(IS_NOJS(self), TRUE); | ||
2828 | 1030 | |||
2829 | 1031 | return(self->priv->checkOnlySecondLevel); | ||
2830 | 1032 | } | ||
2831 | 1033 | |||
2832 | 1034 | void nojs_set_only_second_level_domain(NoJS *self, gboolean inOnlySecondLevel) | ||
2833 | 1035 | { | ||
2834 | 1036 | g_return_if_fail(IS_NOJS(self)); | ||
2835 | 1037 | |||
2836 | 1038 | if(self->priv->checkOnlySecondLevel!=inOnlySecondLevel) | ||
2837 | 1039 | { | ||
2838 | 1040 | self->priv->checkOnlySecondLevel=inOnlySecondLevel; | ||
2839 | 1041 | midori_extension_set_boolean(self->priv->extension, "only-second-level", inOnlySecondLevel); | ||
2840 | 1042 | g_object_notify_by_pspec(G_OBJECT(self), NoJSProperties[PROP_ONLY_SECOND_LEVEL]); | ||
2841 | 1043 | } | ||
2842 | 1044 | } | ||
2843 | 1045 | |||
2844 | 1046 | /************************************************************************************/ | ||
2845 | 1047 | |||
2846 | 1048 | /* Implementation: Enumeration */ | ||
2847 | 1049 | GType nojs_policy_get_type(void) | ||
2848 | 1050 | { | ||
2849 | 1051 | static volatile gsize g_define_type_id__volatile=0; | ||
2850 | 1052 | |||
2851 | 1053 | if(g_once_init_enter(&g_define_type_id__volatile)) | ||
2852 | 1054 | { | ||
2853 | 1055 | static const GEnumValue values[]= | ||
2854 | 1056 | { | ||
2855 | 1057 | { NOJS_POLICY_UNDETERMINED, "NOJS_POLICY_UNDETERMINED", N_("Undetermined") }, | ||
2856 | 1058 | { NOJS_POLICY_ACCEPT, "NOJS_POLICY_ACCEPT", N_("Accept") }, | ||
2857 | 1059 | { NOJS_POLICY_ACCEPT_TEMPORARILY, "NOJS_POLICY_ACCEPT_TEMPORARILY", N_("Accept temporarily") }, | ||
2858 | 1060 | { NOJS_POLICY_BLOCK, "NOJS_POLICY_BLOCK", N_("Block") }, | ||
2859 | 1061 | { 0, NULL, NULL } | ||
2860 | 1062 | }; | ||
2861 | 1063 | |||
2862 | 1064 | GType g_define_type_id=g_enum_register_static(g_intern_static_string("NoJSPolicy"), values); | ||
2863 | 1065 | g_once_init_leave(&g_define_type_id__volatile, g_define_type_id); | ||
2864 | 1066 | } | ||
2865 | 1067 | |||
2866 | 1068 | return(g_define_type_id__volatile); | ||
2867 | 1069 | } | ||
2868 | 0 | 1070 | ||
2869 | === added file 'extensions/nojs/nojs.h' | |||
2870 | --- extensions/nojs/nojs.h 1970-01-01 00:00:00 +0000 | |||
2871 | +++ extensions/nojs/nojs.h 2013-07-29 19:51:25 +0000 | |||
2872 | @@ -0,0 +1,89 @@ | |||
2873 | 1 | /* | ||
2874 | 2 | Copyright (C) 2013 Stephan Haller <nomad@froevel.de> | ||
2875 | 3 | |||
2876 | 4 | This library is free software; you can redistribute it and/or | ||
2877 | 5 | modify it under the terms of the GNU Lesser General Public | ||
2878 | 6 | License as published by the Free Software Foundation; either | ||
2879 | 7 | version 2.1 of the License, or (at your option) any later version. | ||
2880 | 8 | |||
2881 | 9 | See the file COPYING for the full license text. | ||
2882 | 10 | */ | ||
2883 | 11 | |||
2884 | 12 | #ifndef __NOJS__ | ||
2885 | 13 | #define __NOJS__ | ||
2886 | 14 | |||
2887 | 15 | #include "config.h" | ||
2888 | 16 | #include <midori/midori.h> | ||
2889 | 17 | |||
2890 | 18 | #define NOJS_DATABASE "nojs.db" | ||
2891 | 19 | |||
2892 | 20 | G_BEGIN_DECLS | ||
2893 | 21 | |||
2894 | 22 | /* NoJS manager enums */ | ||
2895 | 23 | typedef enum | ||
2896 | 24 | { | ||
2897 | 25 | NOJS_POLICY_UNDETERMINED, | ||
2898 | 26 | NOJS_POLICY_ACCEPT, | ||
2899 | 27 | NOJS_POLICY_ACCEPT_TEMPORARILY, | ||
2900 | 28 | NOJS_POLICY_BLOCK | ||
2901 | 29 | } NoJSPolicy; | ||
2902 | 30 | |||
2903 | 31 | /* NoJS manager object */ | ||
2904 | 32 | #define TYPE_NOJS (nojs_get_type()) | ||
2905 | 33 | #define NOJS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_NOJS, NoJS)) | ||
2906 | 34 | #define IS_NOJS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), TYPE_NOJS)) | ||
2907 | 35 | #define NOJS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_NOJS, NoJSClass)) | ||
2908 | 36 | #define IS_NOJS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_NOJS)) | ||
2909 | 37 | #define NOJS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_NOJS, NoJSClass)) | ||
2910 | 38 | |||
2911 | 39 | typedef struct _NoJS NoJS; | ||
2912 | 40 | typedef struct _NoJSClass NoJSClass; | ||
2913 | 41 | typedef struct _NoJSPrivate NoJSPrivate; | ||
2914 | 42 | |||
2915 | 43 | struct _NoJS | ||
2916 | 44 | { | ||
2917 | 45 | /* Parent instance */ | ||
2918 | 46 | GObject parent_instance; | ||
2919 | 47 | |||
2920 | 48 | /* Private structure */ | ||
2921 | 49 | NoJSPrivate *priv; | ||
2922 | 50 | }; | ||
2923 | 51 | |||
2924 | 52 | struct _NoJSClass | ||
2925 | 53 | { | ||
2926 | 54 | /* Parent class */ | ||
2927 | 55 | GObjectClass parent_class; | ||
2928 | 56 | |||
2929 | 57 | /* Virtual functions */ | ||
2930 | 58 | void (*uri_load_policy_status)(NoJS *self, gchar *inURI, NoJSPolicy inPolicy); | ||
2931 | 59 | void (*policy_changed)(NoJS *self, gchar *inDomain); | ||
2932 | 60 | }; | ||
2933 | 61 | |||
2934 | 62 | /* Public API */ | ||
2935 | 63 | GType nojs_get_type(void); | ||
2936 | 64 | |||
2937 | 65 | NoJS* nojs_new(MidoriExtension *inExtension, MidoriApp *inApp); | ||
2938 | 66 | |||
2939 | 67 | gchar* nojs_get_domain(NoJS *self, SoupURI *inURI); | ||
2940 | 68 | |||
2941 | 69 | gint nojs_get_policy(NoJS *self, const gchar *inDomain); | ||
2942 | 70 | void nojs_set_policy(NoJS *self, const gchar *inDomain, NoJSPolicy inPolicy); | ||
2943 | 71 | |||
2944 | 72 | NoJSPolicy nojs_get_policy_for_unknown_domain(NoJS *self); | ||
2945 | 73 | void nojs_set_policy_for_unknown_domain(NoJS *self, NoJSPolicy inPolicy); | ||
2946 | 74 | |||
2947 | 75 | gboolean nojs_get_allow_all_sites(NoJS *self); | ||
2948 | 76 | void nojs_set_allow_all_sites(NoJS *self, gboolean inAllow); | ||
2949 | 77 | |||
2950 | 78 | gboolean nojs_get_only_second_level_domain(NoJS *self); | ||
2951 | 79 | void nojs_set_only_second_level_domain(NoJS *self, gboolean inOnlySecondLevel); | ||
2952 | 80 | |||
2953 | 81 | gchar* nojs_get_icon_path (const gchar* icon); | ||
2954 | 82 | |||
2955 | 83 | /* Enumeration */ | ||
2956 | 84 | GType nojs_policy_get_type(void) G_GNUC_CONST; | ||
2957 | 85 | #define NOJS_TYPE_POLICY (nojs_policy_get_type()) | ||
2958 | 86 | |||
2959 | 87 | G_END_DECLS | ||
2960 | 88 | |||
2961 | 89 | #endif /* __NOJS__ */ | ||
2962 | 0 | 90 | ||
2963 | === modified file 'po/POTFILES.in' | |||
2964 | --- po/POTFILES.in 2013-07-29 19:10:25 +0000 | |||
2965 | +++ po/POTFILES.in 2013-07-29 19:51:25 +0000 | |||
2966 | @@ -51,6 +51,9 @@ | |||
2967 | 51 | extensions/formhistory/formhistory.c | 51 | extensions/formhistory/formhistory.c |
2968 | 52 | extensions/formhistory/formhistory-gdom-frontend.c | 52 | extensions/formhistory/formhistory-gdom-frontend.c |
2969 | 53 | extensions/history-list.vala | 53 | extensions/history-list.vala |
2970 | 54 | extensions/nojs/nojs-preferences.c | ||
2971 | 55 | extensions/nojs/nojs-view.c | ||
2972 | 56 | extensions/nojs/nojs.c | ||
2973 | 54 | extensions/mouse-gestures.c | 57 | extensions/mouse-gestures.c |
2974 | 55 | extensions/shortcuts.c | 58 | extensions/shortcuts.c |
2975 | 56 | extensions/status-clock.c | 59 | extensions/status-clock.c |
Nice stuff. Let's get this in!