GCC Code Coverage Report


Directory: ./
File: panels/network/cc-net-proxy-page.c
Date: 2024-05-04 07:58:27
Exec Total Coverage
Lines: 113 192 58.9%
Functions: 14 24 58.3%
Branches: 22 80 27.5%

Line Branch Exec Source
1 /* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 *
3 * Copyright (C) 2011-2012 Richard Hughes <richard@hughsie.com>
4 * Copyright 2022 Mohammed Sadiq <sadiq@sadiqpk.org>
5 * Copyright 2022 Purism SPC
6 *
7 * Licensed under the GNU General Public License Version 2
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 * SPDX-License-Identifier: GPL-2.0-or-later
24 */
25
26 #undef G_LOG_DOMAIN
27 #define G_LOG_DOMAIN "cc-net-proxy-page"
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <glib/gi18n.h>
34
35 #include "panels/common/cc-list-row.h"
36 #include "cc-net-proxy-page.h"
37
38 struct _CcNetProxyPage
39 {
40 AdwNavigationPage parent_instance;
41
42 AdwComboRow *proxy_type_row;
43
44 GtkStack *main_stack;
45 AdwPreferencesGroup *automatic_view;
46 GtkBox *manual_view;
47
48 /* Automatic view */
49 GtkEntry *proxy_url_entry;
50 GtkEntry *proxy_warning_label;
51
52 /* Manual view */
53 AdwEntryRow *http_host_entry;
54 GtkAdjustment *http_port_adjustment;
55 AdwEntryRow *https_host_entry;
56 GtkAdjustment *https_port_adjustment;
57 AdwEntryRow *ftp_host_entry;
58 GtkAdjustment *ftp_port_adjustment;
59 AdwEntryRow *socks_host_entry;
60 GtkAdjustment *socks_port_adjustment;
61 AdwEntryRow *proxy_ignore_entry;
62
63 GSettings *settings;
64 char *state_text;
65
66 gboolean is_loading;
67 };
68
69
6/7
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 110 times.
226 G_DEFINE_TYPE (CcNetProxyPage, cc_net_proxy_page, ADW_TYPE_NAVIGATION_PAGE)
70
71 typedef enum
72 {
73 MODE_DISABLED,
74 MODE_MANUAL,
75 MODE_AUTOMATIC
76 } ProxyMode;
77
78 typedef enum
79 {
80 ROW_AUTOMATIC,
81 ROW_MANUAL
82 } RowValue;
83
84 enum {
85 PROP_0,
86 PROP_MODIFIED,
87 PROP_STATE_TEXT,
88 PROP_ENABLED,
89 N_PROPS
90 };
91
92 static GParamSpec *properties[N_PROPS];
93
94 static gboolean
95 11 get_ignore_hosts (GValue *value,
96 GVariant *variant,
97 gpointer user_data)
98 {
99 22 g_autofree const char **strv = NULL;
100
101 11 strv = g_variant_get_strv (variant, NULL);
102 11 g_value_take_string (value, g_strjoinv (", ", (char **)strv));
103
104 11 return TRUE;
105 }
106
107 static GVariant *
108 set_ignore_hosts (const GValue *value,
109 const GVariantType *expected_type,
110 gpointer user_data)
111 {
112 g_auto(GStrv) strv = NULL;
113 const char *sv;
114
115 sv = g_value_get_string (value);
116 strv = g_strsplit_set (sv, ", ", 0);
117
118 return g_variant_new_strv ((const char * const *)strv, -1);
119 }
120
121 /*
122 * Get the currently selected mode, which may not have saved
123 * to settings yet. This method will always return one of
124 * %MODE_AUTOMATIC or %MODE_MANUAL, regardless of whether the
125 * proxy is enabled or not.
126 */
127 static ProxyMode
128 proxy_get_selected_mode (CcNetProxyPage *self)
129 {
130 guint selected;
131
132 g_assert (CC_IS_NET_PROXY_PAGE (self));
133
134 selected = adw_combo_row_get_selected (self->proxy_type_row);
135
136 if (selected == ROW_AUTOMATIC)
137 return MODE_AUTOMATIC;
138
139 if (selected == ROW_MANUAL)
140 return MODE_MANUAL;
141
142 g_assert_not_reached ();
143
144 return -1;
145 }
146
147 /*
148 * Get the current mode, which may not have saved
149 * to settings yet
150 */
151 static ProxyMode
152 44 proxy_get_current_mode (CcNetProxyPage *self)
153 {
154 ProxyMode mode;
155
156
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
44 g_assert (CC_IS_NET_PROXY_PAGE (self));
157
158 /*
159 * Disabled state is immediately applied on change. So get
160 * it from the settings as we don't store it locally
161 */
162 44 mode = g_settings_get_enum (self->settings, "mode");
163
1/2
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
44 if (mode == MODE_DISABLED)
164 44 return MODE_DISABLED;
165
166 if (self->is_loading)
167 return mode;
168
169 return proxy_get_selected_mode (self);
170 }
171
172 static void
173 22 proxy_update_state_text (CcNetProxyPage *self)
174 {
175 ProxyMode mode;
176
177
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
22 g_assert (CC_IS_NET_PROXY_PAGE (self));
178
179 22 mode = proxy_get_current_mode (self);
180
181
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 if (mode == MODE_DISABLED)
182 22 self->state_text = _("Off");
183 else if (mode == MODE_AUTOMATIC)
184 self->state_text = _("Automatic");
185 else
186 self->state_text = _("Manual");
187
188 22 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_STATE_TEXT]);
189 22 }
190
191 static void
192 cancel_clicked_cb (CcNetProxyPage *self)
193 {
194 g_assert (CC_IS_NET_PROXY_PAGE (self));
195
196 cc_net_proxy_page_cancel_changes (CC_NET_PROXY_PAGE (self));
197 }
198
199 static void
200 save_clicked_cb (CcNetProxyPage *self)
201 {
202 g_assert (CC_IS_NET_PROXY_PAGE (self));
203
204 cc_net_proxy_page_save_changes (CC_NET_PROXY_PAGE (self));
205 }
206
207
208 static void
209 proxy_configuration_changed_cb (CcNetProxyPage *self)
210 {
211 GtkWidget *child;
212 ProxyMode mode;
213
214 g_assert (CC_IS_NET_PROXY_PAGE (self));
215
216 if (adw_combo_row_get_selected (self->proxy_type_row) == ROW_AUTOMATIC)
217 child = GTK_WIDGET (self->automatic_view);
218 else
219 child = GTK_WIDGET (self->manual_view);
220
221 gtk_stack_set_visible_child (self->main_stack, child);
222
223 if (self->is_loading)
224 return;
225
226 mode = proxy_get_current_mode (self);
227 g_settings_set_enum (self->settings, "mode", mode);
228 }
229
230 static void
231 proxy_settings_has_unapplied_cb (CcNetProxyPage *self)
232 {
233 g_assert (CC_IS_NET_PROXY_PAGE (self));
234
235 g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODIFIED]);
236 }
237
238 static void
239 11 proxy_settings_changed_cb (CcNetProxyPage *self)
240 {
241 11 g_autofree char *url = NULL;
242 ProxyMode mode;
243
244 11 url = g_settings_get_string (self->settings, "autoconfig-url");
245 11 mode = proxy_get_current_mode (self);
246
247 /* Show warning if autoconfig URL is not set */
248
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
11 gtk_widget_set_visible (GTK_WIDGET (self->proxy_warning_label), !url || !*url);
249 11 gtk_widget_set_sensitive (GTK_WIDGET (self->main_stack), mode != MODE_DISABLED);
250 11 gtk_widget_set_sensitive (GTK_WIDGET (self->proxy_type_row), mode != MODE_DISABLED);
251
252
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (mode == MODE_AUTOMATIC)
253 adw_combo_row_set_selected (self->proxy_type_row, ROW_AUTOMATIC);
254
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 else if (mode == MODE_MANUAL)
255 adw_combo_row_set_selected (self->proxy_type_row, ROW_MANUAL);
256
257 11 proxy_update_state_text (self);
258 11 }
259
260 static void
261 55 cc_net_proxy_page_get_property (GObject *object,
262 guint prop_id,
263 GValue *value,
264 GParamSpec *pspec)
265 {
266 55 CcNetProxyPage *self = (CcNetProxyPage *)object;
267
268
3/4
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
55 switch (prop_id)
269 {
270 33 case PROP_MODIFIED:
271 33 g_value_set_boolean (value, cc_net_proxy_page_has_modified (self));
272 33 break;
273
274 11 case PROP_STATE_TEXT:
275 11 g_value_set_string (value, self->state_text);
276 11 break;
277
278 11 case PROP_ENABLED:
279 11 g_value_set_boolean (value, cc_net_proxy_page_get_enabled (self));
280 11 break;
281
282 default:
283 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
284 }
285 55 }
286
287 static void
288 cc_net_proxy_page_set_property (GObject *object,
289 guint prop_id,
290 const GValue *value,
291 GParamSpec *pspec)
292 {
293 CcNetProxyPage *self = (CcNetProxyPage *)object;
294
295 switch (prop_id)
296 {
297 case PROP_MODIFIED:
298 case PROP_STATE_TEXT:
299 g_warning ("%s is not a writeable property", g_param_spec_get_name (pspec));
300 break;
301
302 case PROP_ENABLED:
303 cc_net_proxy_page_set_enabled (self, g_value_get_boolean (value));
304 break;
305
306 default:
307 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
308 }
309 }
310
311 static void
312 11 cc_net_proxy_page_finalize (GObject *object)
313 {
314 11 CcNetProxyPage *self = (CcNetProxyPage *)object;
315
316
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 g_clear_object (&self->settings);
317
318 11 G_OBJECT_CLASS (cc_net_proxy_page_parent_class)->finalize (object);
319 11 }
320
321 static void
322 1 cc_net_proxy_page_class_init (CcNetProxyPageClass *klass)
323 {
324 1 GObjectClass *object_class = G_OBJECT_CLASS (klass);
325 1 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
326
327 1 object_class->get_property = cc_net_proxy_page_get_property;
328 1 object_class->set_property = cc_net_proxy_page_set_property;
329 1 object_class->finalize = cc_net_proxy_page_finalize;
330
331 1 properties[PROP_STATE_TEXT] =
332 1 g_param_spec_string ("state-text",
333 "Proxy state text",
334 "Human readable Proxy state text",
335 NULL,
336 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
337
338 1 properties[PROP_MODIFIED] =
339 1 g_param_spec_boolean ("modified",
340 "Proxy settings modified",
341 "Proxy settings modified",
342 FALSE,
343 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
344
345 1 properties[PROP_ENABLED] =
346 1 g_param_spec_boolean ("enabled",
347 "", "", FALSE,
348 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
349
350 1 g_object_class_install_properties (object_class, N_PROPS, properties);
351
352 1 gtk_widget_class_set_template_from_resource (widget_class,
353 "/org/gnome/control-center/"
354 "network/cc-net-proxy-page.ui");
355
356 1 gtk_widget_class_bind_template_child (widget_class, CcNetProxyPage, proxy_type_row);
357
358 1 gtk_widget_class_bind_template_child (widget_class, CcNetProxyPage, main_stack);
359 1 gtk_widget_class_bind_template_child (widget_class, CcNetProxyPage, automatic_view);
360 1 gtk_widget_class_bind_template_child (widget_class, CcNetProxyPage, manual_view);
361
362 1 gtk_widget_class_bind_template_child (widget_class, CcNetProxyPage, proxy_url_entry);
363 1 gtk_widget_class_bind_template_child (widget_class, CcNetProxyPage, proxy_warning_label);
364
365 1 gtk_widget_class_bind_template_child (widget_class, CcNetProxyPage, http_host_entry);
366 1 gtk_widget_class_bind_template_child (widget_class, CcNetProxyPage, http_port_adjustment);
367 1 gtk_widget_class_bind_template_child (widget_class, CcNetProxyPage, https_host_entry);
368 1 gtk_widget_class_bind_template_child (widget_class, CcNetProxyPage, https_port_adjustment);
369 1 gtk_widget_class_bind_template_child (widget_class, CcNetProxyPage, ftp_host_entry);
370 1 gtk_widget_class_bind_template_child (widget_class, CcNetProxyPage, ftp_port_adjustment);
371 1 gtk_widget_class_bind_template_child (widget_class, CcNetProxyPage, socks_host_entry);
372 1 gtk_widget_class_bind_template_child (widget_class, CcNetProxyPage, socks_port_adjustment);
373 1 gtk_widget_class_bind_template_child (widget_class, CcNetProxyPage, proxy_ignore_entry);
374
375 1 gtk_widget_class_bind_template_callback (widget_class, proxy_configuration_changed_cb);
376 1 gtk_widget_class_bind_template_callback (widget_class, save_clicked_cb);
377 1 gtk_widget_class_bind_template_callback (widget_class, cancel_clicked_cb);
378 1 }
379
380 static void
381 44 proxy_bind_settings (CcNetProxyPage *self,
382 const char *type,
383 gpointer url_entry,
384 gpointer port_adjustment)
385 {
386 44 g_autoptr(GSettings) settings = NULL;
387
388
2/4
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
44 g_assert (type && *type);
389
390 44 settings = g_settings_get_child (self->settings, type);
391 44 g_settings_bind (settings, "host",
392 url_entry, "text",
393 G_SETTINGS_BIND_DEFAULT);
394 44 g_settings_bind (settings, "port",
395 port_adjustment, "value",
396 G_SETTINGS_BIND_DEFAULT);
397 44 }
398
399 static void
400 11 cc_net_proxy_page_init (CcNetProxyPage *self)
401 {
402 11 self->is_loading = TRUE;
403 11 self->settings = g_settings_new ("org.gnome.system.proxy");
404
405 11 gtk_widget_init_template (GTK_WIDGET (self));
406
407 /* We should save the changes only when asked to */
408 11 g_settings_delay (self->settings);
409 11 g_signal_connect_object (self->settings, "notify::has-unapplied",
410 G_CALLBACK (proxy_settings_has_unapplied_cb),
411 self,
412 G_CONNECT_SWAPPED | G_CONNECT_AFTER);
413
414 11 g_signal_connect_object (self->settings,
415 "changed",
416 G_CALLBACK (proxy_settings_changed_cb),
417 self,
418 G_CONNECT_SWAPPED | G_CONNECT_AFTER);
419 11 proxy_settings_changed_cb (self);
420
421 11 g_settings_bind (self->settings, "autoconfig-url",
422 11 self->proxy_url_entry, "text",
423 G_SETTINGS_BIND_DEFAULT);
424
425 11 proxy_bind_settings (self, "http", self->http_host_entry, self->http_port_adjustment);
426 11 proxy_bind_settings (self, "https", self->https_host_entry, self->https_port_adjustment);
427 11 proxy_bind_settings (self, "ftp", self->ftp_host_entry, self->ftp_port_adjustment);
428 11 proxy_bind_settings (self, "socks", self->socks_host_entry, self->socks_port_adjustment);
429
430 11 g_settings_bind_with_mapping (self->settings, "ignore-hosts",
431 11 self->proxy_ignore_entry, "text",
432 G_SETTINGS_BIND_DEFAULT,
433 get_ignore_hosts, set_ignore_hosts,
434 NULL, NULL);
435
436 11 proxy_update_state_text (self);
437
438 11 self->is_loading = FALSE;
439 11 }
440
441 gboolean
442 11 cc_net_proxy_page_get_enabled (CcNetProxyPage *self)
443 {
444 ProxyMode mode;
445
446
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
11 g_return_val_if_fail (CC_IS_NET_PROXY_PAGE (self), FALSE);
447
448 11 mode = proxy_get_current_mode (self);
449
450 11 return mode != MODE_DISABLED;
451 }
452
453 void
454 cc_net_proxy_page_set_enabled (CcNetProxyPage *self,
455 gboolean enable)
456 {
457 ProxyMode mode;
458
459 g_return_if_fail (CC_IS_NET_PROXY_PAGE (self));
460
461 /* Proxy should not have changed when enabling/disabling */
462 g_return_if_fail (!cc_net_proxy_page_has_modified (self));
463
464 mode = g_settings_get_enum (self->settings, "mode");
465
466 /*
467 * Don't change if that's already the case to avoid marking
468 * the settings as modified
469 */
470 if (enable && mode != MODE_DISABLED)
471 return;
472
473 if (!enable && mode == MODE_DISABLED)
474 return;
475
476 if (enable)
477 mode = proxy_get_selected_mode (self);
478 else
479 mode = MODE_DISABLED;
480
481 g_settings_set_enum (self->settings, "mode", mode);
482
483 /* Apply changes immediately */
484 cc_net_proxy_page_save_changes (self);
485 }
486
487 gboolean
488 33 cc_net_proxy_page_has_modified (CcNetProxyPage *self)
489 {
490
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
33 g_return_val_if_fail (CC_IS_NET_PROXY_PAGE (self), FALSE);
491
492 33 return g_settings_get_has_unapplied (self->settings);
493 }
494
495 void
496 cc_net_proxy_page_save_changes (CcNetProxyPage *self)
497 {
498 g_return_if_fail (CC_IS_NET_PROXY_PAGE (self));
499
500 g_settings_apply (self->settings);
501 }
502
503 void
504 cc_net_proxy_page_cancel_changes (CcNetProxyPage *self)
505 {
506 g_return_if_fail (CC_IS_NET_PROXY_PAGE (self));
507
508 g_settings_revert (self->settings);
509
510 /* Update widgets from the stored settings, not from the UI values */
511 self->is_loading = TRUE;
512 proxy_settings_changed_cb (self);
513 self->is_loading = FALSE;
514 }
515