From 1d37bfdbbe874abd6dcb5563eea19f531de09e1c Mon Sep 17 00:00:00 2001 From: Olivier Blin Date: Fri, 25 May 2007 15:39:46 +0000 Subject: sync with 2007.1 (because of SVN loss) --- bin/net_applet | 489 +++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 334 insertions(+), 155 deletions(-) (limited to 'bin/net_applet') diff --git a/bin/net_applet b/bin/net_applet index a0c9efe..d4eb999 100644 --- a/bin/net_applet +++ b/bin/net_applet @@ -2,20 +2,26 @@ use strict; use lib qw(/usr/lib/libDrakX); +# i18n: IMPORTANT: to get correct namespace (drakx-net instead of libDrakX) +BEGIN { unshift @::textdomains, 'drakx-net' } use c; use common; use standalone; use network::network; use network::tools; +use network::connection; +use network::connection::ethernet; +use network::vpn; use run_program; -use mygtk2 qw(gtknew); +use mygtk2 qw(gtknew gtkset); use dbus_object; use network::ifw; use network::monitor; +use network::signal_strength; use detect_devices; +use modules; use Gtk2::TrayIcon; -use Gtk2::NotificationBubble; use ugtk2 qw(:create :helpers :wrappers :dialogs); @@ -24,33 +30,45 @@ shouldStart() or die "$onstartupfile should be set to TRUE or use net_applet --f #- Allow multiple instances, but only one per user: is_running('net_applet') and die "net_applet already running\n"; -my ($eventbox, $img, $bubble); -my ($current_state, $current_interface, $menu, $wireless_device, $wireless_menu, $timeout, $update_timeout); +my ($eventbox, $img); +my ($current_state, $current_interface, $current_description, $simple_menu, $menu, $wireless_device, $timeout, $update_timeout); add_icon_path("/usr/share/libDrakX/pixmaps/"); my $net = {}; +my $modules_conf = modules::any_conf->read; my $watched_interface; my %pixbufs = ( - firewall => gtkcreate_pixbuf('/usr/lib/libDrakX/icons/drakfirewall.png'), - firewall_icon => gtkcreate_pixbuf('/usr/lib/libDrakX/icons/drakfirewall.png')->scale_simple(24, 24, 'hyper'), - state => { map { $_ => gtkcreate_pixbuf($_) } qw(connected disconnected) }, + firewall => gtknew('Pixbuf', file => 'drakfirewall.png'), + firewall_icon => gtknew('Pixbuf', file => 'drakfirewall.png')->scale_simple(24, 24, 'hyper'), + state => { map { $_ => gtknew('Pixbuf', file => $_) } qw(connected disconnected) }, link_level => { map { - $_ => gtkcreate_pixbuf('wifi-' . sprintf('%03d', $_) . '.png')->scale_simple(24, 24, 'hyper'); + $_ => gtknew('Pixbuf', file => 'wifi-' . sprintf('%03d', $_) . '.png')->scale_simple(24, 24, 'hyper'); } qw(20 40 60 80 100) }, - keyring => gtkcreate_pixbuf("/usr/share/pixmaps/keyring-small.png")->scale_simple(24, 24, 'hyper'), #- provided by usermode, required by drakxtools + encryption => { map { + $_ => gtknew('Pixbuf', file => "encryption-$_-24.png"); + } qw(open weak strong) }, ); my %wireless_networks; -my %tooltips = - ( - connected => N_("Network is up on interface %s"), - disconnected => - #-PO: keep the "Configure Network" substring synced with the "Configure Network" message below - N_("Network is down on interface %s. Click on \"Configure Network\""), - notconfigured => N_("You do not have any configured Internet connection. -Run the \"%s\" assistant from the Mandriva Linux Control Center", N("Set up a new network interface (LAN, ISDN, ADSL, ...)")), - ); + +sub get_state_message { + my ($o_interface) = @_; + my $interface = $o_interface || $current_interface; + my $network = get_current_network(); + formatAlaTeX( + $current_state eq 'connected' ? + N("Network is up on interface %s.", $interface) . + "\n\n" . N("IP address: %s", network::tools::get_interface_ip_address($net, $interface)) . + "\n\n" . N("Gateway: %s", [ network::tools::get_interface_status($interface) ]->[1]) . + ($network && "\n\n" . N("Connected to %s (link level: %d %%)", $network->{name}, $network->{signal_strength})) + : $current_state eq 'disconnected' ? + N("Network is down on interface %s.", $interface) + : + N("You do not have any configured Internet connection. +Run the \"%s\" assistant from the Mandriva Linux Control Center", N("Set up a new network interface (LAN, ISDN, ADSL, ...)")) + ); +} my %actions = ( 'upNetwork' => { name => sub { N("Connect %s", $_[0]) }, launch => sub { network::tools::start_interface($_[0], 1) } }, @@ -58,7 +76,12 @@ my %actions = ( 'monitorNetwork' => { name => N("Monitor Network"), launch => \&run_net_monitor }, 'monitorIFW' => { name => N("Interactive Firewall"), launch => \&run_drakids }, 'wireless' => { name => N("Manage wireless networks"), launch => sub { run_drakroam() } }, - 'confNetwork' => { name => N("Configure Network"), launch => sub { system("/usr/sbin/drakconnect --skip-wizard &") } }, + 'drakvpn' => { + name => N("Manage VPN connections"), launch => sub { + run_program::raw({ detach => 1 }, '/usr/sbin/drakvpn'); + }, + }, + 'confNetwork' => { name => N("Configure Network"), launch => sub { system("/usr/sbin/drakconnect &") } }, 'chooseInterface' => { name => N("Watched interface"), choices => sub { N("Auto-detect"), sort keys %{$net->{ifcfg}} }, @@ -76,6 +99,12 @@ my %actions = ( my ($is_up, $_gw) = network::tools::get_interface_status($_[0]); $is_up; }, + get_icon => sub { + my $ifcfg = $net->{ifcfg}{$_[0]}; + require network::connection; + my $type = $ifcfg && network::connection->find_ifcfg_type($ifcfg); + $type && $type->get_type_icon; + }, launch => sub { my ($is_up, $_gw) = network::tools::get_interface_status($_[0]); if ($is_up) { @@ -93,9 +122,18 @@ my %actions = ( launch => sub { require run_program; $net->{PROFILE} = $_[0]; - run_program::raw({ detach => 1 }, network::tools::wrap_command_for_root('/sbin/set-netprofile', $net->{PROFILE})); + run_program::raw({ detach => 1 }, common::wrap_command_for_root('/sbin/set-netprofile', $net->{PROFILE})); } }, + 'chooseVPN' => { + name => N("VPN connection"), + header => "drakvpn", + choices => sub { map { $_->get_configured_connections } network::vpn::list_types }, + allow_single_choice => 1, + format_choice => \&network::vpn::get_label, + choice_selected => sub { $_[0]->is_started }, + launch => sub { require interactive; $_[0]->is_started ? $_[0]->stop : $_[0]->start(interactive->vnew) }, + }, 'help' => { name => N("Get Online Help"), launch => sub { system("drakhelp --id internet-connection &") } }, 'quit' => { name => N("Quit"), launch => \&mainQuit }, ); @@ -107,7 +145,7 @@ gtkadd(my $icon = Gtk2::TrayIcon->new("Net_Applet"), ); $icon->show_all; -my ($dbus, $monitor, $ifw, $interactive_cb, @attacks_queue, $ifw_alert); +my ($dbus, $monitor, $ifw, $interactive_cb, $ifw_alert); eval { $dbus = dbus_object::system_bus() }; eval { $monitor = network::monitor->new($dbus) } if $dbus; eval { @@ -115,7 +153,9 @@ eval { my ($_con, $msg) = @_; my $member = $msg->get_member; if ($member eq 'Attack') { - handle_attack($msg->get_args_list); + handle_ifw_message($msg->get_args_list); + } elsif ($member eq 'Listen') { + handle_ifw_listen($msg->get_args_list); } elsif ($member eq 'Init') { $ifw->attach_object; checkNetworkForce(); @@ -125,27 +165,24 @@ eval { }); } if $dbus; -$bubble = Gtk2::NotificationBubble->new; -$bubble->attach($icon); -$bubble->signal_connect(timeout => sub { - set_verdict($attacks_queue[0], \&apply_verdict_ignore); -}); -$bubble->signal_connect(clicked => sub { - $bubble->hide; - eval { $ifw->send_alert_ack }; - $ifw_alert = 0; - update_tray_icon(); - ask_attack_verdict($attacks_queue[0]); -}); +my $bubble_queue = Gtk2::NotificationBubble::Queue->new; +$bubble_queue->{bubble}->attach($icon); $eventbox->signal_connect(button_press_event => sub { - $_[1]->button == 1 and ($ifw_alert ? run_drakids() : run_net_monitor()); - $_[1]->button == 3 && $menu and $menu->popup(undef, undef, undef, undef, $_[1]->button, $_[1]->time); + if ($_[1]->button == 1) { + if ($ifw_alert) { + run_drakids(); + } elsif ($simple_menu) { + $simple_menu->popup(undef, undef, undef, undef, $_[1]->button, $_[1]->time); + } + } elsif ($_[1]->button == 3 && $menu) { + $menu->popup(undef, undef, undef, undef, $_[1]->button, $_[1]->time); + } }); checkNetworkForce(); cronNetwork(); -get_unprocessed_attacks(); +get_unprocessed_ifw_messages(); $SIG{HUP} = sub { print "received SIGHUP, reloading network configuration\n"; @@ -160,7 +197,7 @@ sub is_running { my ($name) = @_; any { my ($ppid, $pid, $n) = /^\s*(\d+)\s+(\d+)\s+(.*)/; - $pid != $$ && $n eq $name; + $ppid != 1 && $pid != $$ && $n eq $name; } `ps -o '%P %p %c' -u $ENV{USER}`; } sub shouldStart() { @@ -186,44 +223,57 @@ sub run_drakids() { } } sub generate_wireless_menuitem { - my ($wnet, $ap) = @_; - $wnet->{menuitem} = Gtk2::CheckMenuItem->new; - $wnet->{menuitem}->set_draw_as_radio(1); - $wnet->{menuitem}->add(gtkpack_(gtkshow(Gtk2::HBox->new), - 1, gtkset_alignment($wnet->{ssid_label} = Gtk2::Label->new, 0, 0), - 0, $wnet->{keyring_image} = Gtk2::Image->new_from_pixbuf($pixbufs{keyring}), - 0, $wnet->{level_image} = Gtk2::Image->new)); - $wnet->{activate} = $wnet->{menuitem}->signal_connect('activate' => sub { + my ($wnet) = @_; + my $menuitem = {}; + $menuitem->{widget} = Gtk2::CheckMenuItem->new; + $menuitem->{widget}->set_draw_as_radio(1); + $menuitem->{widget}->add(gtkpack_(gtkshow(gtknew('HBox')), + 1, gtkset_alignment($menuitem->{label} = gtknew('Label'), 0, 0.5), + 0, $menuitem->{strength} = Gtk2::Image->new, + 0, $menuitem->{security} = Gtk2::Image->new, + )); + $menuitem->{activate} = $menuitem->{widget}->signal_connect('activate' => sub { if (exists $wnet->{id}) { eval { $monitor->select_network($wnet->{id}) }; $@ and err_dialog(N("Interactive Firewall"), N("Unable to contact daemon")); } else { - run_drakroam($ap); + run_drakroam($wnet->{ap}); } checkNetworkForce(); }); - undef $current_state; #- force menu redraw + update_wireless_item($menuitem, $wnet); + push @{$wnet->{menuitems}}, $menuitem; + return $menuitem->{widget}; } sub update_wireless_item { - my ($wnet, $ap_address) = @_; - $wnet->{ssid_label}->set_text($wnet->{essid} || "[$ap_address]"); - $wnet->{keyring_image}->visible(to_bool($wnet->{flags})); - $wnet->{level_image}->set_from_pixbuf($pixbufs{link_level}{$wnet->{approx_level}}); - - $wnet->{menuitem}->signal_handler_block($wnet->{activate}); - $wnet->{menuitem}->set_active($wnet->{current}); - $wnet->{menuitem}->signal_handler_unblock($wnet->{activate}); + my ($menuitem, $wnet) = @_; + $menuitem->{label}->set_text($wnet->{name}); + $menuitem->{security}->set_from_pixbuf($pixbufs{encryption}{$wnet->{flags} =~ /WPA/i ? 'strong' : $wnet->{flags} =~ /WEP/i ? 'weak' : 'open'}); + $menuitem->{strength}->set_from_pixbuf(network::signal_strength::get_strength_icon($wnet)); + + $menuitem->{widget}->signal_handler_block($menuitem->{activate}); + $menuitem->{widget}->set_active($wnet->{current}); + $menuitem->{widget}->signal_handler_unblock($menuitem->{activate}); } sub checkWireless() { $wireless_device or return; - my ($networks) = network::monitor::list_wireless($monitor, $wireless_device); + my ($networks) = network::monitor::list_wireless($monitor); + my $force_applet_update; foreach (keys %$networks) { - my $wnet = $wireless_networks{$_} ||= {}; - put_in_hash($wnet, $networks->{$_}); - exists $wnet->{menuitem} or generate_wireless_menuitem($wnet, $_); - update_wireless_item($wnet, $_); + exists $wireless_networks{$_} or $force_applet_update = 1; + put_in_hash($wireless_networks{$_} ||= {}, $networks->{$_}); + } + if ($force_applet_update) { + undef $current_state; + } else { + foreach my $wnet (values %wireless_networks) { + my $is_valuable = exists $networks->{$wnet->{ap}}; + foreach (@{$wnet->{menuitems}}) { + update_wireless_item($_, $wnet) if $is_valuable; + $_->{widget}->visible($is_valuable); + } + } } - $wireless_networks{$_}{menuitem}->visible(exists $networks->{$_}) foreach keys %wireless_networks; } sub checkNetwork() { my ($gw_intf, $_is_up, $gw_address) = $watched_interface ? @@ -249,85 +299,172 @@ sub cronNetwork() { } sub go2State { my ($state_type, $interface) = @_; - if ($current_state ne $state_type || $current_interface ne $interface) { - $current_state = $state_type; - $current_interface = $interface; - $wireless_device = detect_devices::get_wireless_interface(); - if ($menu) { - if (my $m = $wireless_menu && $wireless_menu->get_submenu) { - $_->{menuitem}->get_parent and $m->remove($_->{menuitem}) foreach values %wireless_networks; - } - $menu->destroy; + my $need_update; + my ($old_interface, $old_description); + if ($current_interface ne $interface) { + my $card = find { $_->[0] eq $interface } network::connection::ethernet::get_eth_cards($modules_conf); + if ($state_type eq 'disconnected') { + $old_interface = $current_interface; + $old_description = $current_description; } - $menu = generate_menu($interface); + $current_description = $card && $card->[2]; + $current_interface = $interface; + $need_update = 1; + } + if ($current_state ne $state_type) { + my $show = defined $current_state; # don't show bubble at applet startup + $current_state = $state_type; + $bubble_queue->add({ + title => $old_description || $current_description || N("Network connection"), + pixbuf => get_state_pixbuf(), + message => get_state_message($old_interface || $current_interface), + }) if $show; + $need_update = 1; + } + + update_applet() if $need_update; +} + +sub get_current_network() { + detect_devices::is_wireless_interface($current_interface) && find { $_->{current} } values %wireless_networks; +} + +sub get_state_pixbuf() { + my $pixbuf; + if ($current_state eq 'connected') { + my $wnet = get_current_network(); + $pixbuf = $wnet ? + network::signal_strength::get_strength_icon($wnet) : + $pixbufs{state}{connected}; + } else { + $pixbuf = $pixbufs{state}{disconnected}; } + $pixbuf; } + sub update_tray_icon() { if (!$ifw_alert || $img->get_storage_type ne 'pixbuf') { - my $pixbuf; - if ($current_state eq 'connected') { - if (detect_devices::is_wireless_interface($current_interface)) { - my $wnet = find { $_->{current} } values %wireless_networks; - $pixbuf = $pixbufs{link_level}{$wnet->{approx_level}} if $wnet; - } - $pixbuf ||= $pixbufs{state}{connected}; - } else { - $pixbuf = $pixbufs{state}{disconnected}; - } - $img->set_from_pixbuf($pixbuf); + $img->set_from_pixbuf(get_state_pixbuf()); } else { $img->set_from_stock('gtk-dialog-warning', 'small-toolbar'); } } -sub generate_menu { - my ($interface) = @_; + +sub enable_ifw_alert() { + unless ($ifw_alert) { + $ifw_alert = 1; + update_tray_icon(); + Glib::Timeout->add(1000, sub { + update_tray_icon(); + $ifw_alert; + }); + } +} + +sub disable_ifw_alert() { + eval { $ifw->send_alert_ack }; + $ifw_alert = 0; + update_tray_icon(); +} + +sub update_applet() { + $wireless_device = detect_devices::get_wireless_interface(); + + generate_simple_menu(); + generate_menu(); update_tray_icon(); - gtkset_tip(Gtk2::Tooltips->new, $eventbox, formatAlaTeX(sprintf(translate($tooltips{$current_state}), $interface))); - - my $menu = Gtk2::Menu->new; - my $create_item = sub { - my ($action) = @_; - my $name = ref($actions{$action}{name}) eq 'CODE' ? $actions{$action}{name}->($interface) : $actions{$action}{name}; - my $launch = $actions{$action}{launch}; - my @choices = exists $actions{$action}{choices} ? $actions{$action}{choices}->() : (); - my $w; - if (@choices == 0) { - $w = gtksignal_connect(gtkshow(Gtk2::MenuItem->new_with_label($name)), activate => sub { $launch->($interface) }); - } elsif (@choices > 1) { - my $selected = $actions{$action}{choice_selected}; - my $format = $actions{$action}{format_choice}; - $w = gtkshow(create_menu($name, map { - my $choice = $_; - my $w = gtkshow(gtkset_active(Gtk2::CheckMenuItem->new_with_label($format ? $format->($choice) : $choice), $selected->($choice))); - gtksignal_connect($w, activate => sub { $launch->($choice) }); - $w->set_draw_as_radio(!$actions{$action}{use_checkbox}); - $w; - } $actions{$action}{choices}->())); - } - #- don't add submenu if only one choice exists + gtkset_tip(Gtk2::Tooltips->new, $eventbox, get_state_message()); #gtkset($eventbox, tip => get_state_message()); +} + +sub create_menu_choices { + my ($action) = @_; + my @choices = $actions{$action}{choices}->(); + #- don't add submenu if only zero or one choice exists + @choices > ($actions{$action}{allow_single_choice} ? 0 : 1) or return (); + my $selected = $actions{$action}{choice_selected}; + my $format = $actions{$action}{format_choice}; + my $get_icon = $actions{$action}{get_icon}; + map { + my $choice = $_; + my $label = $format ? $format->($choice) : $choice; + my $w = gtkshow(gtkset_active(gtkadd( + Gtk2::CheckMenuItem->new, + gtknew('HBox', children => [ + 1, gtkset_alignment(gtknew('Label', text => $label), 0, 0.5), + $get_icon ? + (0, gtknew('Image', file => $get_icon->($_))) : + (), + ])), $selected->($choice))); + gtksignal_connect($w, activate => sub { $actions{$action}{launch}->($choice) }); + $w->set_draw_as_radio(!$actions{$action}{use_checkbox}); $w; - }; + } $actions{$action}{choices}->(); +} + +sub create_action_item { + my ($action) = @_; + my $name = ref($actions{$action}{name}) eq 'CODE' ? $actions{$action}{name}->($current_interface) : $actions{$action}{name}; + if (exists $actions{$action}{choices}) { + gtkshow(create_menu($name, + if_($actions{$action}{header}, + create_action_item($actions{$action}{header}), + gtkshow(Gtk2::SeparatorMenuItem->new), + ), + create_menu_choices($action), + )); + } else { + gtksignal_connect(gtkshow(Gtk2::MenuItem->new_with_label($name)), activate => sub { $actions{$action}{launch}->($current_interface) }); + } +} + +sub empty_menu { + my ($menu) = @_; + delete $_->{menuitems} foreach values %wireless_networks; + $menu->destroy if $menu; + Gtk2::Menu->new; +} + +sub get_wireless_networks_sorted() { + sort { + $b->{signal_strength} <=> $a->{signal_strength} || $a->{name} cmp $b->{name}; + } values %wireless_networks; +} + +sub generate_simple_menu() { + $simple_menu = empty_menu($simple_menu); + + if ($wireless_device) { + my @networks = get_wireless_networks_sorted(); + my @valuable_networks = splice @networks, 0, 7; + gtkappend($simple_menu, + (map { generate_wireless_menuitem($_) } @valuable_networks), + (@networks ? create_menu(N("More networks"), map { generate_wireless_menuitem($_) } @networks) : ()), + Gtk2::SeparatorMenuItem->new, + ); + } + gtkappend($simple_menu, create_menu_choices('setInterface')); +} + +sub generate_menu() { + $menu = empty_menu($menu); my (@settings); my $interactive; eval { $interactive = $ifw->get_interactive }; if ($current_state eq 'connected') { - $menu->append($create_item->($_)) foreach qw(downNetwork monitorNetwork); + $menu->append(create_action_item($_)) foreach qw(downNetwork monitorNetwork); } elsif ($current_state eq 'disconnected') { - $menu->append($create_item->('upNetwork')); + $menu->append(create_action_item('upNetwork')); } - $menu->append($create_item->('monitorIFW')) if $current_state ne 'notconfigured' && defined $interactive; + $menu->append(create_action_item('monitorIFW')) if $current_state ne 'notconfigured' && defined $interactive; - $menu->append($create_item->('confNetwork')); + $menu->append(create_action_item('confNetwork')); - if ($current_state ne 'notconfigured') { - $menu->append($create_item->('wireless')) if $wireless_device; - push @settings, $create_item->('chooseInterface'); - } + push @settings, create_action_item('chooseInterface') if $current_state ne 'notconfigured'; - push @settings, $create_item->('chooseProfile'); + push @settings, create_action_item('chooseProfile'); if (defined $interactive) { $interactive_cb = gtkshow(gtksignal_connect(gtkset_active(Gtk2::CheckMenuItem->new_with_label(N("Interactive Firewall automatic mode")), !$interactive), @@ -338,13 +475,18 @@ sub generate_menu { toggled => sub { setAutoStart(uc(bool2text($_[0]->get_active))) })); $menu->append(gtkshow(Gtk2::SeparatorMenuItem->new)); - $wireless_device and $menu->append(gtkshow($wireless_menu = create_menu(N("Wireless networks"), - map { $_->{menuitem} } values %wireless_networks))); - if (my $set = $current_state ne 'notconfigured' && $create_item->('setInterface')) { $menu->append($set) } - $menu->append(gtkshow(create_menu(N("Settings"), grep { $_ } @settings))); + if ($current_state ne 'notconfigured' && $wireless_device) { + $menu->append(gtkshow(create_menu(N("Wireless networks"), + create_action_item('wireless'), + gtkshow(Gtk2::SeparatorMenuItem->new), + map { generate_wireless_menuitem($_) } get_wireless_networks_sorted()))); + } + if (my $vpn = create_action_item('chooseVPN')) { $menu->append($vpn) } + if (my $set = $current_state ne 'notconfigured' && create_action_item('setInterface')) { $menu->append($set) } + $menu->append(gtkshow(create_menu(N("Settings"), @settings))); $menu->append(gtkshow(Gtk2::SeparatorMenuItem->new)); - $menu->append($create_item->('help')); - $menu->append($create_item->('quit')); + $menu->append(create_action_item('help')); + $menu->append(create_action_item('quit')); $menu; } sub mainQuit() { @@ -363,27 +505,17 @@ sub setAutoStart { ); } -sub get_unprocessed_attacks() { +sub get_unprocessed_ifw_messages() { my @packets = eval { $ifw->get_reports }; - while (my @attack = splice(@packets, 0, 10)) { - handle_attack(@attack); + while (my @ifw_message = splice(@packets, 0, 10)) { + handle_ifw_message(@ifw_message); } } -sub handle_attack { - my $attack = network::ifw::attack_to_hash(\@_); - push @attacks_queue, $attack; - @attacks_queue == 1 and notify_attack($attacks_queue[0]); -} - sub set_verdict { my ($attack, $apply_verdict) = @_; eval { $apply_verdict->($attack) }; $@ and err_dialog(N("Interactive Firewall"), N("Unable to contact daemon")); - - shift @attacks_queue; - #- wait for some time so that the new bubble is noticeable - @attacks_queue and Glib::Timeout->add(500, sub { notify_attack($attacks_queue[0]); 0 }); } sub apply_verdict_blacklist { @@ -402,33 +534,40 @@ sub apply_verdict_whitelist { apply_verdict_ignore($attack); } -sub notify_attack { - my ($attack) = @_; +sub handle_ifw_message { + my $attack = network::ifw::attack_to_hash(\@_); unless ($attack->{msg}) { print "unhandled attack type, skipping\n"; return; } - unless ($ifw_alert) { - $ifw_alert = 1; - update_tray_icon(); - Glib::Timeout->add(1000, sub { - update_tray_icon(); - $ifw_alert; - }); - } - $bubble->set(N("Interactive Firewall"), Gtk2::Image->new_from_pixbuf($pixbufs{firewall}), $attack->{msg}); - $bubble->show(5000); + enable_ifw_alert(); + $bubble_queue->add({ + title => N("Interactive Firewall"), + pixbuf => $pixbufs{firewall}, + message => $attack->{msg}, + timeout => sub { + set_verdict($attack, \&apply_verdict_ignore); + }, + clicked => sub { + disable_ifw_alert(); + ask_attack_verdict($attack); + }, + }); } sub ask_attack_verdict { my ($attack) = @_; my $w = ugtk2->new(N("Interactive Firewall: intrusion detected"), - icon => "/usr/lib/libDrakX/icons/drakfirewall.png"); + icon => "drakfirewall.png"); my ($blacklist, $whitelist, $ignore, $auto); my $update_automatic_mode = sub { $auto->get_active and $interactive_cb->set_active(1) }; - + my $set_verdict = sub { + my ($verdict) = @_; + set_verdict($attack, $verdict); + $bubble_queue->process_next; + }; gtkadd($w->{window}, gtknew('VBox', spacing => 5, children_loose => [ gtknew('HBox', children => [ @@ -467,23 +606,63 @@ sub ask_attack_verdict { $blacklist = gtknew('Button', text => N("Blacklist"), clicked => sub { $w->destroy; $update_automatic_mode->(); - set_verdict($attack, \&apply_verdict_blacklist); + $set_verdict->(\&apply_verdict_blacklist); }), $whitelist = gtknew('Button', text => N("Whitelist"), clicked => sub { $w->destroy; $update_automatic_mode->(); - set_verdict($attack, \&apply_verdict_whitelist); + $set_verdict->(\&apply_verdict_whitelist); }), $ignore = gtknew('Button', text => N("Ignore"), clicked => sub { $w->destroy; - set_verdict($attack, \&apply_verdict_ignore); + $set_verdict->(\&apply_verdict_ignore); }), ]), ])); eval { $auto->set_active(!$ifw->get_interactive) }; $blacklist->grab_focus; gtksignal_connect($w->{window}, delete_event => sub { - set_verdict($attack, \&apply_verdict_ignore); + $set_verdict->(\&apply_verdict_ignore); }); $w->{window}->show_all; } + +sub handle_ifw_listen { + my $listen = network::ifw::parse_listen_message(\@_); + enable_ifw_alert(); + $bubble_queue->add({ + title => N("Interactive Firewall: new service"), + pixbuf => $pixbufs{firewall}, + message => $listen->{message}, + clicked => sub { + disable_ifw_alert(); + ask_listen_verdict($listen); + }, + }); +} + +sub ask_listen_verdict { + my ($listen) = @_; + + my $w = ugtk2->new(N("Interactive Firewall: new service"), icon => "drakfirewall.png"); + my $set_verdict = sub { + $bubble_queue->process_next; + }; + gtkadd($w->{window}, + gtknew('VBox', spacing => 5, children_loose => [ + gtknew('HBox', children => [ + 0, Gtk2::Image->new_from_stock('gtk-dialog-warning', 'dialog'), + 1, gtknew('VBox', children => [ + 0, $listen->{message}, + 0, N("Do you want to open this service?"), + ]) + ]), + gtknew('CheckButton', text => N("Remember this answer"), toggled => sub {}), + gtknew('HButtonBox', layout => 'edge', children_loose => [ + gtknew('Button', text => N("Allow"), clicked => sub { $w->destroy; $set_verdict->(1) }), + gtknew('Button', text => N("Block"), clicked => sub { $w->destroy; $set_verdict->(0) }), + ]), + ])); + gtksignal_connect($w->{window}, delete_event => sub { $set_verdict->() }); + $w->{window}->show_all; +} -- cgit v1.2.1