summaryrefslogtreecommitdiffstats
path: root/perl-install/common.pm
blob: 3b4582b9de7ed32ac2ab6624373779499bf9dc1f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
package common; # $Id: common.pm 245955 2008-09-18 14:19:04Z pixel $

use MDK::Common;
use diagnostics;
use strict;
BEGIN { eval { require Locale::gettext } } #- allow common.pm to be used in drakxtools-backend without perl-Locale-gettext

use log;
use run_program;

use Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw($SECTORSIZE N P N_ check_for_xserver files_exist formatTime MB formatXiB get_parent_uid is_running makedev mageia_release mageia_release_info removeXiBSuffix require_root_capability setVirtual set_alternative set_l10n_sort set_permissions to_utf8  translate unmakedev);

# perl_checker: RE-EXPORT-ALL
push @EXPORT, @MDK::Common::EXPORT;


$::prefix ||= ""; # no warning

#-#####################################################################################
#- Globals
#-#####################################################################################
our $SECTORSIZE  = 512;

#-#####################################################################################
#- Functions
#-#####################################################################################

sub P {
    my ($s_singular, $s_plural, $nb, @para) = @_; 
    sprintf(translate($s_singular, $s_plural, $nb), @para);
}

sub N {
    my ($s, @para) = @_; 
    sprintf(translate($s), @para);
}
sub N_ { $_[0] }


sub makedev { ($_[0] << 8) | $_[1] }
sub unmakedev { $_[0] >> 8, $_[0] & 0xff }

sub translate_real {
    my ($s, $o_plural, $o_nb) = @_;
    $s or return '';
    my $s2;
    foreach (@::textdomains, 'libDrakX') {
     if ($o_plural) {
         $s2 = Locale::gettext::dngettext($_, $s, $o_plural, $o_nb);
     } else {
         $s2 = Locale::gettext::dgettext($_, $s);
     }
	# when utf8 pragma is in use, Locale::gettext() returns an utf8 string not tagged as such:
	c::set_tagged_utf8($s2) if !utf8::is_utf8($s2) && utf8::is_utf8($s);
	return $s2 if $s ne $s2 && $s2 ne $o_plural;
    }
    # didn't lookup anything or locale is "C":
    $s2;
}

sub remove_translate_context {
    my ($s) = @_;
    #- translation with context, kde-like 
    $s =~ s/^_:.*\n//;
    $s;
}

sub translate {
    my $s = translate_real(@_);
    $::one_message_has_been_translated ||= join(':', (caller(1))[1,2]); #- see mygtk2.pm
    remove_translate_context($s);
}

sub from_utf8 {
    my ($s) = @_;
    Locale::gettext::iconv($s, "utf-8", undef); #- undef = locale charmap = nl_langinfo(CODESET)
}
sub to_utf8 { 
    my ($s) = @_;
    my $str = Locale::gettext::iconv($s, undef, "utf-8"); #- undef = locale charmap = nl_langinfo(CODESET)
    c::set_tagged_utf8($str);
    $str;
}

#- This is needed because text printed by Gtk2 will always be encoded
#- in UTF-8;
#- we first check if LC_ALL is defined, because if it is, changing
#- only LC_COLLATE will have no effect.
sub set_l10n_sort() {
    my $collation_locale = $ENV{LC_ALL};
    if (!$collation_locale) {
        $collation_locale = c::setlocale(c::LC_COLLATE());
        $collation_locale =~ /UTF-8/ or c::setlocale(c::LC_COLLATE(), "$collation_locale.UTF-8");
    }
}


sub setVirtual {
    my ($vt_number) = @_;
    my $vt = '';
    sysopen(my $C, "/dev/console", 2) or die "failed to open /dev/console: $!";
    ioctl($C, c::VT_GETSTATE(), $vt) &&
      ioctl($C, c::VT_ACTIVATE(), $vt_number) &&
	ioctl($C, c::VT_WAITACTIVE(), $vt_number) or die "setVirtual failed";
    unpack "S", $vt;
}

sub nonblock {
    my ($F) = @_;
    fcntl($F, c::F_SETFL(), fcntl($F, c::F_GETFL(), 0) | c::O_NONBLOCK()) or die "cannot fcntl F_SETFL: $!";
}

#- return a size in sector
#- ie MB(1) is 2048 sectors, which is 1MB
sub MB {
    my ($nb_MB) = @_;
    $nb_MB * 2048;
}

sub removeXiBSuffix {
    local $_ = shift;

    /(\d+)\s*kB?$/i and return $1 * 1024;
    /(\d+)\s*MB?$/i and return $1 * 1024 * 1024;
    /(\d+)\s*GB?$/i and return $1 * 1024 * 1024 * 1024;
    /(\d+)\s*TB?$/i and return $1 * 1024 * 1024 * 1024 * 1024;
    $_;
}
sub formatXiB {
    my ($newnb, $o_newbase) = @_;
    my $newbase = $o_newbase || 1;
    my $sign = $newnb < 0 ? -1 : 1;
    $newnb = abs(int($newnb));
    my ($nb, $base);
    my $decr = sub { 
	($nb, $base) = ($newnb, $newbase);
	$base >= 1024 ? ($newbase = $base / 1024) : ($newnb = $nb / 1024);
    };
    my $suffix;
    foreach (N("B"), N("KB"), N("MB"), N("GB"), N("TB")) {
	$decr->(); 
	if ($newnb < 1 && $newnb * $newbase < 1) {
	    $suffix = $_;
	    last;
	}
    }
    my $v = $nb * $base;
    my $s = $v < 10 && int(10 * $v - 10 * int($v));
    int($v * $sign) . ($s ? "." . abs($s) : '') . ($suffix || N("TB"));
}

sub formatTime {
    my ($s, $m, $h) = gmtime($_[0]);
    if ($h) {
	sprintf "%02d:%02d", $h, $m;
    } elsif ($m > 1) {
	N("%d minutes", $m);
    } elsif ($m == 1) {
	N("1 minute");
    } else {
	N("%d seconds", $s);
    }
}

sub expand_symlinks_with_absolute_symlinks_in_prefix {
    my ($prefix, $link) = @_;

    my ($first, @l) = split '/', $link;
    $first eq '' or die "expand_symlinks: $link is relative\n";
    my ($f, $l);
    foreach (@l) {
	$f .= "/$_";
	while ($l = readlink "$prefix$f") {
	    $f = $l =~ m!^/! ? $l : MDK::Common::File::concat_symlink($f, "../$l");
	}
    }
    "$prefix$f";
}

sub expand_symlinks_but_simple {
    my ($f) = @_;
    my $link = readlink($f);
    my $f2 = expand_symlinks($f);
    if ($link && $link !~ m|/|) {
	# put back the last simple symlink
	$f2 =~ s|\Q$link\E$|basename($f)|e;
    }
    $f2;
}

sub sync { &MDK::Common::System::sync }

BEGIN { undef *formatError }
sub formatError {
    my ($err) = @_;
    ref($err) eq 'SCALAR' and $err = $$err;
    log::l("error: $err");
    &MDK::Common::String::formatError($err);
}

sub group_by(&@) {
    my $f = shift;
    @_ or return;
    my $e = shift;
    my @l = my $last_l = [$e];
    foreach (@_) {
	if ($f->($e, $_)) {
	    push @$last_l, $_;
	} else {
	    push @l, $last_l = [$_];
	    $e = $_;
	}
    }
    @l;
}

# Group the list by n. Returns a reference of lists of length n
sub group_n_lm {
    my $n = shift;
    my @l;
    push @l, [ splice(@_, 0, $n) ] while @_;
    @l;
}

sub join_lines {
    my @l;
    my $s;
    foreach (@_) {
	if (/^\s/) {
	    $s .= $_;
	} else {
	    push @l, $s if $s;
	    $s = $_;
	}
    }
    @l, if_($s, $s);
}


sub read_alternative {
    my ($name) = @_;
    my $alt = readlink("$::prefix/etc/alternatives/$name");
    $alt && $::prefix . $alt;
}

sub set_alternative {
    my ($command, $executable) = @_;

    #- check the existance of $executable as an alternative for $command
    #- (is this needed???)
    run_program::rooted_get_stdout($::prefix, 'update-alternatives', '--display', $command) =~ /^\Q$executable /m or return;

    #- this does not handle relative symlink, but neither does update-alternatives ;p
    symlinkf $executable, "$::prefix/etc/alternatives/$command";
}

sub files_exist { and_(map { -f "$::prefix$_" } @_) }

sub open_file {
    my ($file) = @_;
    my $F;
    open($F, $file) ? $F : do { log::l("Cannot open $file: $!"); undef };
}


sub secured_file {
    my ($f) = @_;
    c::is_secure_file($f) or die "cannot ensure a safe $f";
    $f;
}

sub unwind_protect {
    my ($to_do, $cleanup) = @_;
    my @l = eval { $to_do->() };
    my $err = $@;
    $cleanup->();
    $err and die $err;
    wantarray() ? @l : $l[0];
}

sub with_private_tmp_file {
    my ($file, $content, $f) = @_;

    my $prev_umask = umask 077;

    unwind_protect(sub { 
	MDK::Common::File::secured_output($file, $content);
	$f->($file);
    }, sub {
	umask $prev_umask;
	unlink $file;
    });
}

sub chown_ {
    my ($b_recursive, $name, $group, @files) = @_;

    my ($uid, $gid) = (getpwnam($name) || $name, getgrnam($group) || $group);
      
    require POSIX;
    my $chown; $chown = sub {
	foreach (@_) {
	    POSIX::lchown($uid, $gid, $_) or die "chown of file $_ failed: $!\n";
	    ! -l $_ && -d $_ && $b_recursive and &$chown(glob_($_));
	}
    };
    $chown->(@files);
}


sub set_permissions {
    my ($file, $perms, $o_owner, $o_group) = @_;
    # We only need to set the permissions during installation to be able to
    # print test pages. After installation udev does the business automatically.
    return 1 unless $::isInstall;
    if ($o_owner || $o_group) {
	$o_owner ||= (lstat($file))[4];
	$o_group ||= (lstat($file))[5];
	chown_(0, $o_owner, $o_group, $file);
    }
    chmod(oct($perms), $file) or die "chmod of file $file failed: $!\n";
}

sub is_running {
    my ($name, $o_user) = @_;
    my $user = $o_user || $ENV{USER};
    foreach (`ps -o '%P %p %c' -u $user`) {
	my ($ppid, $pid, $n) = /^\s*(\d+)\s+(\d+)\s+(.*)/;
	return $pid if $ppid != 1 && $pid != $$ && $n eq $name;
    }
}

sub parse_release_file {
    my ($prefix, $f, $part) = @_;
    chomp(my $s = cat_("$prefix$f"));
    my $version = $s =~ s/\s+release\s+(\S+)// && $1;
    my $arch = $s =~ s/\s+for\s+(\S+)// && $1;
    log::l("find_root_parts found $part->{device}: $s for $arch" . ($f !~ m!/etc/! ? " in special release file $f" : ''));
    { release => $s, version => $version, 
      release_file => $f, part => $part, arch => $arch };
}

sub release_file {
    my ($o_dir) = @_;
    my @names = ('mageia-release', 'mandrakelinux-release', 'mandrake-release', 'conectiva-release', 'release', 'redhat-release', 'fedora-release', 'SuSE-release');
    find { -r "$o_dir$_" } (
	(map { "/root/drakx/$_.upgrading" } @names), 
	(map { "/etc/$_" } @names),
    );
}

sub mageia_release_info() {
    parse_LDAP_namespace_structure(cat_('/etc/product.id'));
}

sub parse_LDAP_namespace_structure {
    my ($s) = @_;
    my %h = map { if_(/(.*?)=(.*)/, $1 => $2) } split(',', $s);
    \%h;
}

sub mageia_release {
    my ($o_dir) = @_;
    my $f = release_file($o_dir);
    $f && chomp_(cat_("$o_dir$f"));
}

sub get_parent_uid() {
    cat_('/proc/' . getppid() . '/status') =~ /Uid:\s*(\d+)/ ? $1 : undef;
}

sub wrap_command_for_root {
    my ($name, @args) = @_;
    ([ 'consolehelper', $name ], @args);
}

sub require_root_capability() {
    return if $::testing || !$>; # we're already root

    my ($command, @args) = wrap_command_for_root($0, @ARGV);
    exec { $command->[0] } $command->[1], @args or die N("command %s missing", $command->[0]);

    # still not root ?
    die "you must be root to run this program" if $>;
}

sub check_for_xserver() {
    if (!defined $::xtest) {
	$::xtest = 0;         
	eval { 
	    require xf86misc::main; 
	    $::xtest = xf86misc::main::Xtest($ENV{DISPLAY});
	} if $ENV{DISPLAY};
    }
    return $::xtest;
}

#- special unpack
#- - returning an array refs for each element like "s10"
#- - handling things like s10* at the end of the format
sub unpack_with_refs {
    my ($format, $s) = @_;
    my $initial_format = $format;
    my @r;
    while ($format =~ s/\s*(\w(\d*))(\*?)\s*//) {
	my ($sub_format, $nb, $many) = ($1, $2, $3);
	$many && $format and internal_error("bad * in the middle of format in $initial_format");

	my $done = $many && !length($s);
	while (!$done) {
	    my @l = unpack("$sub_format a*", $s);
	    $s = pop @l;
	    push @r, $nb ? \@l : @l;
	    $done = !$many || !length($s);
	}
    }
    @r;
}

#- used in userdrake and mdkonline
sub md5file {
    require Digest::MD5;
    my @md5 = map {
        my $sum;
	if (open(my $FILE, $_)) {
            binmode($FILE);
            $sum = Digest::MD5->new->addfile($FILE)->hexdigest;
            close($FILE);
        }
        $sum;
    } @_;
    return wantarray() ? @md5 : $md5[0];
}

sub load_modules_from_base {
    my ($base) = @_;
    $base =~ s|::|/|g;
    my $base_file = $base . ".pm";
    require $base_file;
    my ($inc_path) = substr($INC{$base_file}, 0, -length($base_file));
    my @files = map { substr($_, length($inc_path)) } glob_($inc_path . $base . '/*.pm');
    require $_ foreach @files;
    #- return the matching modules list
    map { local $_ = $_; s|/|::|g; s|\.pm$||g; $_ } @files;
}

sub get_alternatives {
    my ($name) = @_;

    my $dir = $::prefix . '/var/lib/rpm/alternatives';
    my ($state, $main_link, @l) = chomp_(cat_("$dir/$name")) or return;
    my @slaves;
    while (@l && $l[0] ne '') {
	my ($name, $link) = splice(@l, 0, 2);
	push @slaves, { name => $name, link => $link };
    }
    shift @l; #- empty line
    my @alternatives;
    while (@l && $l[0] ne '') {
	my ($file, $weight, @slave_files) = splice(@l, 0, 2 + @slaves);
	
	push @alternatives, { file => $file, weight => $weight, slave_files => \@slave_files };
    }
    { name => $name, link => $main_link, state => $state, slaves => \@slaves, alternatives => \@alternatives };
}

sub symlinkf_update_alternatives {
    my ($name, $wanted_file) = @_;
    run_program::rooted($::prefix, 'update-alternatives', '--set', $name, $wanted_file);
}

sub update_gnomekderc_no_create {
    my ($file, $category, %subst_) = @_;
    if (-e $file) {
	update_gnomekderc($file, $category, %subst_);
    }
}

1;
n>; use Exporter; our @ISA = qw(Exporter); our @EXPORT_OK = qw(run); my $urpm; my ($mainw, $list_tv, $something_changed); my %col = ( mainw => { is_enabled => 0, is_update => 1, type => 2, name => 3, activatable => 4 }, ); my $loc = ManaTools::rpmdragora::locale(); sub get_medium_type { my ($medium) = @_; my %medium_type = ( cdrom => $loc->N("CD-ROM"), ftp => $loc->N("FTP"), file => $loc->N("Local"), http => $loc->N("HTTP"), https => $loc->N("HTTPS"), nfs => $loc->N("NFS"), removable => $loc->N("Removable"), rsync => $loc->N("rsync"), ssh => $loc->N("NFS"), ); return $loc->N("Mirror list") if $medium->{mirrorlist}; return $medium_type{$1} if $medium->{url} =~ m!^([^:]*)://!; return $loc->N("Local"); } sub selrow { my ($o_list_tv) = @_; defined $o_list_tv or $o_list_tv = $list_tv; my ($model, $iter) = $o_list_tv->get_selection->get_selected; $model && $iter or return -1; my $path = $model->get_path($iter); my $row = $path->to_string; return $row; } sub selected_rows { my ($o_list_tv) = @_; defined $o_list_tv or $o_list_tv = $list_tv; my (@rows) = $o_list_tv->get_selection->get_selected_rows; return -1 if @rows == 0; map { $_->to_string } @rows; } sub remove_row { my ($model, $path_str) = @_; my $iter = $model->get_iter_from_string($path_str); $iter or return; $model->remove($iter); } sub remove_from_list { my ($list, $list_ref, $model) = @_; my $row = selrow($list); if ($row != -1) { splice @$list_ref, $row, 1; remove_row($model, $row); } } sub _want_base_distro() { $::expert && distro_type(0) eq 'updates' ? interactive_msg( $loc->N("Choose media type"), $loc->N("In order to keep your system secure and stable, you must at a minimum set up sources for official security and stability updates. You can also choose to set up a fuller set of sources which includes the complete official Mageia repositories, giving you access to more software than can fit on the Mageia discs. Please choose whether to configure update sources only, or the full set of sources." ), transient => $::main_window, yesno => 1, text => { yes => $loc->N("Full set of sources"), no => $loc->N("Update sources only") }, ) : 1; } sub easy_add_callback_with_mirror() { # when called on early init by rpmdragora $urpm ||= fast_open_urpmi_db(); #- cooker and community don't have update sources my $want_base_distro = _want_base_distro(); defined $want_base_distro or return 0; my $distro = $ManaTools::rpmdragora::mageia_release; my ($mirror) = choose_mirror($urpm, message => $loc->N("This will attempt to install all official sources corresponding to your distribution (%s).\n I need to contact the Mageia website to get the mirror list. Please check that your network is currently running.\n Is it ok to continue?", $distro), transient => $::main_window, ) or return 0; ref $mirror or return 0; my $wait = wait_msg($loc->N("Please wait, adding media...")); add_distrib_update_media($urpm, $mirror, if_(!$want_base_distro, only_updates => 1)); $offered_to_add_sources->[0] = 1; remove_wait_msg($wait); return 1; } sub easy_add_callback() { # when called on early init by rpmdragora $urpm ||= fast_open_urpmi_db(); #- cooker and community don't have update sources my $want_base_distro = _want_base_distro(); defined $want_base_distro or return 0; warn_for_network_need(undef, transient => $::main_window) or return 0; my $wait = wait_msg($loc->N("Please wait, adding media...")); add_distrib_update_media($urpm, undef, if_(!$want_base_distro, only_updates => 1)); $offered_to_add_sources->[0] = 1; remove_wait_msg($wait); return 1; } ## Internal routine that builds input fields needed to manage ## the selected media type to be added ## return HASH reference with the added widgets sub _build_add_dialog { my $options = shift; die "replace point is needed" if !defined ($options->{replace_pnt}); die "dialog is needed" if !defined ($options->{dialog}); die "selected item is needed" if !defined ($options->{selected}); die "media info is needed" if !defined ($options->{info}); my %widgets; my $factory = yui::YUI::widgetFactory; $options->{dialog}->startMultipleChanges(); $options->{replace_pnt}->deleteChildren(); # replace widgets my $vbox = $factory->createVBox( $options->{replace_pnt} ); my $hbox = $factory->createHBox($vbox); $factory->createHSpacing($hbox, 1.0); my $label = $factory->createLabel($hbox, $options->{info}->{$options->{selected}}->{url} ); $factory->createHSpacing($hbox, 3.0); $widgets{url} = $factory->createInputField($hbox, "", 0); $widgets{url}->setWeight($yui::YD_HORIZ, 2); if (defined($options->{info}->{$options->{selected}}->{dirsel})) { $widgets{dirsel} = $factory->createPushButton($hbox, $loc->N("Browse...")); } elsif (defined($options->{info}->{$options->{selected}}->{loginpass})) { $hbox = $factory->createHBox($vbox); $factory->createHSpacing($hbox, 1.0); $label = $factory->createLabel($hbox, $loc->N("Login:") ); $factory->createHSpacing($hbox, 1.0); $widgets{login} = $factory->createInputField($hbox, "", 0); $label->setWeight($yui::YD_HORIZ, 1); $widgets{login}->setWeight($yui::YD_HORIZ, 3); $hbox = $factory->createHBox($vbox); $factory->createHSpacing($hbox, 1.0); $label = $factory->createLabel($hbox, $loc->N("Password:") ); $factory->createHSpacing($hbox, 1.0); $widgets{pass} = $factory->createInputField($hbox, "", 1); $label->setWeight($yui::YD_HORIZ, 1); $widgets{pass}->setWeight($yui::YD_HORIZ, 3); } # recalc layout $options->{replace_pnt}->showChild(); $options->{dialog}->recalcLayout(); $options->{dialog}->doneMultipleChanges(); return \%widgets; } sub add_callback() { my $retVal = 0; my $appTitle = yui::YUI::app()->applicationTitle(); ## set new title to get it in dialog yui::YUI::app()->setApplicationTitle($loc->N("Add a medium")); my $factory = yui::YUI::widgetFactory; my $dialog = $factory->createPopupDialog(); my $minSize = $factory->createMinSize( $dialog, 60, 5 ); my $vbox = $factory->createVBox( $minSize ); $factory->createVSpacing($vbox, 0.5); my $hbox = $factory->createHBox( $factory->createLeft($vbox) ); $factory->createHeading($hbox, $loc->N("Adding a medium:")); $factory->createVSpacing($vbox, 0.5); $hbox = $factory->createHBox($vbox); $factory->createHSpacing($hbox, 1.0); my $label = $factory->createLabel($hbox, $loc->N("Type of medium:") ); my $media_type = $factory->createComboBox($hbox, "", 0); $media_type->setWeight($yui::YD_HORIZ, 2); my %radios_infos = ( local => { name => $loc->N("Local files"), url => $loc->N("Medium path:"), dirsel => 1 }, ftp => { name => $loc->N("FTP server"), url => $loc->N("URL:"), loginpass => 1 }, rsync => { name => $loc->N("RSYNC server"), url => $loc->N("URL:") }, http => { name => $loc->N("HTTP server"), url => $loc->N("URL:") }, removable => { name => $loc->N("Removable device (CD-ROM, DVD, ...)"), url => $loc->N("Path or mount point:"), dirsel => 1 }, ); my @radios_names_ordered = qw(local ftp rsync http removable); my $itemColl = new yui::YItemCollection; foreach my $elem (@radios_names_ordered) { my $it = new yui::YItem($radios_infos{$elem}->{'name'}, 0); if ($elem eq $radios_names_ordered[0]) { $it->setSelected(1); } $itemColl->push($it); $it->DISOWN(); } $media_type->addItems($itemColl); $media_type->setNotify(1); $hbox = $factory->createHBox($vbox); $factory->createHSpacing($hbox, 1.0); $label = $factory->createLabel($hbox, $loc->N("Medium name:") ); $factory->createHSpacing($hbox, 1.0); my $media_name = $factory->createInputField($hbox, "", 0); $media_name->setWeight($yui::YD_HORIZ, 2); # per function layout (replace point) my $align = $factory->createLeft($vbox); my $replace_pnt = $factory->createReplacePoint($align); my $add_widgets = _build_add_dialog({replace_pnt => $replace_pnt, dialog => $dialog, info => \%radios_infos, selected => $radios_names_ordered[0]} ); # check-boxes $hbox = $factory->createHBox($factory->createLeft($vbox)); $factory->createHSpacing($hbox, 1.3); my $dist_media = $factory->createCheckBox($hbox, $loc->N("Create media for a whole distribution"), 0); $hbox = $factory->createHBox($factory->createLeft($vbox)); $factory->createHSpacing($hbox, 1.3); my $update_media = $factory->createCheckBox($hbox, $loc->N("Tag this medium as an update medium"), 0); $dist_media->setNotify(1); # Last line buttons $factory->createVSpacing($vbox, 0.5); $hbox = $factory->createHBox($vbox); my $cancelButton = $factory->createPushButton($hbox, $loc->N("&Cancel")); $factory->createHSpacing($hbox, 3.0); my $okButton = $factory->createPushButton($hbox, $loc->N("&Ok")); $cancelButton->setDefaultButton(1); # dialog event loop while(1) { my $event = $dialog->waitForEvent(); my $eventType = $event->eventType(); #event type checking if ($eventType == $yui::YEvent::CancelEvent) { last; } elsif ($eventType == $yui::YEvent::WidgetEvent) { ### widget my $widget = $event->widget(); if ($widget == $cancelButton) { last; } elsif ($widget == $media_type) { my $item = $media_type->selectedItem(); my $sel = $item ? $item->index() : 0 ; $add_widgets = _build_add_dialog({replace_pnt => $replace_pnt, dialog => $dialog, info => \%radios_infos, selected => $radios_names_ordered[$sel]} ); } elsif ($widget == $dist_media) { $update_media->setEnabled(!$dist_media->value()); } elsif ($widget == $okButton) { my $item = $media_type->selectedItem(); my $sel = $item ? $item->index() : 0 ; my $info = $radios_infos{$radios_names_ordered[$sel]}; my $name = $media_name->value(); my $url = $add_widgets->{url}->value(); $name eq '' || $url eq '' and interactive_msg('rpmdragora', $loc->N("You need to fill up at least the two first entries.")), next; if (member($name, map { $_->{name} } @{$urpm->{media}})) { interactive_msg('rpmdragora', $loc->N("There is already a medium called <%s>,\ndo you really want to replace it?", $name), yesno => 1) or next; } my %i = ( name => $name, url => $url, distrib => $dist_media->value() ? 1 : 0, update => $update_media->value() ? 1 : undef, ); my %make_url = ( local => "file:/$i{url}", http => $i{url}, rsync => $i{url}, removable => "removable:/$i{url}", ); $i{url} =~ s|^ftp://||; $make_url{ftp} = sprintf "ftp://%s%s", defined($add_widgets->{login}) ? $add_widgets->{login}->value() . ':' . ( $add_widgets->{pass}->value() ? $add_widgets->{pass}->value() : '') : '', $i{url}; if ($i{distrib}) { add_medium_and_check( $urpm, { nolock => 1, distrib => 1 }, $i{name}, $make_url{$radios_names_ordered[$sel]}, probe_with => 'synthesis', update => $i{update}, ); } else { if (member($i{name}, map { $_->{name} } @{$urpm->{media}})) { urpm::media::select_media($urpm, $i{name}); urpm::media::remove_selected_media($urpm); } add_medium_and_check( $urpm, { nolock => 1 }, $i{name}, $make_url{$radios_names_ordered[$sel]}, $i{hdlist}, update => $i{update}, ); } $retVal = 1; last; } else { my $item = $media_type->selectedItem(); my $sel = $item ? $item->index() : 0 ; if (defined($radios_infos{$radios_names_ordered[$sel]}->{dirsel}) && defined($add_widgets->{dirsel}) ) { if ($widget == $add_widgets->{dirsel}) { my $dir = yui::YUI::app()->askForExistingDirectory(home(), $radios_infos{$radios_names_ordered[$sel]}->{url} ); $add_widgets->{url}->setValue($dir) if ($dir); } } } } } ### End ### $dialog->destroy(); #restore old application title yui::YUI::app()->setApplicationTitle($appTitle) if $appTitle; return $retVal; } sub options_callback() { my $appTitle = yui::YUI::app()->applicationTitle(); ## set new title to get it in dialog yui::YUI::app()->setApplicationTitle($loc->N("Global options for package installation")); my $factory = yui::YUI::widgetFactory; my $dialog = $factory->createPopupDialog(); my $minSize = $factory->createMinSize( $dialog, 50, 5 ); my $vbox = $factory->createVBox( $minSize ); my $hbox = $factory->createHBox($vbox); $factory->createHSpacing($hbox, 1.0); my $label = $factory->createLabel($hbox, $loc->N("Verify RPMs to be installed:") ); $factory->createHSpacing($hbox, 3.5); my $verify_rpm = $factory->createComboBox($hbox, "", 0); $verify_rpm->setWeight($yui::YD_HORIZ, 2); my @verif = ($loc->N("never"), $loc->N("always")); my $verify_rpm_value = $urpm->{global_config}{'verify-rpm'} || 0; my $itemColl = new yui::YItemCollection; my $cnt = 0; foreach my $elem (@verif) { my $it = new yui::YItem($elem, 0); if ($cnt == $verify_rpm_value) { $it->setSelected(1); } $itemColl->push($it); $it->DISOWN(); $cnt++; } $verify_rpm->addItems($itemColl); $hbox = $factory->createHBox($vbox); $factory->createHSpacing($hbox, 1.0); $label = $factory->createLabel($hbox, $loc->N("Download program to use:") ); $factory->createHSpacing($hbox, 4.0); my $downloader_entry = $factory->createComboBox($hbox, "", 0); $downloader_entry->setWeight($yui::YD_HORIZ, 2); my @comboList = urpm::download::available_ftp_http_downloaders() ; my $downloader = $urpm->{global_config}{downloader} || $comboList[0]; if (scalar(@comboList) > 0) { $itemColl = new yui::YItemCollection; foreach my $elem (@comboList) { my $it = new yui::YItem($elem, 0); if ($elem eq $downloader) { $it->setSelected(1); } $itemColl->push($it); $it->DISOWN(); } $downloader_entry->addItems($itemColl); } $hbox = $factory->createHBox($vbox); $factory->createHSpacing($hbox, 1.0); $label = $factory->createLabel($hbox, $loc->N("XML meta-data download policy:") ); my $xml_info_policy = $factory->createComboBox($hbox, "", 0); $xml_info_policy->setWeight($yui::YD_HORIZ, 2); my @xml_info_policies = ('', 'never', 'on-demand', 'update-only', 'always'); my @xml_info_policiesL = ('', $loc->N("Never"), $loc->N("On-demand"), $loc->N("Update-only"), $loc->N("Always")); my $xml_info_policy_value = $urpm->{global_config}{'xml-info'}; $itemColl = new yui::YItemCollection; $cnt = 0; foreach my $elem (@xml_info_policiesL) { my $it = new yui::YItem($elem, 0); if ($xml_info_policy_value && $xml_info_policy_value eq $xml_info_policies[$cnt]) { $it->setSelected(1); } $itemColl->push($it); $it->DISOWN(); $cnt++; } $xml_info_policy->addItems($itemColl); ### TODO tips ### #tip => #join("\n", #$loc->N("For remote media, specify when XML meta-data (file lists, changelogs & information) are downloaded."), #'', #$loc->N("Never"), #$loc->N("For remote media, XML meta-data are never downloaded."), #'', #$loc->N("On-demand"), #$loc->N("(This is the default)"), #$loc->N("The specific XML info file is downloaded when clicking on package."), #'', #$loc->N("Update-only"), #$loc->N("Updating media implies updating XML info files already required at least once."), #'', #$loc->N("Always"), #$loc->N("All XML info files are downloaded when adding or updating media."), $factory->createVSpacing($vbox, 0.5); ### last line buttons $factory->createVSpacing($vbox, 0.5); $hbox = $factory->createHBox($vbox); my $cancelButton = $factory->createPushButton($hbox, $loc->N("&Cancel")); $factory->createHSpacing($hbox, 3.0); my $okButton = $factory->createPushButton($hbox, $loc->N("&Ok")); $cancelButton->setDefaultButton(1); # dialog event loop while(1) { my $event = $dialog->waitForEvent(); my $eventType = $event->eventType(); #event type checking if ($eventType == $yui::YEvent::CancelEvent) { last; } elsif ($eventType == $yui::YEvent::WidgetEvent) { ### widget my $widget = $event->widget(); if ($widget == $cancelButton) { last; } elsif ($widget == $okButton) { my $changed = 0; my $item = $verify_rpm->selectedItem(); if ($item->index() != $verify_rpm_value) { $changed = 1; $urpm->{global_config}{'verify-rpm'} = $item->index(); } $item = $downloader_entry->selectedItem(); if ($item->label() ne $downloader) { $changed = 1; $urpm->{global_config}{downloader} = $item->label(); } $item = $xml_info_policy->selectedItem(); if ($xml_info_policies[$item->index()] ne $xml_info_policy_value) { $changed = 1; $urpm->{global_config}{'xml-info'} = $xml_info_policies[$item->index()]; } if ($changed) { urpm::media::write_config($urpm); $urpm = fast_open_urpmi_db(); } last; } } } ### End ### $dialog->destroy(); #restore old application title yui::YUI::app()->setApplicationTitle($appTitle) if $appTitle; } #============================================================= =head2 remove_callback =head3 INPUT $selection: YItemCollection (selected items) =head3 DESCRIPTION Remove the selected medias =cut #============================================================= sub remove_callback { my $selection = shift; my @rows; for (my $it = 0; $it < $selection->size(); $it++) { my $item = $selection->get($it); push @rows, $item->index(); } @rows == 0 and return 0; interactive_msg( $loc->N("Source Removal"), @rows == 1 ? $loc->N("Are you sure you want to remove source \"%s\"?", $urpm->{media}[$rows[0]]{name}) : $loc->N("Are you sure you want to remove the following sources?") . "\n\n" . format_list(map { $urpm->{media}[$_]{name} } @rows), yesno => 1, scroll => 1, ) or return 0; my $wait = wait_msg($loc->N("Please wait, removing medium...")); foreach my $row (reverse(@rows)) { $something_changed = 1; urpm::media::remove_media($urpm, [ $urpm->{media}[$row] ]); } urpm::media::write_urpmi_cfg($urpm); remove_wait_msg($wait); return 1; } #============================================================= =head2 upwards_callback =head3 INPUT $table: Mirror table (YTable) =head3 DESCRIPTION Move selected item to high priority level =cut #============================================================= sub upwards_callback { my $table = shift; ## get the first my $item = $table->selectedItem(); !$item and return 0; return 0 if ($item->index() == 0); my $row = $item->index(); my @media = ( $urpm->{media}[$row-1], $urpm->{media}[$row]); $urpm->{media}[$row] = $media[0]; $urpm->{media}[$row-1] = $media[1]; urpm::media::write_config($urpm); $urpm = fast_open_urpmi_db(); return $row - 1; } #============================================================= =head2 downwards_callback =head3 INPUT $table: Mirror table (YTable) =head3 DESCRIPTION Move selected item to low priority level =cut #============================================================= sub downwards_callback { my $table = shift; ## get the first my $item = $table->selectedItem(); !$item and return 0; my $row = $item->index(); return $row if ($row >= $table->itemsCount()-1); my @media = ( $urpm->{media}[$row], $urpm->{media}[$row+1]); $urpm->{media}[$row+1] = $media[0]; $urpm->{media}[$row] = $media[1]; urpm::media::write_config($urpm); $urpm = fast_open_urpmi_db(); return $row + 1; } #- returns 1 if something changed to force readMedia() sub edit_callback { my $table = shift; my $changed = 0; ## get the first my $item = $table->selectedItem(); !$item and return 0; my $row = $item->index(); my $medium = $urpm->{media}[$row]; my $config = urpm::cfg::load_config_raw($urpm->{config}, 1); my ($verbatim_medium) = grep { $medium->{name} eq $_->{name} } @$config; my $appTitle = yui::YUI::app()->applicationTitle(); ## set new title to get it in dialog yui::YUI::app()->setApplicationTitle($loc->N("Edit a medium")); my $factory = yui::YUI::widgetFactory; my $dialog = $factory->createPopupDialog(); my $minSize = $factory->createMinSize( $dialog, 80, 5 ); my $vbox = $factory->createVBox( $minSize ); my $hbox = $factory->createHBox( $factory->createLeft($vbox) ); $factory->createHeading($hbox, $loc->N("Editing medium \"%s\":", $medium->{name})); $factory->createVSpacing($vbox, 1.0); $hbox = $factory->createHBox($vbox); $factory->createHSpacing($hbox, 1.0); my $label = $factory->createLabel($hbox, $loc->N("URL:")); my $url_entry = $factory->createInputField($hbox, "", 0); $url_entry->setWeight($yui::YD_HORIZ, 2); $url_entry->setValue($verbatim_medium->{url} || $verbatim_medium->{mirrorlist}); $hbox = $factory->createHBox($vbox); $factory->createHSpacing($hbox, 1.0); $label = $factory->createLabel($hbox, $loc->N("Downloader:") ); my $downloader_entry = $factory->createComboBox($hbox, "", 0); $downloader_entry->setWeight($yui::YD_HORIZ, 2); my @comboList = urpm::download::available_ftp_http_downloaders() ; my $downloader = $verbatim_medium->{downloader} || $urpm->{global_config}{downloader} || $comboList[0]; if (scalar(@comboList) > 0) { my $itemColl = new yui::YItemCollection; foreach my $elem (@comboList) { my $it = new yui::YItem($elem, 0); if ($elem eq $downloader) { $it->setSelected(1); } $itemColl->push($it); $it->DISOWN(); } $downloader_entry->addItems($itemColl); } $factory->createVSpacing($vbox, 0.5); my $url = $url_entry->value(); $hbox = $factory->createHBox($factory->createLeft($vbox)); $factory->createHSpacing($hbox, 1.0); my $tableItem = yui::toYTableItem($item); # enabled cell 0, updates cell 1 my $cellEnabled = $tableItem->cell(0)->label() ? 1 : 0; my $enabled = $factory->createCheckBox($hbox, $loc->N("Enabled"), $cellEnabled); my $cellUpdates = $tableItem->cell(1)->label() ? 1 : 0; my $update = $factory->createCheckBox($hbox, $loc->N("Updates"), $cellUpdates); $update->setDisabled() if (!$::expert); $factory->createVSpacing($vbox, 0.5); $hbox = $factory->createHBox($vbox); my $cancelButton = $factory->createPushButton($hbox, $loc->N("&Cancel")); $factory->createHSpacing($hbox, 3.0); my $saveButton = $factory->createPushButton($hbox, $loc->N("&OK")); $factory->createHSpacing($hbox, 3.0); my $proxyButton = $factory->createPushButton($hbox, $loc->N("&Proxy...")); $cancelButton->setDefaultButton(1); # dialog event loop while(1) { my $event = $dialog->waitForEvent(); my $eventType = $event->eventType(); #event type checking if ($eventType == $yui::YEvent::CancelEvent) { last; } elsif ($eventType == $yui::YEvent::WidgetEvent) { ### widget my $widget = $event->widget(); if ($widget == $cancelButton) { last; } elsif ($widget == $saveButton) { if ($cellEnabled != $enabled->value()) { $urpm->{media}[$row]{ignore} = !$urpm->{media}[$row]{ignore} || undef; $changed = 1; } if ($cellUpdates != $update->value()) { $urpm->{media}[$row]{update} = !$urpm->{media}[$row]{update} || undef; $changed = 1; } if ( $changed ) { urpm::media::write_config($urpm); } my ($m_name, $m_update) = map { $medium->{$_} } qw(name update); # TODO check if really changed first $url = $url_entry->value(); $downloader = $downloader_entry->value(); $url =~ m|^removable://| and ( interactive_msg( $loc->N("You need to insert the medium to continue"), $loc->N("In order to save the changes, you need to insert the medium in the drive."), yesno => 1, text => { yes => $loc->N("Ok"), no => $loc->N("Cancel") } ) or return 0 ); my $saved_proxy = urpm::download::get_proxy($m_name); undef $saved_proxy if !defined $saved_proxy->{http_proxy} && !defined $saved_proxy->{ftp_proxy}; urpm::media::select_media($urpm, $m_name); if (my ($media) = grep { $_->{name} eq $m_name } @{$urpm->{media}}) { MDK::Common::DataStructure::put_in_hash($media, { ($verbatim_medium->{mirrorlist} ? 'mirrorlist' : 'url') => $url, name => $m_name, if_($m_update && $m_update ne $media->{update} || $m_update, update => $m_update), if_($saved_proxy && $saved_proxy ne $media->{proxy} || $saved_proxy, proxy => $saved_proxy), if_($downloader ne $media->{downloader} || $downloader, downloader => $downloader), modified => 1, }); urpm::media::write_config($urpm); update_sources_noninteractive($urpm, [ $m_name ]); } else { urpm::media::remove_selected_media($urpm); add_medium_and_check($urpm, { nolock => 1, proxy => $saved_proxy }, $m_name, $url, undef, update => $m_update, if_($downloader, downloader => $downloader)); } last; } elsif ($widget == $proxyButton) { proxy_callback($medium); } } } ### End ### $dialog->destroy(); #restore old application title yui::YUI::app()->setApplicationTitle($appTitle) if $appTitle; return $changed; } sub update_callback() { update_sources_interactive($urpm, transient => $::main_window, nolock => 1); } #============================================================= =head2 proxy_callback =head3 INPUT $medium: the medium which proxy is going to be modified =head3 DESCRIPTION Set or change the proxy settings for the given media. Note that Ok button saves the changes. =cut #============================================================= sub proxy_callback { my ($medium) = @_; my $medium_name = $medium ? $medium->{name} : ''; my ($proxy, $proxy_user) = readproxy($medium_name); my ($user, $pass) = $proxy_user =~ /^([^:]*):(.*)$/; my $appTitle = yui::YUI::app()->applicationTitle(); ## set new title to get it in dialog yui::YUI::app()->setApplicationTitle($loc->N("Configure proxies")); my $factory = yui::YUI::widgetFactory; my $dialog = $factory->createPopupDialog(); my $minSize = $factory->createMinSize( $dialog, 80, 5 ); my $vbox = $factory->createVBox( $minSize ); my $hbox = $factory->createHBox( $factory->createLeft($vbox) ); $factory->createHeading($hbox, $medium_name ? $loc->N("Proxy settings for media \"%s\"", $medium_name) : $loc->N("Global proxy settings")); $factory->createVSpacing($vbox, 0.5); $hbox = $factory->createHBox($vbox); $factory->createHSpacing($hbox, 1.0); my $label = $factory->createLabel($hbox, $loc->N("If you need a proxy, enter the hostname and an optional port (syntax: <proxyhost[:port]>):")); $factory->createVSpacing($vbox, 0.5); my ($proxybutton, $proxyentry, $proxyuserbutton, $proxyuserentry, $proxypasswordentry); $hbox = $factory->createHBox($factory->createLeft($vbox)); $proxybutton = $factory->createCheckBoxFrame($hbox, $loc->N("Enable proxy"), 1); my $frm_vbox = $factory->createVBox( $proxybutton ); my $align = $factory->createRight($frm_vbox); $hbox = $factory->createHBox($align); $label = $factory->createLabel($hbox, $loc->N("Proxy hostname:") ); $proxyentry = $factory->createInputField($hbox, "", 0); $label->setWeight($yui::YD_HORIZ, 1); $proxyentry->setWeight($yui::YD_HORIZ, 2); $proxyuserbutton = $factory->createCheckBoxFrame($factory->createLeft($frm_vbox), $loc->N("You may specify a username/password for the proxy authentication:"), 1); $proxyentry->setValue($proxy) if $proxy; $frm_vbox = $factory->createVBox( $proxyuserbutton ); ## proxy user name $align = $factory->createRight($frm_vbox); $hbox = $factory->createHBox($align); $label = $factory->createLabel($hbox, $loc->N("User:") ); $proxyuserentry = $factory->createInputField($hbox, "", 0); $label->setWeight($yui::YD_HORIZ, 1); $proxyuserentry->setWeight($yui::YD_HORIZ, 2); $proxyuserentry->setValue($user) if $user; ## proxy user password $align = $factory->createRight($frm_vbox); $hbox = $factory->createHBox($align); $label = $factory->createLabel($hbox, $loc->N("Password:") ); $proxypasswordentry = $factory->createInputField($hbox, "", 1); $label->setWeight($yui::YD_HORIZ, 1); $proxypasswordentry->setWeight($yui::YD_HORIZ, 2); $proxypasswordentry->setValue($pass) if $pass; $proxyuserbutton->setValue ($proxy_user ? 1 : 0); $proxybutton->setValue ($proxy ? 1 : 0); # dialog low level buttons $factory->createVSpacing($vbox, 0.5); $hbox = $factory->createHBox($vbox); my $okButton = $factory->createPushButton($hbox, $loc->N("&Ok")); $factory->createHSpacing($hbox, 3.0); my $cancelButton = $factory->createPushButton($hbox, $loc->N("&Cancel")); $cancelButton->setDefaultButton(1); # dialog event loop while(1) { my $event = $dialog->waitForEvent(); my $eventType = $event->eventType(); #event type checking if ($eventType == $yui::YEvent::CancelEvent) { last; } elsif ($eventType == $yui::YEvent::WidgetEvent) { ### widget my $widget = $event->widget(); if ($widget == $cancelButton) { last; } elsif ($widget == $okButton) { $proxy = $proxybutton->value() ? $proxyentry->value() : ''; $proxy_user = $proxyuserbutton->value() ? ($proxyuserentry->value() . ':' . $proxypasswordentry->value()) : ''; writeproxy($proxy, $proxy_user, $medium_name); last; } } } ### End ### $dialog->destroy(); #restore old application title yui::YUI::app()->setApplicationTitle($appTitle) if $appTitle; } sub parallel_read_sysconf() { my @conf; foreach (MDK::Common::File::cat_('/etc/urpmi/parallel.cfg')) { my ($name, $protocol, $command) = /([^:]+):([^:]+):(.*)/ or print STDERR "Warning, unrecognized line in /etc/urpmi/parallel.cfg:\n$_"; my $medias = $protocol =~ s/\(([^\)]+)\)$// ? [ split /,/, $1 ] : []; push @conf, { name => $name, protocol => $protocol, medias => $medias, command => $command }; } \@conf; } sub parallel_write_sysconf { my ($conf) = @_; output '/etc/urpmi/parallel.cfg', map { my $m = @{$_->{medias}} ? '(' . join(',', @{$_->{medias}}) . ')' : ''; "$_->{name}:$_->{protocol}$m:$_->{command}\n" } @$conf; } sub remove_parallel { my ($num, $conf) = @_; if ($num != -1) { splice @$conf, $num, 1; parallel_write_sysconf($conf); } } sub add_callback_ { my ($title, $label, $mainw, $widget, $get_value, $check) = @_; my $w = ugtk2->new($title, grab => 1, transient => $mainw->{real_window}); local $::main_window = $w->{real_window}; gtkadd( $w->{window}, gtkpack__( gtknew('VBox', spacing => 5), gtknew('Label', text => $label), $widget, gtknew('HSeparator'), gtkpack( gtknew('HButtonBox'), gtknew('Button', text => $loc->N("Ok"), clicked => sub { $w->{retval} = 1; $get_value->(); Gtk2->main_quit }), gtknew('Button', text => $loc->N("Cancel"), clicked => sub { $w->{retval} = 0; Gtk2->main_quit }) ) ) ); $check->() if $w->main; } sub edit_parallel { my ($num, $conf) = @_; my $edited = $num == -1 ? {} : $conf->[$num]; my $w = ugtk2->new($num == -1 ? $loc->N("Add a parallel group") : $loc->N("Edit a parallel group"), grab => 1, center => 1, transient => $::main_window); local $::main_window = $w->{real_window}; my $name_entry; my ($medias_ls, $hosts_ls) = (Gtk2::ListStore->new("Glib::String"), Gtk2::ListStore->new("Glib::String")); my ($medias, $hosts) = map { my $list = Gtk2::TreeView->new_with_model($_); $list->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, 'text' => 0)); $list->set_headers_visible(0); $list->get_selection->set_mode('browse'); $list; } $medias_ls, $hosts_ls; $medias_ls->append_set([ 0 => $_ ]) foreach @{$edited->{medias}}; my $add_media = sub { my $medias_list_ls = Gtk2::ListStore->new("Glib::String"); my $medias_list = Gtk2::TreeView->new_with_model($medias_list_ls); $medias_list->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, 'text' => 0)); $medias_list->set_headers_visible(0); $medias_list->get_selection->set_mode('browse'); $medias_list_ls->append_set([ 0 => $_->{name} ]) foreach @{$urpm->{media}}; my $sel; add_callback_($loc->N("Add a medium limit"), $loc->N("Choose a medium to add to the media limit:"), $w, $medias_list, sub { $sel = selrow($medias_list) }, sub { return if $sel == -1; my $media = ${$urpm->{media}}[$sel]{name}; $medias_ls->append_set([ 0 => $media ]); push @{$edited->{medias}}, $media; } ); }; my $hosts_list; if ($edited->{protocol} eq 'ssh') { $hosts_list = [ split /:/, $edited->{command} ] } elsif ($edited->{protocol} eq 'ka-run') { push @$hosts_list, $1 while $edited->{command} =~ /-m (\S+)/g } $hosts_ls->append_set([ 0 => $_ ]) foreach @$hosts_list; my $add_host = sub { my ($entry, $value); add_callback_($loc->N("Add a host"), $loc->N("Type in the hostname or IP address of the host to add:"), $mainw, $entry = gtkentry(), sub { $value = $entry->get_text }, sub { $hosts_ls->append_set([ 0 => $value ]); push @$hosts_list, $value } ); }; my @protocols_names = qw(ka-run ssh); my @protocols; gtkadd( $w->{window}, gtkpack_( gtknew('VBox', spacing => 5), if_( $num != -1, 0, gtknew('Label', text => $loc->N("Editing parallel group \"%s\":", $edited->{name})) ), 1, create_packtable( {}, [ $loc->N("Group name:"), $name_entry = gtkentry($edited->{name}) ], [ $loc->N("Protocol:"), gtknew('HBox', children_tight => [ @protocols = gtkradio($edited->{protocol}, @protocols_names) ]) ], [ $loc->N("Media limit:"), gtknew('HBox', spacing => 5, children => [ 1, gtknew('Frame', shadow_type => 'in', child => gtknew('ScrolledWindow', h_policy => 'never', child => $medias)), 0, gtknew('VBox', children_tight => [ gtksignal_connect(Gtk2::Button->new(but($loc->N("Add"))), clicked => sub { $add_media->() }), gtksignal_connect(Gtk2::Button->new(but($loc->N("Remove"))), clicked => sub { remove_from_list($medias, $edited->{medias}, $medias_ls); }) ]) ]) ], [ $loc->N("Hosts:"), gtknew('HBox', spacing => 5, children => [ 1, gtknew('Frame', shadow_type => 'in', child => gtknew('ScrolledWindow', h_policy => 'never', child => $hosts)), 0, gtknew('VBox', children_tight => [ gtksignal_connect(Gtk2::Button->new(but($loc->N("Add"))), clicked => sub { $add_host->() }), gtksignal_connect(Gtk2::Button->new(but($loc->N("Remove"))), clicked => sub { remove_from_list($hosts, $hosts_list, $hosts_ls); }) ]) ]) ] ), 0, gtknew('HSeparator'), 0, gtkpack( gtknew('HButtonBox'), gtksignal_connect( gtknew('Button', text => $loc->N("Ok")), clicked => sub { $w->{retval} = 1; $edited->{name} = $name_entry->get_text; mapn { $_[0]->get_active and $edited->{protocol} = $_[1] } \@protocols, \@protocols_names; Gtk2->main_quit; } ), gtknew('Button', text => $loc->N("Cancel"), clicked => sub { $w->{retval} = 0; Gtk2->main_quit })) ) ); $w->{rwindow}->set_size_request(600, -1); if ($w->main) { $num == -1 and push @$conf, $edited; if ($edited->{protocol} eq 'ssh') { $edited->{command} = join(':', @$hosts_list) } if ($edited->{protocol} eq 'ka-run') { $edited->{command} = "-c ssh " . join(' ', map { "-m $_" } @$hosts_list) } parallel_write_sysconf($conf); return 1; } return 0; } sub parallel_callback() { my $w = ugtk2->new($loc->N("Configure parallel urpmi (distributed execution of urpmi)"), grab => 1, center => 1, transient => $mainw->{real_window}); local $::main_window = $w->{real_window}; my $list_ls = Gtk2::ListStore->new("Glib::String", "Glib::String", "Glib::String", "Glib::String"); my $list = Gtk2::TreeView->new_with_model($list_ls); each_index { $list->append_column(Gtk2::TreeViewColumn->new_with_attributes($_, Gtk2::CellRendererText->new, 'text' => $::i)) } $loc->N("Group"), $loc->N("Protocol"), $loc->N("Media limit"); $list->append_column(my $commandcol = Gtk2::TreeViewColumn->new_with_attributes($loc->N("Command"), Gtk2::CellRendererText->new, 'text' => 3)); $commandcol->set_max_width(200); my $conf; my $reread = sub { $list_ls->clear; $conf = parallel_read_sysconf(); foreach (@$conf) { $list_ls->append_set([ 0 => $_->{name}, 1 => $_->{protocol}, 2 => @{$_->{medias}} ? join(', ', @{$_->{medias}}) : $loc->N("(none)"), 3 => $_->{command} ]); } }; $reread->(); gtkadd( $w->{window}, gtkpack_( gtknew('VBox', spacing => 5), 1, gtkpack_( gtknew('HBox', spacing => 10), 1, $list, 0, gtkpack__( gtknew('VBox', spacing => 5), gtksignal_connect( Gtk2::Button->new(but($loc->N("Remove"))), clicked => sub { remove_parallel(selrow($list), $conf); $reread->() }, ), gtksignal_connect( Gtk2::Button->new(but($loc->N("Edit..."))), clicked => sub { my $row = selrow($list); $row != -1 and edit_parallel($row, $conf); $reread->(); }, ), gtksignal_connect( Gtk2::Button->new(but($loc->N("Add..."))), clicked => sub { edit_parallel(-1, $conf) and $reread->() }, ) ) ), 0, gtknew('HSeparator'), 0, gtkpack( gtknew('HButtonBox'), gtknew('Button', text => $loc->N("Ok"), clicked => sub { Gtk2->main_quit }) ) ) ); $w->main; } sub keys_callback() { my $changed = 0; my $appTitle = yui::YUI::app()->applicationTitle(); ## set new title to get it in dialog yui::YUI::app()->setApplicationTitle($loc->N("Manage keys for digital signatures of packages")); my $factory = yui::YUI::widgetFactory; my $dialog = $factory->createPopupDialog(); my $minSize = $factory->createMinSize( $dialog, 80, 20 ); my $vbox = $factory->createVBox( $minSize ); my $hbox_headbar = $factory->createHBox($vbox); my $head_align_left = $factory->createLeft($hbox_headbar); my $head_align_right = $factory->createRight($hbox_headbar); my $headbar = $factory->createHBox($head_align_left); my $headRight = $factory->createHBox($head_align_right); my $hbox_content = $factory->createHBox($vbox); my $leftContent = $factory->createLeft($hbox_content); $leftContent->setWeight($yui::YD_HORIZ,3); my $frame = $factory->createFrame ($leftContent, ""); my $frmVbox = $factory->createVBox( $frame ); my $hbox = $factory->createHBox( $frmVbox ); ## media list my $yTableHeader = new yui::YTableHeader(); $yTableHeader->addColumn($loc->N("Medium"), $yui::YAlignBegin); my $multiselection = 0; my $mediaTbl = $factory->createTable($hbox, $yTableHeader, $multiselection); $mediaTbl->setKeepSorting(1); $mediaTbl->setImmediateMode(1); my $itemColl = new yui::YItemCollection; foreach (@{$urpm->{media}}) { my $name = $_->{name}; my $item = new yui::YTableItem ($name); # NOTE row is $item->index() $item->setLabel( $name ); $itemColl->push($item); $item->DISOWN(); } $mediaTbl->addItems($itemColl); ## key list $leftContent = $factory->createLeft($hbox_content); $leftContent->setWeight($yui::YD_HORIZ,3); $frame = $factory->createFrame ($leftContent, ""); $frmVbox = $factory->createVBox( $frame ); $hbox = $factory->createHBox( $frmVbox ); $yTableHeader = new yui::YTableHeader(); $yTableHeader->addColumn($loc->N("Keys"), $yui::YAlignBegin); $multiselection = 0; my $keyTbl = $factory->createTable($hbox, $yTableHeader, $multiselection); $keyTbl->setKeepSorting(1); my ($current_medium, $current_medium_nb, @keys); ### internal subroutines my $read_conf = sub { $urpm->parse_pubkeys(root => $urpm->{root}); @keys = map { [ split /[,\s]+/, ($_->{'key-ids'} || '') ] } @{$urpm->{media}}; }; my $write = sub { $something_changed = 1; urpm::media::write_config($urpm); $urpm = fast_open_urpmi_db(); $read_conf->(); }; $read_conf->(); my $key_name = sub { exists $urpm->{keys}{$_[0]} ? $urpm->{keys}{$_[0]}{name} : $loc->N("no name found, key doesn't exist in rpm keyring!"); }; my $sel_changed = sub { my $item = $mediaTbl->selectedItem(); if ($item) { $current_medium = $item->label(); $current_medium_nb = $item->index(); yui::YUI::app()->busyCursor(); yui::YUI::ui()->blockEvents(); $dialog->startMultipleChanges(); $keyTbl->deleteAllItems(); my $itemColl = new yui::YItemCollection; foreach ( @{$keys[$current_medium_nb]} ) { my $it = new yui::YTableItem (sprintf("%s (%s)", $_, $key_name->($_))); # NOTE row is $item->index() $it->setLabel( $_ ); $itemColl->push($it); $it->DISOWN(); } $keyTbl->addItems($itemColl); $dialog->recalcLayout(); $dialog->doneMultipleChanges(); yui::YUI::ui()->unblockEvents(); yui::YUI::app()->normalCursor(); } }; my $add_key = sub { my $sh_gui = ManaTools::Shared::GUI->new(); my $item = $mediaTbl->selectedItem(); if ($item) { $current_medium = $item->label(); $current_medium_nb = $item->index(); my @list; my %key; foreach (keys %{$urpm->{keys}}) { my $k = sprintf("%s (%s)", $_, $key_name->($_)); $key{$k} = $_; push @list, $k; } my $choice = $sh_gui->ask_fromList({ title => $loc->N("Add a key"), header => $loc->N("Choose a key to add to the medium %s", $current_medium), list => \@list, }); if ($choice) { my $k = $key{$choice}; $urpm->{media}[$current_medium_nb]{'key-ids'} = join(',', sort(uniq(@{$keys[$current_medium_nb]}, $k))); $write->(); return 1; } } return 0; }; my $remove_key = sub { my $sh_gui = ManaTools::Shared::GUI->new(); my $keyItem = $keyTbl->selectedItem(); my $mediaItem = $mediaTbl->selectedItem(); if ($keyItem && $mediaItem) { $current_medium = $mediaItem->label(); $current_medium_nb = $mediaItem->index(); my $current_key = $keyItem->label(); my $current_keyVal = yui::toYTableItem($keyItem)->cell(0)->label(); my $choice = $sh_gui->ask_YesOrNo({ title => $loc->N("Remove a key"), text => $loc->N("Are you sure you want to remove the key <br>%s<br> from medium %s?<br>(name of the key: %s)", $current_keyVal, $current_medium, $current_key ), richtext => 1, }); if ($choice) { $urpm->{media}[$current_medium_nb]{'key-ids'} = join(',', difference2(\@{$keys[$current_medium_nb]}, [ $current_key ]) ); $write->(); return 1; } } return 0; }; #### end subroutines $sel_changed->(); my $rightContent = $factory->createRight($hbox_content); $rightContent->setWeight($yui::YD_HORIZ,1); my $topContent = $factory->createTop($rightContent); my $vbox_commands = $factory->createVBox($topContent); $factory->createVSpacing($vbox_commands, 1.0); my $addButton = $factory->createPushButton($factory->createHBox($vbox_commands), $loc->N("Add")); my $remButton = $factory->createPushButton($factory->createHBox($vbox_commands), $loc->N("Remove")); # dialog buttons $factory->createVSpacing($vbox, 1.0); $hbox = $factory->createHBox( $vbox ); ### Close button my $closeButton = $factory->createPushButton($hbox, $loc->N("&Quit") ); ### dialog event loop while(1) { my $event = $dialog->waitForEvent(); my $eventType = $event->eventType(); my $changed = 0; my $selection_changed = 0; #event type checking if ($eventType == $yui::YEvent::CancelEvent) { last; } elsif ($eventType == $yui::YEvent::WidgetEvent) { # widget selected my $widget = $event->widget(); my $wEvent = yui::toYWidgetEvent($event); if ($widget == $closeButton) { last; } elsif ($widget == $addButton) { $changed = $add_key->(); $sel_changed->() if $changed; } elsif ($widget == $remButton) { $changed = $remove_key->(); $sel_changed->() if $changed; } elsif ($widget == $mediaTbl) { $sel_changed->(); } } } $dialog->destroy(); #restore old application title yui::YUI::app()->setApplicationTitle($appTitle) if $appTitle; return $changed; } #============================================================= =head2 readMedia =head3 INPUT $name: optional parameter, the media called name has to be updated =head3 OUTPUT $itemColl: yui::YItemCollection containing media data to be added to the YTable =head3 DESCRIPTION This method reads the configured media and add their info to the collection =cut #============================================================= sub readMedia { my ($name) = @_; if (defined $name) { urpm::media::select_media($urpm, $name); update_sources_check( $urpm, { nolock => 1 }, $loc->N_("Unable to update medium, errors reported:\n\n%s"), $name, ); } # reread configuration after updating media else ignore bit will be restored # by urpm::media::check_existing_medium(): $urpm = fast_open_urpmi_db(); my $itemColl = new yui::YItemCollection; foreach (grep { ! $_->{external} } @{$urpm->{media}}) { my $name = $_->{name}; my $item = new yui::YTableItem (($_->{ignore} ? "" : "X"), ($_->{update} ? "X" : ""), get_medium_type($_), $name); ## NOTE anaselli: next lines add check icon to cells, but they are 8x8, a dimension should ## be evaluated by font size, so disabled atm # my $cell = $item->cell(0); # Checked # my $checkedIcon = File::ShareDir::dist_file(ManaTools::Shared::distName(), 'images/Check_8x8.png'); # # $cell->setIconName($checkedIcon) if (!$_->{ignore}); # $cell = $item->cell(1); # Updates # $cell->setIconName($checkedIcon) if ($_->{update}); ## end icons on cells # TODO manage to_bool($::expert) # row # is $item->index() $item->setLabel( $name ); $itemColl->push($item); $item->DISOWN(); } return $itemColl; } #============================================================= =head2 selectRow =head3 INPUT $itemCollection: YItem collection in which to find the item that has to be selected $row: line to be selected =head3 DESCRIPTION Select item at row position =cut #============================================================= sub selectRow { my ($itemCollection, $row) = @_; return if !$itemCollection; for (my $it = 0; $it < $itemCollection->size(); $it++) { my $item = $itemCollection->get($it); if ($it == $row) { $item->setSelected(1); return; } } } #============================================================= =head2 _showMediaStatus =head3 INPUT $info: HASH reference containing item => selected item updates => updates checkbox widget enabled => enabled checkbox widget =head3 DESCRIPTION This internal function enables/disables checkboxes according to the passed item value. =cut #============================================================= sub _showMediaStatus { my $info = shift; die "Updates checkbox is mandatory" if !defined($info->{updates}) || !$info->{updates}; die "Enabled checkbox is mandatory" if !defined($info->{enabled}) || !$info->{enabled}; if (defined($info->{item})) { my $tableItem = yui::toYTableItem($info->{item}); # enabled cell 0, updates cell 1 my $cellEnabled = $tableItem && $tableItem->cell(0)->label() ? 1 : 0; my $cellUpdates = $tableItem && $tableItem->cell(1)->label() ? 1 : 0; $info->{enabled}->setValue($cellEnabled); $info->{updates}->setValue($cellUpdates); } else { $info->{enabled}->setDisabled(); $info->{updates}->setDisabled(); } } sub mainwindow() { my $something_changed = 0; my $appTitle = yui::YUI::app()->applicationTitle(); ## set new title to get it in dialog yui::YUI::app()->setApplicationTitle($loc->N("Configure media")); ## set icon if not already set by external launcher TODO yui::YUI::app()->setApplicationIcon("/usr/share/mcc/themes/default/rpmdrake-mdk.png"); my $mageiaPlugin = "mga"; my $factory = yui::YUI::widgetFactory; my $dialog = $factory->createMainDialog; my $vbox = $factory->createVBox( $dialog ); my $hbox_headbar = $factory->createHBox($vbox); my $head_align_left = $factory->createLeft($hbox_headbar); my $head_align_right = $factory->createRight($hbox_headbar); my $headbar = $factory->createHBox($head_align_left); my $headRight = $factory->createHBox($head_align_right); my %fileMenu = ( widget => $factory->createMenuButton($headbar,$loc->N("File")), update => new yui::YMenuItem($loc->N("Update")), add_media => new yui::YMenuItem($loc->N("Add a specific media mirror")), custom => new yui::YMenuItem($loc->N("Add a custom medium")), quit => new yui::YMenuItem($loc->N("&Quit")), ); my @ordered_menu_lines = qw(update add_media custom quit); foreach (@ordered_menu_lines) { $fileMenu{ widget }->addItem($fileMenu{ $_ }); } $fileMenu{ widget }->rebuildMenuTree(); my %optionsMenu = ( widget => $factory->createMenuButton($headbar, $loc->N("&Options")), global => new yui::YMenuItem($loc->N("Global options")), man_keys => new yui::YMenuItem($loc->N("Manage keys")), parallel => new yui::YMenuItem($loc->N("Parallel")), proxy => new yui::YMenuItem($loc->N("Proxy")), ); @ordered_menu_lines = qw(global man_keys parallel proxy); foreach (@ordered_menu_lines) { $optionsMenu{ widget }->addItem($optionsMenu{ $_ }); } $optionsMenu{ widget }->rebuildMenuTree(); my %helpMenu = ( widget => $factory->createMenuButton($headRight, $loc->N("&Help")), help => new yui::YMenuItem($loc->N("Manual")), report_bug => new yui::YMenuItem($loc->N("Report Bug")), about => new yui::YMenuItem($loc->N("&About")), ); @ordered_menu_lines = qw(help report_bug about); foreach (@ordered_menu_lines) { $helpMenu{ widget }->addItem($helpMenu{ $_ }); } $helpMenu{ widget }->rebuildMenuTree(); # my %contextMenu = ( # enable => $loc->N("Enable/Disable"), # update => $loc->N("Check as updates"), # ); # @ordered_menu_lines = qw(enable update); # my $itemColl = new yui::YItemCollection; # foreach (@ordered_menu_lines) { # # last if (!$::expert && $_ eq "update"); # my $item = new yui::YMenuItem($contextMenu{$_}); # $item->DISOWN(); # $itemColl->push($item); # } # yui::YUI::app()->openContextMenu($itemColl) or die "Cannot create contextMenu"; my $hbox_content = $factory->createHBox($vbox); my $leftContent = $factory->createLeft($hbox_content); $leftContent->setWeight($yui::YD_HORIZ,3); my $frame = $factory->createFrame ($leftContent, ""); my $frmVbox = $factory->createVBox( $frame ); my $hbox = $factory->createHBox( $frmVbox ); my $yTableHeader = new yui::YTableHeader(); $yTableHeader->addColumn($loc->N("Enabled"), $yui::YAlignCenter); $yTableHeader->addColumn($loc->N("Updates"), $yui::YAlignCenter); $yTableHeader->addColumn($loc->N("Type"), $yui::YAlignBegin); $yTableHeader->addColumn($loc->N("Medium"), $yui::YAlignBegin); ## mirror list my $multiselection = 1; my $mirrorTbl = $factory->createTable($hbox, $yTableHeader, $multiselection); $mirrorTbl->setKeepSorting(1); $mirrorTbl->setImmediateMode(1); my $itemCollection = readMedia(); selectRow($itemCollection, 0); #default selection $mirrorTbl->addItems($itemCollection); my $rightContent = $factory->createRight($hbox_content); $rightContent->setWeight($yui::YD_HORIZ,1); my $topContent = $factory->createTop($rightContent); my $vbox_commands = $factory->createVBox($topContent); $factory->createVSpacing($vbox_commands, 1.0); my $remButton = $factory->createPushButton($factory->createHBox($vbox_commands), $loc->N("Remove")); my $edtButton = $factory->createPushButton($factory->createHBox($vbox_commands), $loc->N("Edit")); my $addButton = $factory->createPushButton($factory->createHBox($vbox_commands), $loc->N("Add")); $hbox = $factory->createHBox( $vbox_commands ); my $item = $mirrorTbl->selectedItem(); $factory->createHSpacing($hbox, 1.0); my $enabled = $factory->createCheckBox($factory->createLeft($hbox), $loc->N("Enabled")); my $update = $factory->createCheckBox($factory->createLeft($hbox), $loc->N("Updates")); _showMediaStatus({item => $item, enabled => $enabled, updates => $update}); $update->setNotify(1); $enabled->setNotify(1); $update->setDisabled() if (!$::expert); $hbox = $factory->createHBox( $vbox_commands ); ## TODO icon and label for ncurses my $upIcon = File::ShareDir::dist_file(ManaTools::Shared::distName(), 'images/Up_16x16.png'); my $downIcon = File::ShareDir::dist_file(ManaTools::Shared::distName(), 'images/Down_16x16.png'); my $upButton = $factory->createPushButton($factory->createHBox($hbox), $loc->N("Up")); my $downButton = $factory->createPushButton($factory->createHBox($hbox), $loc->N("Down")); $upButton->setIcon($upIcon); $downButton->setIcon($downIcon); $addButton->setWeight($yui::YD_HORIZ,1); $edtButton->setWeight($yui::YD_HORIZ,1); $remButton->setWeight($yui::YD_HORIZ,1); $upButton->setWeight($yui::YD_HORIZ,1); $downButton->setWeight($yui::YD_HORIZ,1); # dialog buttons $factory->createVSpacing($vbox, 1.0); ## Window push buttons $hbox = $factory->createHBox( $vbox ); my $align = $factory->createLeft($hbox); $hbox = $factory->createHBox($align); my $helpButton = $factory->createPushButton($hbox, $loc->N("Help") ); $align = $factory->createRight($hbox); $hbox = $factory->createHBox($align); ### Close button my $closeButton = $factory->createPushButton($hbox, $loc->N("&Quit") ); ### dialog event loop while(1) { my $event = $dialog->waitForEvent(); my $eventType = $event->eventType(); my $changed = 0; my $selection_changed = 0; #event type checking if ($eventType == $yui::YEvent::CancelEvent) { last; }