#!/usr/bin/perl # drakroam: wireless network roaming GUI # Austin Acton, 2004 # Olivier Blin, 2005-2006 # Licensed under the GPL 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 standalone; use common; use run_program; use detect_devices; use interactive; use mygtk2; use ugtk2 qw(:create :helpers :wrappers); use Gtk2::SimpleList; use network::monitor; use network::signal_strength; use network::network; use network::tools; use network::connection; use network::connection::wireless; use network::connection::cellular_card; use modules; my $droam = {}; my $title = N("Wireless connection"); my $icon = '/usr/share/mcc/themes/default/drakroam-mdk.png'; $ugtk2::wm_icon = $icon; my $w = ugtk2->new($title); #- so that transient_for is defined, for wait messages and popups to be centered $::main_window = $w->{real_window}; my $in = 'interactive'->vnew('su'); my %args = map { if_(/^--(\w+)=(.*)$/ && member($1, qw(ap interface)), $1 => $2) } @ARGV; my @connection_types = qw(network::connection::wireless network::connection::cellular_card); my %buttons; my $model = Gtk2::ListStore->new('Gtk2::Gdk::Pixbuf', 'Glib::String'); my $connections_combo = Gtk2::ComboBox->new($model); my $pix_r = Gtk2::CellRendererPixbuf->new; $connections_combo->pack_start($pix_r, 0,); $connections_combo->add_attribute($pix_r, pixbuf => 0); my $text_r = Gtk2::CellRendererText->new; $connections_combo->pack_start($text_r, 1); $connections_combo->add_attribute($text_r, text => 1); my $pixbuf_size = 32; my $empty_pixbuf = Gtk2::Gdk::Pixbuf->new('rgb', 1, 8, $pixbuf_size, $pixbuf_size); $empty_pixbuf->fill(0); sub update_connections_list() { $model->set($model->append, 0, $empty_pixbuf , 1, N("No device found")) unless @{$droam->{all_connections}}; $model->set($model->append, 0, gtknew('Pixbuf', file => $_->get_type_icon)->scale_simple($pixbuf_size, $pixbuf_size, 'hyper'), 1, $_->get_description) foreach @{$droam->{all_connections}}; my $index = $droam->{connection} && eval { find_index { $_ == $droam->{connection} } @{$droam->{all_connections}} }; $connections_combo->set_active($index) if defined $index; } sub get_connection() { @{$droam->{all_connections}} or return; my $index = $connections_combo->get_active; defined $index && $droam->{all_connections}[$index]; } sub prepare_connection() { my @packages = $droam->{connection}->can('get_packages') ? $droam->{connection}->get_packages : (); if (@packages && !$in->do_pkgs->install(@packages)) { $in->ask_warn(N("Error"), N("Could not install the packages (%s)!", join(', ', @packages))); return; } $droam->{connection}->prepare_device; $droam->{connection}->setup_thirdparty($in) or return; if ($droam->{connection}->can("check_device") && !$droam->{connection}->check_device) { $in->ask_warn(N("Error"), $droam->{connection}{device}{error}); return; } if ($droam->{connection}->can('get_hardware_settings')) { $droam->{connection}->guess_hardware_settings if $droam->{connection}->can('guess_hardware_settings'); $in->ask_from_({ title => "Network settings", messages => N("Please enter settings for network") }, $droam->{connection}->get_hardware_settings) or return; } if ($droam->{connection}->can('check_hardware')) { my $_w = $in->wait_message('', N("Configuring device...")); if (!$droam->{connection}->check_hardware) { $in->ask_warn(N("Error"), $droam->{connection}{hardware}{error}) if $droam->{connection}{hardware}{error}; return; } } } sub select_connection() { $droam->{connection} = get_connection(); prepare_connection() if $droam->{connection}; update_on_connection_change(); } sub update_on_connection_change() { $buttons{refresh}->set_sensitive(to_bool($droam->{connection})); update_networks(); } my $net = {}; network::network::read_net_conf($net); my $networks_list = Gtk2::SimpleList->new( "AP" => "hidden", '' => "pixbuf", N("SSID") => "text", N("Signal strength") => "pixbuf", '' => "pixbuf", N("Encryption") => "text", N("Operating Mode") => "text", ); $networks_list->get_selection->set_mode('single'); my $status_bar = Gtk2::Statusbar->new; my $status_bar_cid = $status_bar->get_context_id("Network event"); sub get_network_event_message { my ($member, @args) = @_; #- FIXME: the hostname.d script and s2u use a different D-Bus interface if ($member eq 'hostname') { my ($hostname) = @args; N("Hostname changed to \"%s\"", $hostname); } elsif ($member eq 'status') { my ($status, $interface) = @args; my $event_connection = find { $_->get_interface eq $interface } @{$droam->{all_connections}}; $event_connection && $event_connection->get_status_message($status); } } my $dbus; eval { $dbus = dbus_object::system_bus() }; if ($dbus) { eval { $net->{monitor} = network::monitor->new($dbus) }; $dbus->{connection}->add_filter(sub { my ($_con, $msg) = @_; my $member = $msg->get_member; my $message = get_network_event_message($member, $msg->get_args_list) or return; my $m_id = $status_bar->push($status_bar_cid, $message); Glib::Timeout->add(20000, sub { $status_bar->remove($status_bar_cid, $m_id); 0 }); update_networks() if $member eq 'status'; }); $dbus->{connection}->add_match("type='signal',interface='com.mandriva.network'"); dbus_object::set_gtk2_watch_helper($dbus); } my %pixbufs = ( state => { map { $_ => gtkcreate_pixbuf($_) } qw(connected disconnected refresh) }, link_level => { map { $_ => gtkcreate_pixbuf('wifi-' . sprintf('%03d', $_) . '.png')->scale_simple(24, 24, 'hyper'); } qw(20 40 60 80 100) }, encryption => { map { $_ => gtkcreate_pixbuf("encryption-$_-24.png"); } qw(open weak strong) }, ); sub update_networks() { @{$networks_list->{data}} = (); if ($droam->{connection}) { my $wait = $droam->{connection}->network_scan_is_slow && $in->wait_message('', N("Scanning for networks...")); $droam->{connection}{networks} = $droam->{connection}->get_networks; undef $wait; $droam->{connection}{network} ||= find { $droam->{connection}{networks}{$_}{current} } keys %{$droam->{connection}{networks}}; my $routes = network::tools::get_routes(); my $interface = $droam->{connection}->get_interface; my $connected = exists $routes->{$interface}{network}; while (my ($ap, $network) = each(%{$droam->{connection}{networks}})) { push @{$networks_list->{data}}, [ $ap || $network->{name}, $network->{current} ? $connected ? $pixbufs{state}{connected} : $pixbufs{state}{refresh} : undef, !$network->{essid} && exists $net->{wireless}{$ap} && $net->{wireless}{$ap}{WIRELESS_ESSID} || $network->{name}, network::signal_strength::get_strength_icon($network), $pixbufs{encryption}{$network->{flags} =~ /WPA/i ? 'strong' : $network->{flags} =~ /WEP/i ? 'weak' : 'open'}, $network->{flags}, $network->{mode}, ]; } if ($droam->{connection}{network}) { my $index = eval { find_index { $_->[0] eq $droam->{connection}{network} } @{$networks_list->{data}} }; $networks_list->select($index) if defined $index; } } update_on_network_change(); } sub load_settings() { $droam->{connection}->load_interface_settings; $droam->{connection}->guess_network_access_settings if $droam->{connection}->can('guess_network_access_settings'); $droam->{connection}->guess_protocol($net) if $droam->{connection}->can('guess_protocol'); $droam->{connection}->guess_access_settings if $droam->{connection}->can('guess_access_settings'); $droam->{connection}->guess_address_settings if $droam->{connection}->can('guess_address_settings'); $droam->{connection}->guess_hostname_settings if $droam->{connection}->can('guess_hostname_settings'); $droam->{connection}->guess_network_control_settings if $droam->{connection}->can('guess_network_control_settings'); $droam->{connection}->guess_control_settings; } sub configure_network() { load_settings(); $in->ask_from_({ title => "Network settings", messages => N("Please enter settings for network") }, [ $droam->{connection}->can('get_network_access_settings') ? ( { label => $droam->{connection}->get_network_access_settings_label, title => 1, advanced => 1 }, @{$droam->{connection}->get_network_access_settings}, ) : (), $droam->{connection}->can('get_protocols') ? ( @{$droam->{connection}->get_protocol_settings}, ) : (), $droam->{connection}->can('get_access_settings') ? ( { label => $droam->{connection}->get_access_settings_label, title => 1, advanced => 1 }, @{$droam->{connection}->get_access_settings} ) : (), $droam->{connection}->can('get_address_settings') ? ( { label => $droam->{connection}->get_address_settings_label, title => 1, advanced => 1 }, @{$droam->{connection}->get_address_settings('show_all')} ) : (), $droam->{connection}->can('get_network_control_settings') ? ( @{$droam->{connection}->get_network_control_settings} ) : (), ], ) or return; $droam->{connection}->install_packages($in) if $droam->{connection}->can('install_packages'); $droam->{connection}->unload_connection if $droam->{connection}->can('unload_connection'); my $modules_conf = modules::any_conf->read; $droam->{connection}->write_settings($net, $modules_conf); $modules_conf->write; 1; } sub connect_to_network() { if ($droam->{connection}->selected_network_is_configured || configure_network()) { gtkset_mousecursor_wait($w->{window}->window); my $_wait = $in->wait_message(N("Please wait"), N("Connecting...")); #- settings have to be rewritten only if they are impacted by choices from the main window if ($droam->{connection}->can('get_networks')) { load_settings(); $droam->{connection}->write_settings($net); } $droam->{connection}->prepare_connection if $droam->{connection}->can('prepare_connection'); $droam->{connection}->disconnect; $droam->{connection}->connect($in, $net); gtkset_mousecursor_normal($w->{window}->window); } } sub select_network() { if ($droam->{connection}) { my ($selected) = $networks_list->get_selected_indices; $droam->{connection}{network} = defined $selected && $networks_list->{data}[$selected][0]; } update_on_network_change(); } sub update_on_network_change() { $buttons{connect}->set_label(toggle_would_disconnect() ? N("Disconnect") : N("Connect")); #- always allow to disconnect if connected $buttons{connect}->set_sensitive($droam->{connection} && ($droam->{connection}->get_status || $droam->{connection}{network})); #- allow to configure only if a network is selected $buttons{configure}->set_sensitive($droam->{connection} && $droam->{connection}{network}); } sub toggle_would_disconnect() { my $network = $droam->{connection} && $droam->{connection}->get_selected_network; $droam->{connection} && $droam->{connection}->get_status && (!$network || keys(%{$droam->{connection}{networks}}) <= 1 || $network->{current}); } sub toggle_connection() { if (toggle_would_disconnect()) { gtkset_mousecursor_wait($w->{window}->window); my $_wait = $in->wait_message(N("Please wait"), N("Disconnecting...")); $droam->{connection}->disconnect; gtkset_mousecursor_normal($w->{window}->window); } elsif ($droam->{connection}) { $droam->{connection}{network} or return; connect_to_network(); } update_on_network_change(); } gtkadd($w->{window}, gtknew('VBox', spacing => 5, children => [ $::isEmbedded ? () : (0, Gtk2::Banner->new($icon, $title)), 0, gtknew('HBox', children_tight => [ gtknew('Label_Left', text => N("Device: "), alignment => [ 0.5, 0.5 ]), gtksignal_connect($connections_combo, changed => \&select_connection) ]), 1, gtknew('ScrolledWindow', width => 500, height => 300, child => $networks_list), 0, gtknew('HButtonBox', layout => 'edge', children_loose => [ $buttons{configure} = gtknew('Button', text => N("Configure"), clicked => \&configure_network), $buttons{connect} = gtknew('Button', relief => 'half', clicked => \&toggle_connection), $buttons{refresh} = gtknew('Button', text => N("Refresh"), clicked => \&update_networks), gtknew('Button', text => N("Quit"), clicked => sub { Gtk2->main_quit }) ]), 0, $status_bar, ]), ); $networks_list->get_selection->signal_connect('changed' => \&select_network); $w->show; @{$droam->{all_connections}} = map { $_->get_connections(automatic_only => 1) } @connection_types; $droam->{connection} = $args{interface} && find { $_->get_interface eq $args{interface} } @{$droam->{all_connections}}; $droam->{connection} ||= find { !$_->network_scan_is_slow } @{$droam->{all_connections}}; update_connections_list(); update_on_connection_change(); if ($args{ap} && $droam->{connection}) { $droam->{connection}{network} = $args{ap}; $w->{window}->show_all; connect_to_network(); } $w->main;