/[soft]/drakx-net/trunk/bin/net_applet
ViewVC logotype

Contents of /drakx-net/trunk/bin/net_applet

Parent Directory Parent Directory | Revision Log Revision Log


Revision 398 - (show annotations) (download)
Thu Feb 3 18:07:04 2011 UTC (13 years, 2 months ago) by dmorgan
File size: 20828 byte(s)
Import cleaned drakx-net
1 #!/usr/bin/perl
2
3 use strict;
4
5 use POSIX ":sys_wait_h";
6 use lib qw(/usr/lib/libDrakX);
7 # i18n: IMPORTANT: to get correct namespace (drakx-net instead of libDrakX)
8 BEGIN { unshift @::textdomains, 'drakx-net' }
9 use c;
10 use common;
11 use standalone;
12 use network::network;
13 use network::tools;
14 use network::connection;
15 use network::connection::ethernet;
16 use network::vpn;
17 use run_program;
18 use mygtk2 qw(gtknew gtkset);
19 use dbus_object;
20 use network::monitor;
21 use network::signal_strength;
22 use detect_devices;
23 use Gtk2::Notify -init, 'notify';
24
25 use ugtk2 qw(:create :helpers :wrappers :dialogs);
26
27 my $onstartupfile = "$ENV{HOME}/.net_applet";
28 my $system_file = '/etc/sysconfig/drakx-net';
29 shouldStart() or die "$onstartupfile should be set to TRUE or use net_applet --force\n";
30
31 #- Allow multiple instances, but only one per user:
32 is_running('net_applet') and die "net_applet already running\n";
33
34 package network::net_applet;
35
36 use mygtk2 qw(gtknew gtkset);
37 use common;
38
39 our ($current_state, $current_interface);
40 our ($icon, $notification_queue);
41 our $dbus;
42 our ($interactive_cb, $ifw, $ifw_alert);
43
44 our %wireless_networks;
45
46 our %pixbufs =
47 (
48 firewall => gtknew('Pixbuf', file => 'drakfirewall'),
49 firewall_icon => gtknew('Pixbuf', file => 'drakfirewall')->scale_simple(24, 24, 'hyper'),
50 state => { map { $_ => gtknew('Pixbuf', file => $_) } qw(connected disconnected unconfigured connecting) },
51 link_level => { map {
52 $_ => gtknew('Pixbuf', file => 'wifi-' . sprintf('%03d', $_))->scale_simple(24, 24, 'hyper');
53 } qw(20 40 60 80 100) },
54 encryption => { map {
55 $_ => gtknew('Pixbuf', file => "encryption-$_-24");
56 } qw(open weak strong) },
57 );
58
59 sub get_current_network() {
60 detect_devices::is_wireless_interface($current_interface) && find { $_->{current} } values %wireless_networks;
61 }
62
63 sub get_state_pixbuf() {
64 my $wnet = $current_state eq 'connected' && get_current_network();
65 $wnet ?
66 network::signal_strength::get_strength_icon($wnet) :
67 $pixbufs{state}{$current_state};
68 }
69
70 sub update_tray_icon() {
71 if (!$ifw_alert || $icon->get_storage_type ne 'pixbuf') {
72 $icon->set_from_pixbuf(get_state_pixbuf());
73 } else {
74 $icon->set_from_stock('gtk-dialog-warning');
75 }
76 }
77
78 1;
79
80 package main;
81
82 my ($current_description, $simple_menu, $menu, $wireless_device, $timeout, $update_timeout);
83 add_icon_path("/usr/share/libDrakX/pixmaps/");
84
85 my $net = {};
86 my $watched_interface;
87
88 my %global_settings = getVarsFromSh($system_file);
89
90 sub get_state_message {
91 my ($o_interface) = @_;
92 my $interface = $o_interface || $current_interface;
93 my $network = network::net_applet::get_current_network();
94 formatAlaTeX(
95 $current_state eq 'connected' ?
96 N("Network is up on interface %s.", get_interface_name($interface)) .
97 "\n\n" . N("IP address: %s", network::tools::get_interface_ip_address($net, $interface)) .
98 "\n\n" . N("Gateway: %s", [ network::tools::get_interface_status($interface) ]->[1]) .
99 "\n\n" . N("DNS: %s", $net->{resolv}{dnsServer}) .
100 ($network && "\n\n" . N("Connected to %s (link level: %d %%)", $network->{name}, $network->{signal_strength}))
101 : $current_state eq 'disconnected' ?
102 N("Network is down on interface %s.", get_interface_name($interface))
103 : $current_state eq 'unconfigured' ?
104 N("You do not have any configured Internet connection.
105 Run the \"%s\" assistant from the Mageia Linux Control Center", N("Set up a new network interface (LAN, ISDN, ADSL, ...)"))
106 :
107 N("Connecting...")
108 );
109 }
110
111 sub get_interface_type {
112 my ($interface) = @_;
113 my $ifcfg = $net->{ifcfg}{$interface};
114 require network::connection;
115 $ifcfg && network::connection->find_ifcfg_type($ifcfg);
116 }
117
118 sub get_interface_icon {
119 my ($interface) = @_;
120 my $type = get_interface_type($interface);
121 $type && $type->get_type_icon;
122 }
123
124 sub get_interface_name {
125 my ($interface) = @_;
126 my $type = get_interface_type($interface);
127 my $type_name = $type && $type->get_type_description;
128 $type_name ? "$type_name ($interface)" : $interface;
129 }
130
131 my %actions = (
132 'upNetwork' => {
133 name => sub { N("Connect %s", get_interface_name($_[0])) },
134 launch => sub { network::tools::start_interface($_[0], 1) }
135 },
136 'downNetwork' => {
137 name => sub { N("Disconnect %s", get_interface_name($_[0])) },
138 launch => sub { network::tools::stop_interface($_[0], 1) }
139 },
140 'monitorNetwork' => {
141 name => N("Monitor Network"),
142 launch => \&run_net_monitor
143 },
144 'monitorIFW' => {
145 name => N("Interactive Firewall"),
146 launch => \&run_drakids
147 },
148 'wireless' => {
149 name => N("Manage wireless networks"),
150 launch => sub { run_drakroam() }
151 },
152 'drakvpn' => {
153 name => N("Manage VPN connections"),
154 launch => sub { run_program::raw({ detach => 1 }, '/usr/sbin/drakvpn'); },
155 },
156 'confNetwork' => {
157 name => N("Configure Network"),
158 launch => sub { system("/usr/sbin/drakconnect &") }
159 },
160 'chooseInterface' => {
161 name => N("Watched interface"),
162 choices => sub { N("Auto-detect"), sort keys %{$net->{ifcfg}} },
163 choice_selected => sub {
164 $watched_interface ? $_[0] eq $watched_interface :
165 $_[0] eq N("Auto-detect")
166 },
167 launch => sub {
168 $watched_interface = $_[0] eq N("Auto-detect") ? undef : $_[0];
169 checkNetworkForce();
170 }
171 },
172 'setInterface' => {
173 name => N("Active interfaces"),
174 use_checkbox => 1,
175 choices => sub { sort keys %{$net->{ifcfg}} },
176 choice_selected => sub {
177 my ($is_up, $_gw) = network::tools::get_interface_status($_[0]);
178 $is_up;
179 },
180 format_choice => \&get_interface_name,
181 get_icon => \&get_interface_icon,
182 launch => sub {
183 my ($is_up, $_gw) = network::tools::get_interface_status($_[0]);
184 if ($is_up) {
185 network::tools::stop_interface($_[0], 1);
186 } else {
187 network::tools::start_interface($_[0], 1);
188 }
189 checkNetworkForce();
190 }
191 },
192 'chooseProfile' => {
193 name => N("Profiles"),
194 choices => sub { network::network::netprofile_list() },
195 choice_selected => sub { $_[0] eq $net->{PROFILE} },
196 launch => sub {
197 require run_program;
198 $net->{PROFILE} = $_[0];
199 run_program::raw({ detach => 1 }, common::wrap_command_for_root('/sbin/set-netprofile', $net->{PROFILE}));
200 }
201 },
202 'chooseVPN' => {
203 name => N("VPN connection"),
204 header => "drakvpn",
205 choices => sub {
206 map { $_->get_configured_connections } network::vpn::list_types
207 },
208 allow_single_choice => 1,
209 format_choice => \&network::vpn::get_label,
210 choice_selected => sub { $_[0]->is_started },
211 launch => sub {
212 require interactive; $_[0]->is_started ?
213 $_[0]->stop : $_[0]->start(interactive->vnew)
214 },
215 },
216 'help' => {
217 name => N("Help"),
218 launch => sub { system("drakhelp --id internet-connection &") }
219 },
220 'quit' => {
221 name => N("Quit"),
222 launch => \&mainQuit
223 },
224 );
225
226
227 $icon = Gtk2::StatusIcon->new;
228
229 eval { $dbus = dbus_object::system_bus() } if !defined($global_settings{NET_APPLET_DBUS}) || text2bool($global_settings{NET_APPLET_DBUS});
230 eval { $net->{monitor} = network::monitor->new($dbus) } if $dbus;
231 if ($dbus) {
232 require network::net_applet::ifw;
233 network::net_applet::ifw::init();
234 }
235 if ($dbus) {
236 $dbus->{connection}->add_filter(sub {
237 my ($_con, $msg) = @_;
238 if ($msg->get_interface eq 'org.mageia.network' && $msg->get_member eq 'status') {
239 my ($status, $interface) = $msg->get_args_list;
240 print "got connection status event: $status $interface\n";
241 if ($status eq "add") {
242 checkNetworkForce();
243 }
244 }
245 });
246 $dbus->{connection}->add_match("type='signal',interface='org.mageia.network'");
247 dbus_object::set_gtk2_watch_helper($dbus);
248 }
249
250 $notification_queue = Gtk2::Notify::Queue->new($icon);
251
252 $icon->signal_connect(activate => sub {
253 my ($_icon, $button, $time) = @_;
254 if ($ifw_alert) {
255 run_drakids();
256 } elsif ($simple_menu) {
257 $simple_menu->popup(undef, undef, undef, undef, $button, $time);
258 } else {
259 run_netcenter();
260 }
261 });
262 $icon->signal_connect(popup_menu => sub {
263 my ($_icon, $button, $time) = @_;
264 $menu->popup(undef, undef, undef, undef, $button, $time) if $menu;
265 });
266
267 checkNetworkForce();
268 cronNetwork();
269 gtkflush(); #- for notifications to appear on the status icon position
270 network::net_applet::ifw::get_unprocessed_ifw_messages() if $ifw;
271
272 $SIG{HUP} = sub {
273 print "received SIGHUP, reloading network configuration\n";
274 checkNetworkForce();
275 };
276 $SIG{USR1} = sub {
277 # clear all ifw notifications
278 my @packets = eval { $network::net_applet::ifw->get_reports };
279 };
280
281 # do not create zombies (#20552)
282 $SIG{CHLD} = \&harvester;
283 sub harvester {
284 my $pid;
285 do {
286 # we don't care about our child processes
287 $pid = waitpid(-1, &WNOHANG);
288 } while $pid > 0;
289 }
290
291 Gtk2->main;
292
293 ugtk2::exit(0);
294
295 sub is_running {
296 my ($name, $o_user) = @_;
297 my $user = $o_user || $ENV{USER};
298 any {
299 my ($ppid, $pid, $n) = /^\s*(\d+)\s+(\d+)\s+(.*)/;
300 $ppid != 1 && $pid != $$ && $n eq $name;
301 } `ps -o '%P %p %c' -u $user`;
302 }
303
304 sub is_running_match {
305 # (eugeni) this matches part of a running command.
306 # Right now it is only used to detect if ifup script is running.
307 my ($name, $o_user) = @_;
308 my $user = $o_user || $ENV{USER};
309 any {
310 my ($ppid, $pid, $n) = /^\s*(\d+)\s+(\d+)\s+(.*)/;
311 $ppid != 1 && $pid != $$ && $n =~ $name;
312 } `ps -o '%P %p %c' -u $user`;
313 }
314
315 sub shouldStart() {
316 my ($opt) = @ARGV;
317 if ($opt eq '--force' || $opt eq '-f') {
318 return 1;
319 }
320 return getAutoStart();
321 }
322 sub run_net_monitor() {
323 run_program::raw({ detach => 1 }, '/usr/bin/net_monitor', '--defaultintf', $current_interface) unless is_running('net_monitor');
324 }
325 sub run_netcenter() {
326 run_program::raw({ detach => 1 }, '/usr/bin/draknetcenter') unless is_running('draknetcenter', 'root');
327 }
328 sub run_drakroam {
329 my ($o_ap) = @_;
330 run_program::raw({ detach => 1 }, '/usr/sbin/drakroam', if_($o_ap, "--ap=$o_ap")) unless is_running('drakroam', 'root');
331 }
332 sub run_drakids() {
333 $ifw_alert = 0;
334 if (is_running('drakids')) {
335 eval { $ifw->send_manage_request };
336 } else {
337 run_program::raw({ detach => 1 }, '/usr/sbin/drakids');
338 }
339 }
340 sub generate_wireless_menuitem {
341 my ($wnet) = @_;
342 my $menuitem = {};
343 $menuitem->{widget} = Gtk2::CheckMenuItem->new;
344 $menuitem->{widget}->set_draw_as_radio(1);
345 $menuitem->{widget}->add(gtkpack_(gtkshow(gtknew('HBox')),
346 1, gtkset_alignment($menuitem->{label} = gtknew('Label'), 0, 0.5),
347 0, $menuitem->{strength} = Gtk2::Image->new,
348 0, $menuitem->{security} = Gtk2::Image->new,
349 ));
350 $menuitem->{activate} = $menuitem->{widget}->signal_connect('activate' => sub {
351 if ($net->{monitor} && exists $wnet->{id}) {
352 eval { $net->{monitor}->select_network($wnet->{id}) };
353 $@ and err_dialog(N("Interactive Firewall"), N("Unable to contact daemon"));
354 } else {
355 run_drakroam($wnet->{ap});
356 }
357 checkNetworkForce();
358 });
359 update_wireless_item($menuitem, $wnet);
360 push @{$wnet->{menuitems}}, $menuitem;
361 return $menuitem->{widget};
362 }
363 sub update_wireless_item {
364 my ($menuitem, $wnet) = @_;
365 $menuitem->{label}->set_text($wnet->{name});
366 $menuitem->{security}->set_from_pixbuf($pixbufs{encryption}{$wnet->{flags} =~ /WPA/i ? 'strong' : $wnet->{flags} =~ /WEP/i ? 'weak' : 'open'});
367 $menuitem->{strength}->set_from_pixbuf(network::signal_strength::get_strength_icon($wnet));
368
369 $menuitem->{widget}->signal_handler_block($menuitem->{activate});
370 $menuitem->{widget}->set_active($wnet->{current});
371 $menuitem->{widget}->signal_handler_unblock($menuitem->{activate});
372 }
373 sub checkWireless() {
374 $wireless_device or return;
375 my ($networks) = network::monitor::list_wireless($net->{monitor});
376 my $force_applet_update;
377 foreach (keys %$networks) {
378 exists $wireless_networks{$_} or $force_applet_update = 1;
379 put_in_hash($wireless_networks{$_} ||= {}, $networks->{$_});
380 }
381 if ($force_applet_update) {
382 undef $current_state;
383 } else {
384 foreach my $wnet (values %wireless_networks) {
385 my $is_valuable = exists $networks->{$wnet->{ap}};
386 foreach (@{$wnet->{menuitems}}) {
387 update_wireless_item($_, $wnet) if $is_valuable;
388 $_->{widget}->visible($is_valuable);
389 }
390 }
391 }
392 }
393 sub checkNetwork() {
394 my ($gw_intf, $_is_up, $gw_address) = $watched_interface ?
395 ($watched_interface, network::tools::get_interface_status($watched_interface)) :
396 network::tools::get_default_connection($net);
397 my $connecting = is_running_match('ifup', 'root');
398 go2State($gw_address ? 'connected' : $connecting ? 'connecting' : $gw_intf ? 'disconnected' : 'unconfigured', $gw_intf);
399 }
400 sub checkNetworkForce() {
401 $net = {};
402 network::network::read_net_conf($net);
403 undef $current_state;
404 $wireless_device = detect_devices::get_wireless_interface();
405 checkWireless();
406 checkNetwork();
407 }
408 sub cronNetwork() {
409 my $i;
410 $timeout = Glib::Timeout->add(2000, sub {
411 checkWireless() if !($i++%30);
412 checkNetwork();
413 1;
414 });
415 }
416 sub go2State {
417 my ($state_type, $interface) = @_;
418 my $need_update;
419 my ($old_interface, $old_description);
420 if ($current_interface ne $interface) {
421 my $card = find { $_->[0] eq $interface } network::connection::ethernet::get_eth_cards();
422 if ($state_type eq 'disconnected') {
423 $old_interface = $current_interface;
424 $old_description = $current_description;
425 }
426 $current_description = $card && $card->[2];
427 $current_interface = $interface;
428 $need_update = 1;
429 }
430 if ($current_state ne $state_type) {
431 my $show = defined $current_state && $state_type ne 'connecting'; # don't show notification at applet startup and when establishing a connection
432 $current_state = $state_type;
433 $notification_queue->add({
434 title => $old_description || $current_description || N("Network connection"),
435 pixbuf => network::net_applet::get_state_pixbuf(),
436 message => get_state_message($old_interface || $current_interface),
437 }) if $show;
438 $need_update = 1;
439 }
440
441 update_applet() if $need_update;
442 }
443
444 sub update_applet() {
445 $wireless_device = detect_devices::get_wireless_interface();
446
447 # Re-checking wireless networks (#40912)
448 checkWireless();
449
450 generate_menu();
451
452 network::net_applet::update_tray_icon();
453 $icon->set_tooltip(get_state_message());
454 }
455
456 sub create_menu_choices {
457 my ($action, $o_allow_single_choice) = @_;
458 my @choices = $actions{$action}{choices}->();
459 #- don't add submenu if only zero or one choice exists
460 my $allow_single_choice = $actions{$action}{allow_single_choice} || $o_allow_single_choice;
461 @choices > ($allow_single_choice ? 0 : 1) or return ();
462 my $selected = $actions{$action}{choice_selected};
463 my $format = $actions{$action}{format_choice};
464 my $get_icon = $actions{$action}{get_icon};
465 map {
466 my $choice = $_;
467 my $label = $format ? $format->($choice) : $choice;
468 my $w = gtkshow(gtkset_active(gtkadd(
469 Gtk2::CheckMenuItem->new,
470 gtknew('HBox', children => [
471 1, gtkset_alignment(gtknew('Label', text => $label), 0, 0.5),
472 $get_icon ?
473 (0, gtknew('Image', file => $get_icon->($_))) :
474 (),
475 ])), $selected->($choice)));
476 gtksignal_connect($w, activate => sub { $actions{$action}{launch}->($choice) });
477 $w->set_draw_as_radio(!$actions{$action}{use_checkbox});
478 $w;
479 } $actions{$action}{choices}->();
480 }
481
482 sub create_action_item {
483 my ($action) = @_;
484 my $name = ref($actions{$action}{name}) eq 'CODE' ? $actions{$action}{name}->($current_interface) : $actions{$action}{name};
485 if (exists $actions{$action}{choices}) {
486 my @menu = create_menu_choices($action);
487 @menu || $actions{$action}{header} or return ();
488 gtkshow(create_menu($name,
489 $actions{$action}{header} ? (
490 create_action_item($actions{$action}{header}),
491 gtkshow(Gtk2::SeparatorMenuItem->new),
492 ) : (),
493 @menu,
494 ));
495 } else {
496 gtksignal_connect(gtkshow(Gtk2::MenuItem->new_with_label($name)), activate => sub { $actions{$action}{launch}->($current_interface) });
497 }
498 }
499
500 sub empty_menu {
501 my ($menu) = @_;
502 delete $_->{menuitems} foreach values %wireless_networks;
503 $menu->destroy if $menu;
504 Gtk2::Menu->new;
505 }
506
507 sub get_wireless_networks_sorted() {
508 sort {
509 $b->{current} <=> $a->{current} || $b->{signal_strength} <=> $a->{signal_strength} || $a->{name} cmp $b->{name};
510 } values %wireless_networks;
511 }
512
513 sub generate_simple_menu() {
514 $simple_menu = empty_menu($simple_menu);
515
516 if ($wireless_device) {
517 my @networks = get_wireless_networks_sorted();
518 my @valuable_networks = splice @networks, 0, 7;
519 gtkappend($simple_menu,
520 (map { generate_wireless_menuitem($_) } @valuable_networks),
521 (@networks ? create_menu(N("More networks"), map { generate_wireless_menuitem($_) } @networks) : ()),
522 Gtk2::SeparatorMenuItem->new,
523 );
524 }
525 gtkappend($simple_menu, create_menu_choices('setInterface', 'allow_single_choice'));
526 }
527
528 sub generate_menu() {
529 $menu = empty_menu($menu);
530
531 my (@settings);
532 my $interactive;
533 eval { $interactive = $ifw->get_interactive };
534
535 if ($current_state eq 'connected') {
536 $menu->append(create_action_item($_)) foreach qw(downNetwork monitorNetwork);
537 } elsif ($current_state eq 'disconnected') {
538 $menu->append(create_action_item('upNetwork'));
539 }
540 $menu->append(create_action_item('monitorIFW')) if $current_state ne 'unconfigured' && defined $interactive;
541
542 $menu->append(create_action_item('confNetwork'));
543
544 push @settings, create_action_item('chooseInterface') if $current_state ne 'unconfigured';
545
546 push @settings, create_action_item('chooseProfile');
547 if (defined $interactive) {
548 $interactive_cb = gtkshow(gtksignal_connect(gtkset_active(Gtk2::CheckMenuItem->new_with_label(N("Interactive Firewall automatic mode")),
549 !$interactive),
550 toggled => sub { eval { $ifw->set_interactive(to_bool(!$_[0]->get_active)) } }));
551 push @settings, $interactive_cb;
552 }
553 push @settings, gtkshow(gtksignal_connect(gtkset_active(Gtk2::CheckMenuItem->new_with_label(N("Always launch on startup")), getAutoStart()),
554 toggled => sub { setAutoStart(uc(bool2text($_[0]->get_active))) }));
555
556 $menu->append(gtkshow(Gtk2::SeparatorMenuItem->new));
557 if ($current_state ne 'unconfigured' && $wireless_device) {
558 $menu->append(gtkshow(create_menu(N("Wireless networks"),
559 create_action_item('wireless'),
560 gtkshow(Gtk2::SeparatorMenuItem->new),
561 map { generate_wireless_menuitem($_) } get_wireless_networks_sorted())));
562 }
563 if (my $vpn = create_action_item('chooseVPN')) { $menu->append($vpn) }
564 if (my $set = $current_state ne 'unconfigured' && create_action_item('setInterface')) { $menu->append($set) }
565 $menu->append(gtkshow(create_menu(N("Settings"), @settings)));
566 $menu->append(gtkshow(Gtk2::SeparatorMenuItem->new));
567 $menu->append(create_action_item('help'));
568 $menu->append(create_action_item('quit'));
569 $menu;
570 }
571 sub mainQuit() {
572 Glib::Source->remove($timeout) if $timeout;
573 Glib::Source->remove($update_timeout) if $update_timeout;
574 Gtk2->main_quit;
575 }
576 sub getAutoStart() {
577 my %p = getVarsFromSh($onstartupfile);
578 return to_bool($p{AUTOSTART} ne 'FALSE');
579 }
580 sub setAutoStart {
581 my $state = shift;
582 output_p $onstartupfile,
583 qq(AUTOSTART=$state
584 );
585 }

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.30