diff options
Diffstat (limited to 'bin/drakroam')
-rwxr-xr-x | bin/drakroam | 405 |
1 files changed, 253 insertions, 152 deletions
diff --git a/bin/drakroam b/bin/drakroam index 5511e76..a642aec 100755 --- a/bin/drakroam +++ b/bin/drakroam @@ -2,12 +2,14 @@ # drakroam: wireless network roaming GUI # Austin Acton, 2004 <austin@mandriva.org> -# Olivier Blin, 2005 <oblin@mandriva.com> +# Olivier Blin, 2005-2006 <oblin@mandriva.com> # 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; @@ -16,33 +18,104 @@ use interactive; use mygtk2; use ugtk2 qw(:create :helpers :wrappers); use Gtk2::SimpleList; -use network::ethernet; use network::monitor; +use network::signal_strength; use network::network; use network::tools; -use network::wireless; - +use network::connection; +use network::connection::wireless; +use network::connection::cellular_card; +use modules; + +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 $arg_ap; -/^--ap=(.*)/ and $arg_ap = $1 foreach @ARGV; +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 @connections; +my $connection; + +my %buttons; + +my $model = Gtk2::ListStore->new('Gtk2::Gdk::Pixbuf', 'Glib::String'); +my $connections_combo = Gtk2::ComboBox->new($model); +$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 @connections; + $model->set($model->append, + 0, gtknew('Pixbuf', file => $_->get_type_icon)->scale_simple($pixbuf_size, $pixbuf_size, 'hyper'), + 1, $_->get_description) foreach @connections; + my $index = $connection && eval { find_index { $_ == $connection } @connections }; + $connections_combo->set_active($index) if defined $index; +} -my $wireless_device = detect_devices::get_wireless_interface(); +sub get_connection() { + @connections or return; + my $index = $connections_combo->get_active; + defined $index && $connections[$index]; +} -unless ($wireless_device) { - ugtk2::err_dialog(N("Error"), N("You do not have any wireless interface. -Run the \"%s\" assistant from the Mandriva Linux Control Center", N("Set up a new network interface (LAN, ISDN, ADSL, ...)"))); - ugtk2::exit(0) if !$::testing; +sub prepare_connection() { + my @packages = $connection->can('get_packages') ? $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; + } + $connection->prepare_device; + $connection->setup_thirdparty($in) or return; + if ($connection->can("check_device") && !$connection->check_device) { + $in->ask_warn(N("Error"), $connection->{device}{error}); + return; + } + if ($connection->can('get_hardware_settings')) { + $connection->guess_hardware_settings if $connection->can('guess_hardware_settings'); + $in->ask_from_({ + title => "Network settings", + messages => N("Please enter settings for network") + }, $connection->get_hardware_settings) or return; + } + if ($connection->can('check_hardware')) { + my $_w = $in->wait_message('', N("Configuring device...")); + if (!$connection->check_hardware) { + $in->ask_warn(N("Error"), $connection->{hardware}{error}) if $connection->{hardware}{error}; + return; + } + } } -my $modules_conf = modules::any_conf->read; -my $dev = find { $_->[0] eq $wireless_device } network::ethernet::get_eth_cards($modules_conf); -my $wireless_module = $dev->[1]; +sub select_connection() { + $connection = get_connection(); + prepare_connection() if $connection; + update_on_connection_change(); +} + +sub update_on_connection_change() { + $buttons{refresh}->set_sensitive(to_bool($connection)); + update_networks(); +} my $net = {}; network::network::read_net_conf($net); -my $wireless_list = Gtk2::SimpleList->new( +my $networks_list = Gtk2::SimpleList->new( "AP" => "hidden", '' => "pixbuf", N("SSID") => "text", @@ -51,13 +124,39 @@ my $wireless_list = Gtk2::SimpleList->new( N("Encryption") => "text", N("Operating Mode") => "text", ); -$wireless_list->get_selection->set_mode('single'); +$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 } @connections; + $event_connection && $event_connection->get_status_message($status); + } +} -my ($dbus, $monitor); +my $dbus; eval { $dbus = dbus_object::system_bus() }; -eval { $monitor = network::monitor->new($dbus) } if $dbus; -my $wireless_networks = {}; -my $has_roaming; +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 = ( @@ -65,174 +164,176 @@ my %pixbufs = link_level => { map { $_ => gtkcreate_pixbuf('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 { + $_ => gtkcreate_pixbuf("encryption-$_-24.png"); + } qw(open weak strong) }, ); sub update_networks() { - ($wireless_networks, $has_roaming) = network::monitor::list_wireless($monitor, $wireless_device); - @{$wireless_list->{data}} = (); - - my $routes = network::tools::get_routes(); - my $connected = exists $routes->{$wireless_device}{network}; - - while (my ($ap, $network) = each(%$wireless_networks)) { - push @{$wireless_list->{data}}, [ - $ap, - $network->{current} ? $connected ? $pixbufs{state}{connected} : $pixbufs{state}{refresh} : undef, - $network->{essid} || exists $net->{wireless}{$ap} && $net->{wireless}{$ap}{WIRELESS_ESSID} || "[$ap]", - $pixbufs{link_level}{$network->{approx_level}}, - $network->{flags} ? $pixbufs{keyring} : undef, - $network->{flags}, - $network->{mode}, - ]; + @{$networks_list->{data}} = (); + + if ($connection) { + my $wait = $connection->network_scan_is_slow && $in->wait_message('', N("Scanning for networks...")); + $connection->{networks} = $connection->get_networks; + undef $wait; + + $connection->{network} ||= find { $connection->{networks}{$_}{current} } keys %{$connection->{networks}}; + + my $routes = network::tools::get_routes(); + my $interface = $connection->get_interface; + my $connected = exists $routes->{$interface}{network}; + + while (my ($ap, $network) = each(%{$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 ($connection->{network}) { + my $index = eval { find_index { $_->[0] eq $connection->{network} } @{$networks_list->{data}} }; + $networks_list->select($index) if defined $index; + } } - 1; -} -sub configure_ap { - my ($ap) = @_; - my $network = $wireless_networks->{$ap}; - my $essid = $network->{essid}; - my $wireless_net = - $essid && exists $net->{wireless}{$essid} ? - $net->{wireless}{$essid} : - exists $net->{wireless}{$ap} ? - $net->{wireless}{$ap} : - {}; - $wireless_net->{WIRELESS_ESSID} = $essid if $essid; + update_on_network_change(); +} - my ($wireless_enc_mode, $wireless_enc_key, $wireless_restricted); - ($wireless_enc_key, $wireless_restricted) = network::wireless::get_wep_key_from_iwconfig($wireless_net->{WIRELESS_ENC_KEY}); - $wireless_enc_mode = $network->{flags} =~ /wpa/i ? 'wpa-psk' : $network->{flags} =~ /wep/i ? $wireless_restricted ? 'restricted' : 'open' : 'none'; +sub load_settings() { + $connection->load_interface_settings; + $connection->guess_network_access_settings if $connection->can('guess_network_access_settings'); + $connection->guess_protocol($net) if $connection->can('guess_protocol'); + $connection->guess_access_settings if $connection->can('guess_access_settings'); + $connection->guess_address_settings if $connection->can('guess_address_settings'); + $connection->guess_hostname_settings if $connection->can('guess_hostname_settings'); + $connection->guess_network_control_settings if $connection->can('guess_network_control_settings'); + $connection->guess_control_settings; +} - my $dhcp = to_bool(!exists($wireless_net->{BOOTPROTO}) || $wireless_net->{BOOTPROTO} eq "dhcp"); +sub configure_network() { + load_settings(); $in->ask_from_({ - title => "Wireless settings", - messages => N("Please enter settings for wireless network \"%s\"", $essid || $ap) + title => "Network settings", + messages => N("Please enter settings for network") }, [ - { label => N("Network name (ESSID)"), val => \$wireless_net->{WIRELESS_ESSID}, disabled => sub { $essid } }, - { label => N("Encryption mode"), val => \$wireless_enc_mode, - list => [ keys %network::wireless::wireless_enc_modes ], - sort => 1, - format => sub { translate($network::wireless::wireless_enc_modes{$_[0]}) } }, - { label => N("Encryption key"), val => \$wireless_enc_key, disabled => sub { $wireless_enc_mode eq 'none' } }, - { text => N("Automatic IP (BOOTP/DHCP)"), val => \$dhcp, type => 'bool' }, - { label => N("IP address"), val => \$wireless_net->{IPADDR}, disabled => sub { $dhcp } }, - { label => N("DNS server"), val => \$wireless_net->{MS_DNS1}, disabled => sub { $dhcp } }, - { label => N("Gateway IP address"), val => \$wireless_net->{GATEWAY}, disabled => sub { $dhcp } }, + $connection->can('get_network_access_settings') ? ( + { label => $connection->get_network_access_settings_label, title => 1, advanced => 1 }, + @{$connection->get_network_access_settings}, + ) : (), + $connection->can('get_protocols') ? ( + @{$connection->get_protocol_settings}, + ) : (), + $connection->can('get_access_settings') ? ( + { label => $connection->get_access_settings_label, title => 1, advanced => 1 }, + @{$connection->get_access_settings} + ) : (), + $connection->can('get_address_settings') ? ( + { label => $connection->get_address_settings_label, title => 1, advanced => 1 }, + @{$connection->get_address_settings('show_all')} + ) : (), + $connection->can('get_network_control_settings') ? ( + @{$connection->get_network_control_settings} + ) : (), ], ) or return; - $wireless_net->{BOOTPROTO} = $dhcp ? 'dhcp' : 'static'; - $wireless_net->{WIRELESS_ENC_KEY} = $wireless_enc_key && network::wireless::convert_wep_key_for_iwconfig($wireless_enc_key, $wireless_enc_mode eq 'restricted'); - $wireless_net->{WIRELESS_MODE} = $network->{mode} eq 'Ad-Hoc' ? $network->{mode} : 'Managed'; - - if ($has_roaming || $wireless_enc_mode eq 'wpa-psk') { - $wireless_net->{WIRELESS_WPA_DRIVER} = network::wireless::wpa_supplicant_get_driver($wireless_module); - network::wireless::wpa_supplicant_add_network($wireless_net->{WIRELESS_ESSID}, $wireless_enc_mode, $wireless_enc_key); - } else { - delete $wireless_net->{WIRELESS_WPA_DRIVER}; - } - - my $ssid = $essid || $ap; - $net->{wireless}{$ssid} = $wireless_net; + $connection->install_packages($in) if $connection->can('install_packages'); + $connection->unload_connection if $connection->can('unload_connection'); - network::network::write_wireless_conf($ssid, $wireless_net); - - if ($has_roaming) { - #- this should be handled by the monitoring daemon instead - run_program::run('/usr/sbin/wpa_cli', 'reconfigure'); - } else { - overwrite_wireless_ifcfg($wireless_net); - } + my $modules_conf = modules::any_conf->read; + $connection->write_settings($net, $modules_conf); + $modules_conf->write; 1; } -sub overwrite_wireless_ifcfg { - my ($wireless_net) = @_; - my $ifcfg = $net->{ifcfg}{$wireless_device} ||= {}; - delete $ifcfg->{$_} foreach grep { /wireless/i } keys %$ifcfg; - put_in_hash($ifcfg, $wireless_net); - network::network::write_interface_conf($net, $wireless_device); -} - -sub wait_and_run_sub { - my ($time, $sub) = @_; - gtkset_mousecursor_wait(); - Glib::Timeout->add($time, sub { - $sub->(); - gtkset_mousecursor_normal(); - 0; - }); -} - -sub connect_to_ap { - my ($ap, $o_disable_configure) = @_; - my $network = $wireless_networks->{$ap}; - my $found; - - if ($network) { - my $wireless_net = !$has_roaming && ($net->{wireless}{$ap} || $net->{wireless}{$network->{essid}}); - if (defined $network->{id}) { - eval { $monitor->select_network($network->{id}) }; - $found = !$@; - $found or ugtk2::err_dialog(N("Wireless connection"), N("Unable to contact daemon")); - } elsif ($wireless_net) { - network::tools::stop_interface($wireless_device, 0); - overwrite_wireless_ifcfg($wireless_net); - network::tools::start_interface($wireless_device, 1); - $found = 1; +sub connect_to_network() { + if ($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 ($connection->can('get_networks')) { + load_settings(); + $connection->write_settings($net); } + $connection->prepare_connection if $connection->can('prepare_connection'); + $connection->disconnect; + $connection->connect($in, $net); + gtkset_mousecursor_normal($w->{window}->window); } +} - $found || !$o_disable_configure or return; - - if (!$found) { - if ($has_roaming) { - configure_ap($ap); - #- wait for wpa_supplicant to reconfigure the device - wait_and_run_sub(2000, sub { connect_to_ap($ap, 1) }); - return; - } else { - network::tools::stop_interface($wireless_device, 0); - configure_ap($ap); - network::tools::start_interface($wireless_device, 0); - } +sub select_network() { + if ($connection) { + my ($selected) = $networks_list->get_selected_indices; + $connection->{network} = defined $selected && $networks_list->{data}[$selected][0]; } - wait_and_run_sub(10000, \&update_networks); + update_on_network_change(); } -sub configure_selected() { - my ($selected) = $wireless_list->get_selected_indices or return; - configure_ap($wireless_list->{data}[$selected][0]); +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($connection && ($connection->get_status || $connection->{network})); + #- allow to configure only if a network is selected + $buttons{configure}->set_sensitive($connection && $connection->{network}); } -sub connect_to_selected() { - my ($selected) = $wireless_list->get_selected_indices or return; - connect_to_ap($wireless_list->{data}[$selected][0]); +sub toggle_would_disconnect() { + my $network = $connection && $connection->get_selected_network; + $connection && $connection->get_status && + (!$network || keys(%{$connection->{networks}}) <= 1 || $network->{current}); } -update_networks(); +sub toggle_connection() { + if (toggle_would_disconnect()) { + gtkset_mousecursor_wait($w->{window}->window); + my $_wait = $in->wait_message(N("Please wait"), N("Disconnecting...")); + $connection->disconnect; + gtkset_mousecursor_normal($w->{window}->window); + } elsif ($connection) { + $connection->{network} or return; + connect_to_network(); + } + update_on_network_change(); +} -my $w = ugtk2->new(N("Wireless connection")); gtkadd($w->{window}, gtknew('VBox', spacing => 5, children => [ - $::isEmbedded ? () : (0, Gtk2::Banner->new('/usr/share/mcc/themes/default/drakroam-mdk.png', N("Wireless connection"))), - 1, gtknew('HBox', spacing => 5, children => [ - 1, gtknew('ScrolledWindow', width => 500, height => 300, child => $wireless_list), - 0, gtknew('VButtonBox', layout => 'edge', children_loose => [ - gtknew('Button', text => N("Configure"), clicked => \&configure_selected), - gtknew('Button', text => N("Connect"), clicked => \&connect_to_selected), - gtknew('Button', text => N("Refresh"), clicked => \&update_networks), + $::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; -$arg_ap and Glib::Timeout->add(100, sub { connect_to_ap($arg_ap); 0 }); +@connections = map { $_->get_connections(automatic_only => 1) } @connection_types; +$connection = $args{interface} && find { $_->get_interface eq $args{interface} } @connections; +$connection ||= find { !$_->network_scan_is_slow } @connections; +update_connections_list(); +update_on_connection_change(); + +if ($args{ap} && $connection) { + $connection->{network} = $args{ap}; + $w->{window}->show_all; + connect_to_network(); +} $w->main; |