App-USBKeyCopyCon

 view release on metacpan or  search on metacpan

lib/App/USBKeyCopyCon.pm  view on Meta::CPAN


    return if $> == 0;

    my $path = $self->find_command('gksudo') || $self->find_command('sudo');
    if($path) {
        $self->sudo_path($path);
        return;
    }

    die "You must either run this program as root or install sudo\n";
}


sub disable_automount {
    my $self = shift;

    my $state = `gconftool-2 --get $gconf_automount_path 2>/dev/null`;
    return if !defined($state) or $? != 0;

    chomp($state);
    $self->automount_state($state);
    system("gconftool-2 --type bool --set $gconf_automount_path false 2>/dev/null");
}


sub restore_automount {
    my $self = shift;

    my $state = $self->automount_state or return;
    system("gconftool-2 --type bool --set $gconf_automount_path $state 2>/dev/null");

}


sub build_ui {
    my $self = shift;

    my $window = Gtk2::Window->new;
    $self->app_win($window);
    $window->signal_connect(destroy => sub { Gtk2->main_quit; });
    $window->set_title('USB Key Copying Console');
    $window->set_default_size(850, 250);

    my $vbox = Gtk2::VBox->new(FALSE);
    $vbox->pack_start($self->build_menu,     FALSE, FALSE, 0);
    $vbox->pack_start($self->build_filters,  FALSE, FALSE, 0);
    $vbox->pack_start(Gtk2::HSeparator->new, FALSE, TRUE,  0);
    $vbox->pack_start($self->build_key_rack, FALSE, FALSE, 0);
    $vbox->pack_start($self->build_console,  TRUE,  TRUE,  0);
    $window->add($vbox);

    $window->show_all;
}


sub init_dbus_watcher {
    my $self = shift;

    my $bus = Net::DBus::GLib->system;

    my $hal = $bus->get_service("org.freedesktop.Hal");

    my $manager = $hal->get_object(
        "/org/freedesktop/Hal/Manager", "org.freedesktop.Hal.Manager"
    );
    $self->hal($manager);

    $manager->connect_to_signal('DeviceAdded', sub {
        $self->hal_device_added(@_);
    });

    $manager->connect_to_signal('DeviceRemoved', sub {
        $self->hal_device_removed(@_);
    });
}


sub require_master_key {
    my $self = shift;

    if(not $self->reader_script) {
        return $self->ready_to_write;
    }
    $self->current_state('MASTER-WAIT');
    $self->disable_filter_inputs;
    $self->say("Waiting for USB master key ...\n");
}


sub hal_device_added {
    my($self, $target_udi) = @_;

    return unless $target_udi =~ /storage/;
    my $prop = $self->hal_device_properties($target_udi) or return;

    if($self->current_state eq 'MASTER-WAIT') {
        $self->start_master_read($prop);
        return;
    }
    elsif($self->current_state eq 'COPYING') {
        if($self->match_device_filter($prop)) {
            $self->say("Device added: $prop->{block_device}\n");
        }
        else {
            $self->say(" - device ignored\n");
            $prop->{ignored} = 1;
        }
        #$self->say(Dumper($prop));
        $self->add_key_to_rack($prop);
    }
}


sub hal_device_removed {
    my($self, $target_udi) = @_;

    return unless $target_udi =~ /storage/;

    my $state = $self->current_state;
    if($state eq 'MASTER-COPIED') {
        if($self->master_info->{udi} eq $target_udi) {
            $self->ready_to_write;
        }
    }

lib/App/USBKeyCopyCon.pm  view on Meta::CPAN

        sub { $self->on_copier_pipe_read(@_); },
        $key_info->{udi}
    );
    $key_info->{pid}    = $pid;
    $key_info->{fh}     = $rd;
    $key_info->{output} = '';
    $key_info->{status} = 0;
}


sub on_copier_pipe_read {
    my($self, $fd, $cond, $udi) = @_;

    my $key_info = $self->current_keys->{$udi} or return FALSE;
    my $fh = $key_info->{fh};
    my $buffer;
    if(sysread($fh, $buffer, 100000)) {
        $key_info->{output} .= $buffer;
        if($key_info->{output} =~ m/\A.*^\{(\d+)\/(\d+)\}/sm) {
            $self->update_key_progress($udi, int(9 * $1 / $2));
        }
        return TRUE;
    }
    close($fh);
    delete $key_info->{fh};
    return FALSE;
}


sub remove_key_from_rack {
    my($self, $udi) = @_;

    my $key_info = delete $self->current_keys->{$udi} or return;
    $self->key_rack->remove($key_info->{widget});
    return;
}


sub update_key_progress {
    my($self, $udi, $status) = @_;

    $status = -1 if !defined $status or $status < -1 or $status > 10;

    my $key_info = $self->current_keys->{$udi} or return;
    $key_info->{status} = $status;
    $key_info->{icon_widget}->set_from_pixbuf(
        App::USBKeyCopyCon::Chrome::usb_icon($status)
    );
}


sub on_menu_file_new {
    my $self = shift;
    $self->require_master_key;
}


sub on_menu_file_quit {
    my $self = shift;
    # TODO: check for work in progress
    # TODO: check if desktop automount should be re-enabled
    Gtk2->main_quit;
}


sub on_menu_edit_preferences {
    my $self = shift;
    $self->say("Edit>Preferences - not implemented\n");
}


sub on_menu_help_about {
    my $self = shift;

    my $dialog = Gtk2::Dialog->new(
        'About: usb-key-copy-con',
        $self->app_win,
        [qw/modal destroy-with-parent/],
        'gtk-close' => 'ok',
    );
    $dialog->set_default_size (90, 80);

    my $panel = Gtk2::VBox->new(FALSE, 12);

    my $title = Gtk2::Label->new;
    $title->set_markup("<span font_desc='sans 20'> USB Key Copy Console </span>");
    $title->set_selectable(TRUE);
    $panel->pack_start($title, FALSE, FALSE, 10);

    my $version = Gtk2::Label->new;
    $version->set_markup("<span font_desc='sans 16'>Version: $VERSION</span>");
    $version->set_selectable(TRUE);
    $panel->pack_start($version, FALSE, FALSE, 0);

    my $author = Gtk2::Label->new;
    my $detail = '(c) 2009 Grant McLean &lt;grantm@cpan.org&gt;';
    $author->set_markup("  <span font_desc='sans 10'>$detail</span>  ");
    $author->set_selectable(TRUE);
    $panel->pack_start($author, FALSE, FALSE, 10);

    $dialog->vbox->pack_start($panel, FALSE, FALSE, 4);
    $dialog->show_all;

    $dialog->run;

    $dialog->destroy;
}


sub build_menu {
    my $self = shift;

    foreach my $item (@menu_entries) {
        if(exists $item->[5]) {
            my $action = 'on_menu_' . $item->[5];
            $item->[5] = sub { $self->$action(@_) };
        }
    }
    my $actions = Gtk2::ActionGroup->new("Actions");
    $actions->add_actions(\@menu_entries, undef);

lib/App/USBKeyCopyCon.pm  view on Meta::CPAN

    $self->restore_automount;
    $self->clean_temp_dir;
}


1;

__END__

=head1 ATTRIBUTES

The application object has the following attributes (with correspondingly named
accessor methods):

=over 4

=item app_win

The main Gtk2::Window object.

=item automount_state

Stores the enabled state ('true' or 'false') of the GNOME/Nautilus media
automount option.  The function will be disabled on startup and this value will
be restored on exit.

=item capacity_combo

The Gtk2::ComboBox object for the device filter 'Capacity' drop-down menu.

=item capacity_entry

The Gtk2::Entry object for the device filter 'Capacity' text entry box.

=item console

The Gtk2::TextView object used for writing output messages.

=item current_keys

A hash for tracking which (non-master) keys are currently inserted and what
stage each copy process is at.  The hash key is the device 'UDI' and the value
is a hash of device dtails .

=item current_state

Used to control which mode the application is in:

  MASTER-WAIT    waiting for the user to insert the master key
  MASTER-COPYING waiting for the master key 'reader' script to complete
  MASTER-COPIED  waiting for the user to remove the master key
  COPYING        waiting for the user to insert blank keys

=item exit_status

Used by a SIGCHLD handler to track the exit status of the copy scripts.  The
key is a process ID and the value is the exist status returned by C<wait>.

=item hal

The DBus object ('org.freedesktop.Hal.Manager') from which device add/remove
events are received.

=item key_rack

The Gtk2::HBox object containing the widgets representing currently inserted
keys.

=item master_info

A hash of device details for the 'master' USB key.

=item master_root

The path to the temp directory containing the copy of the master key.

=item mount_dir

The path to the temp directory containing temporary mount points.

The volume label read from the master key and to be applied to the copies.

=item options

A hash of option name/value pairs passed in from comman-line arguments by the
wrapper script.

=item profiles

A hash of details of known profiles.  Used to populate the profile drop-down
menu on the confirm master key dialog.

=item selected_profile

The name of the copying profile which will be used to select reader/writer
scripts.

=item selected_sound

Pathname of the currently selected sound file, to be played when copying is
complete.

=item sudo_path

If the script was run by a non-root user and sudo is available, this string
will be populated with the pathname of either C<gksudo> or C<sudo>.  When
running the read/writer scripts the string will be prepended onto the commands.

=item temp_root

The temp directory selected by the user.  The application will create a
subdirectory for the copy of the master key and for temporary mount points.

=item vendor_combo

The Gtk2::ComboBox object for the device filter 'Vendor' drop-down menu.

=item vendor_entry

The Gtk2::Entry object for the device filter 'Vendor' text entry box.



( run in 1.835 second using v1.01-cache-2.11-cpan-13bb782fe5a )