From 1624ce382eb033c2cf3ef1fe6b9c41beb0b0a91b Mon Sep 17 00:00:00 2001 From: Angelo Naselli Date: Mon, 27 Jan 2014 18:20:30 +0100 Subject: Project structure change --- AdminPanel/AdminMouse.pm | 278 --- AdminPanel/Hosts/GHosts.pm | 355 ---- AdminPanel/Hosts/hosts.pm | 103 - AdminPanel/LogViewer/init.pm | 31 - AdminPanel/Privileges.pm | 61 - AdminPanel/Rpmdragora/.perl_checker | 1 - AdminPanel/Rpmdragora/edit_urpm_sources.pm | 1216 ----------- AdminPanel/Rpmdragora/formatting.pm | 192 -- AdminPanel/Rpmdragora/gui.pm | 1220 ----------- AdminPanel/Rpmdragora/gurpm.pm | 138 -- AdminPanel/Rpmdragora/icon.pm | 236 --- AdminPanel/Rpmdragora/init.pm | 174 -- AdminPanel/Rpmdragora/localization.pm | 35 - AdminPanel/Rpmdragora/open_db.pm | 162 -- AdminPanel/Rpmdragora/pkg.pm | 997 --------- AdminPanel/Rpmdragora/rpmnew.pm | 205 -- AdminPanel/Rpmdragora/widgets.pm | 52 - AdminPanel/Services/AdminService.pm | 559 ------ AdminPanel/Services/Utility.pm | 446 ---- AdminPanel/Services/adminService.conf | 10 - AdminPanel/Shared.pm | 712 ------- AdminPanel/Users/GUsers.pm | 2570 ------------------------ AdminPanel/Users/adminUser.conf | 10 - AdminPanel/Users/users.pm | 126 -- AdminPanel/rpmdragora.pm | 984 --------- Category.pm | 201 -- Changes | 5 + ConfigReader.pm | 119 -- MANIFEST | 114 ++ MainDisplay.pm | 451 ----- Makefile.PL | 35 + Module.pm | 121 -- README | 63 + SettingsReader.pm | 45 - apanel.pl | 95 - categories.conf | 6 +- extras/Services/adminService.conf | 10 + extras/Users/adminUser.conf | 10 + ignore.txt | 20 + lib/AdminPanel/Category.pm | 201 ++ lib/AdminPanel/ConfigReader.pm | 119 ++ lib/AdminPanel/LogViewer/init.pm | 31 + lib/AdminPanel/MainDisplay.pm | 505 +++++ lib/AdminPanel/Module.pm | 121 ++ lib/AdminPanel/Module/AdminMouse.pm | 278 +++ lib/AdminPanel/Module/Hosts.pm | 355 ++++ lib/AdminPanel/Module/Services.pm | 559 ++++++ lib/AdminPanel/Module/Users.pm | 2570 ++++++++++++++++++++++++ lib/AdminPanel/Privileges.pm | 61 + lib/AdminPanel/Rpmdragora/.perl_checker | 1 + lib/AdminPanel/Rpmdragora/edit_urpm_sources.pm | 1216 +++++++++++ lib/AdminPanel/Rpmdragora/formatting.pm | 192 ++ lib/AdminPanel/Rpmdragora/gui.pm | 1220 +++++++++++ lib/AdminPanel/Rpmdragora/gurpm.pm | 138 ++ lib/AdminPanel/Rpmdragora/icon.pm | 236 +++ lib/AdminPanel/Rpmdragora/init.pm | 174 ++ lib/AdminPanel/Rpmdragora/localization.pm | 35 + lib/AdminPanel/Rpmdragora/open_db.pm | 162 ++ lib/AdminPanel/Rpmdragora/pkg.pm | 997 +++++++++ lib/AdminPanel/Rpmdragora/rpmnew.pm | 205 ++ lib/AdminPanel/Rpmdragora/widgets.pm | 52 + lib/AdminPanel/SettingsReader.pm | 45 + lib/AdminPanel/Shared.pm | 712 +++++++ lib/AdminPanel/Shared/Hosts.pm | 103 + lib/AdminPanel/Shared/Services.pm | 444 ++++ lib/AdminPanel/Shared/Users.pm | 126 ++ lib/AdminPanel/rpmdragora.pm | 984 +++++++++ modules/adminMouse | 13 - modules/hostmanager/hostmanager | 36 - modules/services/adminService | 13 - modules/usermanager/adminUser | 13 - modules/usermanager/mgaAddUser | 13 - scripts/adminMouse | 13 + scripts/adminService | 13 + scripts/adminUser | 13 + scripts/apanel.pl | 95 + scripts/hostmanager | 36 + scripts/mgaAddUser | 13 + t/00-load.t | 13 + t/boilerplate.t | 57 + t/manifest.t | 15 + t/pod-coverage.t | 20 + t/pod.t | 12 + 83 files changed, 12402 insertions(+), 11996 deletions(-) delete mode 100644 AdminPanel/AdminMouse.pm delete mode 100644 AdminPanel/Hosts/GHosts.pm delete mode 100644 AdminPanel/Hosts/hosts.pm delete mode 100644 AdminPanel/LogViewer/init.pm delete mode 100644 AdminPanel/Privileges.pm delete mode 100644 AdminPanel/Rpmdragora/.perl_checker delete mode 100644 AdminPanel/Rpmdragora/edit_urpm_sources.pm delete mode 100644 AdminPanel/Rpmdragora/formatting.pm delete mode 100644 AdminPanel/Rpmdragora/gui.pm delete mode 100644 AdminPanel/Rpmdragora/gurpm.pm delete mode 100644 AdminPanel/Rpmdragora/icon.pm delete mode 100644 AdminPanel/Rpmdragora/init.pm delete mode 100644 AdminPanel/Rpmdragora/localization.pm delete mode 100644 AdminPanel/Rpmdragora/open_db.pm delete mode 100644 AdminPanel/Rpmdragora/pkg.pm delete mode 100644 AdminPanel/Rpmdragora/rpmnew.pm delete mode 100644 AdminPanel/Rpmdragora/widgets.pm delete mode 100644 AdminPanel/Services/AdminService.pm delete mode 100644 AdminPanel/Services/Utility.pm delete mode 100644 AdminPanel/Services/adminService.conf delete mode 100644 AdminPanel/Shared.pm delete mode 100644 AdminPanel/Users/GUsers.pm delete mode 100644 AdminPanel/Users/adminUser.conf delete mode 100644 AdminPanel/Users/users.pm delete mode 100644 AdminPanel/rpmdragora.pm delete mode 100644 Category.pm create mode 100644 Changes delete mode 100644 ConfigReader.pm create mode 100644 MANIFEST delete mode 100644 MainDisplay.pm create mode 100644 Makefile.PL delete mode 100644 Module.pm create mode 100644 README delete mode 100644 SettingsReader.pm delete mode 100755 apanel.pl create mode 100644 extras/Services/adminService.conf create mode 100644 extras/Users/adminUser.conf create mode 100644 ignore.txt create mode 100644 lib/AdminPanel/Category.pm create mode 100644 lib/AdminPanel/ConfigReader.pm create mode 100644 lib/AdminPanel/LogViewer/init.pm create mode 100644 lib/AdminPanel/MainDisplay.pm create mode 100644 lib/AdminPanel/Module.pm create mode 100644 lib/AdminPanel/Module/AdminMouse.pm create mode 100644 lib/AdminPanel/Module/Hosts.pm create mode 100644 lib/AdminPanel/Module/Services.pm create mode 100644 lib/AdminPanel/Module/Users.pm create mode 100644 lib/AdminPanel/Privileges.pm create mode 100644 lib/AdminPanel/Rpmdragora/.perl_checker create mode 100644 lib/AdminPanel/Rpmdragora/edit_urpm_sources.pm create mode 100644 lib/AdminPanel/Rpmdragora/formatting.pm create mode 100644 lib/AdminPanel/Rpmdragora/gui.pm create mode 100644 lib/AdminPanel/Rpmdragora/gurpm.pm create mode 100644 lib/AdminPanel/Rpmdragora/icon.pm create mode 100644 lib/AdminPanel/Rpmdragora/init.pm create mode 100644 lib/AdminPanel/Rpmdragora/localization.pm create mode 100644 lib/AdminPanel/Rpmdragora/open_db.pm create mode 100644 lib/AdminPanel/Rpmdragora/pkg.pm create mode 100644 lib/AdminPanel/Rpmdragora/rpmnew.pm create mode 100644 lib/AdminPanel/Rpmdragora/widgets.pm create mode 100644 lib/AdminPanel/SettingsReader.pm create mode 100644 lib/AdminPanel/Shared.pm create mode 100644 lib/AdminPanel/Shared/Hosts.pm create mode 100644 lib/AdminPanel/Shared/Services.pm create mode 100644 lib/AdminPanel/Shared/Users.pm create mode 100644 lib/AdminPanel/rpmdragora.pm delete mode 100755 modules/adminMouse delete mode 100755 modules/hostmanager/hostmanager delete mode 100755 modules/services/adminService delete mode 100755 modules/usermanager/adminUser delete mode 100755 modules/usermanager/mgaAddUser create mode 100755 scripts/adminMouse create mode 100755 scripts/adminService create mode 100755 scripts/adminUser create mode 100755 scripts/apanel.pl create mode 100755 scripts/hostmanager create mode 100755 scripts/mgaAddUser create mode 100644 t/00-load.t create mode 100644 t/boilerplate.t create mode 100644 t/manifest.t create mode 100644 t/pod-coverage.t create mode 100644 t/pod.t diff --git a/AdminPanel/AdminMouse.pm b/AdminPanel/AdminMouse.pm deleted file mode 100644 index fecf1e21..00000000 --- a/AdminPanel/AdminMouse.pm +++ /dev/null @@ -1,278 +0,0 @@ -# vim: set et ts=4 sw=4: -#***************************************************************************** -# -# Copyright (c) 2013 Angelo Naselli -# from drakx services -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2, as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -#***************************************************************************** - -package AdminPanel::AdminMouse; - -#leaving them atm -use lib qw(/usr/lib/libDrakX); - -# i18n: IMPORTANT: to get correct namespace (drakx-kbd-mouse-x11 instead of libDrakX) -BEGIN { unshift @::textdomains, 'drakx-kbd-mouse-x11' } - -use common; -use modules; -use mouse; -use c; - -use AdminPanel::Shared; - -use yui; -use Moose; - -extends qw( Module ); - -has '+icon' => ( - default => "/usr/share/mcc/themes/default/mousedrake-mdk.png", -); - -has '+name' => ( - default => N("AdminMouse"), -); - -sub start { - my $self = shift; - - $self->_adminMouseDialog(); -} - -sub _getUntranslatedName { - my ($self, $name, $list) = @_; - - foreach my $n (@{$list}) { - my @names = split(/\|/, $n); - for (my $lev=0; $lev < scalar(@names); $lev++) { - if (translate($names[$lev]) eq $name) { - return $names[$lev]; - } - } - } - - return undef; -} - - -sub _adminMouseDialog { - my $self = shift; - - my $datavalue = "TEST"; - - my $appTitle = yui::YUI::app()->applicationTitle(); - - ## set new title to get it in dialog - yui::YUI::app()->setApplicationTitle($self->name); - ## set icon if not already set by external launcher - yui::YUI::app()->setApplicationIcon($self->icon); - - my $factory = yui::YUI::widgetFactory; - - my $dialog = $factory->createMainDialog; - my $vbox = $factory->createVBox( $dialog ); - my $frame = $factory->createFrame ($vbox, N("Please choose your type of mouse.")); - my $treeWidget = $factory->createTree($frame, ""); - - my $modules_conf = modules::any_conf->read; - - my $mouse = mouse::read(); - - if (!$::noauto) { - my $probed_mouse = mouse::detect($modules_conf); - $mouse = $probed_mouse if !$mouse->{Protocol} || !$probed_mouse->{unsafe}; - } - - if (!$mouse || !$::auto) { - $mouse ||= mouse::fullname2mouse('Universal|Any PS/2 & USB mice'); - - my $prev = my $fullname = $mouse->{type} . '|' . $mouse->{name}; - my $selected = $mouse->{name}; - - my $fullList = { list => [ mouse::_fullnames() ], items => [], separator => '|', val => \$fullname, - format => sub { join('|', map { translate($_) } split('\|', $_[0])) } } ; - my $i; - - my $itemColl = new yui::YItemCollection; - my @items; - for ($i=0; $i{list}}); $i++) { - my @names = split(/\|/, $fullList->{list}[$i]); - for (my $lev=0; $lev < scalar(@names); $lev++) { - $names[$lev] = N($names[$lev]); - } - if ($i == 0 || $names[0] ne $items[0]->{label}) { - if ($i != 0) { - $itemColl->push($items[0]->{item}); - push @{$fullList->{items}}, $items[-1]->{item};; - } - @items = undef; - my $item = new yui::YTreeItem ($names[0]); - - if ($selected eq $self->_getUntranslatedName($item->label(), $fullList->{list})) { - $item->setSelected(1) ; - $item->setOpen(1); - my $parent = $item; - while($parent = $parent->parent()) { - $parent->setOpen(1); - } - } - $item->DISOWN(); - @items = ({item => $item, label => $names[0], level => 0}); - for (my $lev=1; $lev < scalar(@names); $lev++) { - $item = new yui::YTreeItem ($items[$lev-1]->{item}, $names[$lev]); - - if ($selected eq $self->_getUntranslatedName($item->label(), $fullList->{list})) { - $item->setSelected(1) ; - $item->setOpen(1); - my $parent = $item; - while($parent = $parent->parent()) { - $parent->setOpen(1); - } - } - $item->DISOWN(); - if ($lev < scalar(@names)-1) { - push @items, {item => $item, label => $names[$lev], level => $lev}; - } - } - } - else { - my $prevItem = 0; - for (my $lev=1; $lev < scalar(@names); $lev++) { - my $it; - for ($it=1; $it < scalar(@items); $it++){ - if ($items[$it]->{label} eq $names[$lev] && $items[$it]->{level} == $lev) { - $prevItem = $it; - last; - } - } - if ($it == scalar(@items)) { - my $item = new yui::YTreeItem ($items[$prevItem]->{item}, $names[$lev]); - - if ($selected eq $self->_getUntranslatedName($item->label(), $fullList->{list})) { - $item->setSelected(1) ; - $item->setOpen(1); - my $parent = $item; - while($parent = $parent->parent()) { - $parent->setOpen(1); - } - } - $item->DISOWN(); - push @items, {item => $item, label => $names[$lev], level => $lev}; - } - } - } - } - $itemColl->push($items[0]->{item}); - push @{$fullList->{items}}, $items[-1]->{item}; - - $treeWidget->addItems($itemColl); - my $align = $factory->createLeft($vbox); - my $hbox = $factory->createHBox($align); - my $aboutButton = $factory->createPushButton($hbox, N("About") ); - $align = $factory->createRight($hbox); - $hbox = $factory->createHBox($align); - my $cancelButton = $factory->createPushButton($hbox, N("Cancel") ); - my $okButton = $factory->createPushButton($hbox, N("Ok") ); - - 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 selected - my $widget = $event->widget(); - - if ($widget == $cancelButton) { - last; - } - elsif ($widget == $aboutButton) { - my $license = translate($AdminPanel::Shared::License); - AdminPanel::Shared::AboutDialog( - { name => N("AdminMouse"), - version => $self->VERSION, - copyright => N("Copyright (C) %s Mageia community", '2014'), - license => $license, - comments => N("AdminMouse is the Mageia mouse management tool \n(from the original idea of Mandriva mousedrake)."), - website => 'http://www.mageia.org', - website_label => N("Mageia"), - authors => "Angelo Naselli \nMatteo Pasotti ", - translator_credits => - #-PO: put here name(s) and email(s) of translator(s) (eg: "John Smith ") - N("_: Translator(s) name(s) & email(s)\n")} - ); - } - elsif ($widget == $okButton) { - my $continue = 1; - my $selectedItem = $treeWidget->selectedItem(); - - my $it=$selectedItem; - my $fullname = $self->_getUntranslatedName($it->label(), $fullList->{list}); - while($it = yui::toYTreeItem($it)->parent()) { - $fullname = join("|", $self->_getUntranslatedName($it->label(), $fullList->{list}), $fullname); - } - - if ($fullname ne $prev) { - my $mouse_ = mouse::fullname2mouse($fullname, device => $mouse->{device}); - if ($fullname =~ /evdev/) { - $mouse_->{evdev_mice} = $mouse_->{evdev_mice_all} = $mouse->{evdev_mice_all}; - } - %$mouse = %$mouse_; - } - - if ($mouse->{nbuttons} < 3 ) { - $mouse->{Emulate3Buttons} = AdminPanel::Shared::ask_YesOrNo('', N("Emulate third button?")); - } - if ($mouse->{type} eq 'serial') { - my @list = (); - foreach (detect_devices::serialPorts()) { - push @list, detect_devices::serialPort2text($_); - } - my $choice = AdminPanel::Shared::ask_fromList(N("Mouse Port"), - N("Please choose which serial port your mouse is connected to."), - \@list); - if ( !$choice ) { - $continue = 0; - } - else { - $mouse->{device} = $choice; - } - } - - if ($continue) { - last; - } - } - } - } - - } - - # TODO manage write conf without interactive things - # mouse::write_conf($in->do_pkgs, $modules_conf, $mouse, 1); - system('systemctl', 'try-restart', 'gpm.service') if -e '/usr/lib/systemd/system/gpm.service'; - - $dialog->destroy(); - - #restore old application title - yui::YUI::app()->setApplicationTitle($appTitle); -} - -1; \ No newline at end of file diff --git a/AdminPanel/Hosts/GHosts.pm b/AdminPanel/Hosts/GHosts.pm deleted file mode 100644 index 4b64ddf7..00000000 --- a/AdminPanel/Hosts/GHosts.pm +++ /dev/null @@ -1,355 +0,0 @@ -# vim: set et ts=4 sw=4: -#***************************************************************************** -# -# Copyright (c) 2013-2014 Matteo Pasotti -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2, as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -#***************************************************************************** - -package AdminPanel::Hosts::GHosts; - -use Modern::Perl 2011; -use autodie; -use Moose; -use POSIX qw(ceil); -use utf8; - -use Glib; -use yui; -use AdminPanel::Shared; -use AdminPanel::Hosts::hosts; - -extends qw( Module ); - - -has '+icon' => ( - default => "/usr/lib/libDrakX/icons/IC-Dhost-48.png" -); - -has '+name' => ( - default => "Hostmanager", -); - -=head1 VERSION - -Version 1.0.0 - -=cut - -our $VERSION = '1.0.0'; - -has 'dialog' => ( - is => 'rw', - init_arg => undef -); - -has 'table' => ( - is => 'rw', - init_arg => undef -); - -has 'cfgHosts' => ( - is => 'rw', - init_arg => undef -); - -sub start { - my $self = shift; - - $self->manageHostsDialog(); -}; - - -#============================================================= - -=head2 _addHostDialog - -=head3 INPUT - - $self: this object - -=head3 DESCRIPTION - -This subroutine creates the Host dialog to add host definitions - -=cut - -#============================================================= -sub _manipulateHostDialog { - my $self = shift; - - my $headerString = shift(); - my $boolEdit = shift(); - - my $hostIpString = ""; - my $hostNameString = ""; - my $hostAliasesString = ""; - - if($boolEdit == 1){ - $hostIpString = shift(); - $hostNameString = shift(); - $hostAliasesString = shift(); - } - - my $factory = yui::YUI::widgetFactory; - my $dlg = $factory->createPopupDialog(); - my $layout = $factory->createVBox($dlg); - - my $hbox_header = $factory->createHBox($layout); - my $vbox_content = $factory->createVBox($layout); - my $hbox_footer = $factory->createHBox($layout); - - # header - my $labelDescription = $factory->createLabel($hbox_header,$headerString); - - # content - my $firstHbox = $factory->createHBox($vbox_content); - my $secondHbox = $factory->createHBox($vbox_content); - my $thirdHbox = $factory->createHBox($vbox_content); - - my $labelIPAddress = $factory->createLabel($firstHbox,"IP Address"); - my $labelHostName = $factory->createLabel($secondHbox,"Hostname"); - my $labelHostAlias = $factory->createLabel($thirdHbox,"Host aliases"); - $labelIPAddress->setWeight($yui::YD_HORIZ, 10); - $labelHostName->setWeight($yui::YD_HORIZ, 10); - $labelHostAlias->setWeight($yui::YD_HORIZ, 10); - - my $textIPAddress = $factory->createInputField($firstHbox,""); - my $textHostName = $factory->createInputField($secondHbox,""); - my $textHostAlias = $factory->createInputField($thirdHbox,""); - $textIPAddress->setWeight($yui::YD_HORIZ, 30); - $textHostName->setWeight($yui::YD_HORIZ, 30); - $textHostAlias->setWeight($yui::YD_HORIZ, 30); - - if($boolEdit == 1){ - $textIPAddress->setValue($hostIpString); - $textHostName->setValue($hostNameString); - $textHostAlias->setValue($hostAliasesString); - } - - # footer - my $cancelButton = $factory->createPushButton($factory->createLeft($hbox_footer),"Cancel"); - my $okButton = $factory->createPushButton($factory->createRight($hbox_footer),"OK"); - - while(1){ - my $event = $dlg->waitForEvent(); - my $eventType = $event->eventType(); - - #event type checking - if ($eventType == $yui::YEvent::CancelEvent) { - last; - } - elsif ($eventType == $yui::YEvent::WidgetEvent) { - # widget selected - my $widget = $event->widget(); - if ($widget == $cancelButton) { - last; - } - elsif($widget == $okButton) { - my $res = undef; - my @hosts_toadd; - push @hosts_toadd, $textHostName->value(); - if(trim($textHostAlias->value()) ne ""){ - push @hosts_toadd, $textHostAlias->value(); - } - print "@hosts_toadd\n"; - if($boolEdit == 0){ - $res = $self->cfgHosts->_insertHost($textIPAddress->value(),[@hosts_toadd]); - }else{ - $res = $self->cfgHosts->_modifyHost($textIPAddress->value(),[@hosts_toadd]); - } - $res = $self->cfgHosts->_writeHosts(); - print "Write result: $res\n"; - last; - } - } - } - - destroy $dlg; -} - -sub _addHostDialog { - my $self = shift(); - return $self->_manipulateHostDialog("Add the information",0); -} - -sub _edtHostDialog { - my $self = shift(); - my $hostIp = shift(); - my $hostName = shift(); - my $hostAliases = shift(); - return $self->_manipulateHostDialog("Modify the information",1,$hostIp,$hostName,$hostAliases); -} - -#============================================================= - -=head2 setupTable - -=head3 INPUT - - $self: this object - - $data: reference to the array containaing the host data to show into the table - -=head3 DESCRIPTION - -This subroutine populates a previously created YTable with the hosts data -retrieved by the Config::Hosts module - -=cut - -#============================================================= -sub setupTable { - my $self = shift(); - - my @hosts = $self->cfgHosts->_getHosts(); - # clear table - $self->table->deleteAllItems(); - foreach my $host (@hosts){ - my $tblItem; - my $aliases = join(',',@{$host->{'hosts'}}); - if(scalar(@{$host->{'hosts'}}) > 1){ - $aliases =~s/^$host->{'hosts'}[0]\,*//g; - }elsif(scalar(@{$host->{'hosts'}}) == 1){ - $aliases = ""; - } - $tblItem = new yui::YTableItem($host->{'ip'},$host->{'hosts'}[0],$aliases); - $self->table->addItem($tblItem); - } -} - -sub manageHostsDialog { - my $self = shift; - - ## TODO fix for adminpanel - my $appTitle = yui::YUI::app()->applicationTitle(); - my $appIcon = yui::YUI::app()->applicationIcon(); - ## set new title to get it in dialog - my $newTitle = "Manage hosts definitions"; - yui::YUI::app()->setApplicationTitle($newTitle); - - my $factory = yui::YUI::widgetFactory; - my $optional = yui::YUI::optionalWidgetFactory; - - - $self->dialog($factory->createMainDialog()); - my $layout = $factory->createVBox($self->dialog); - - my $hbox_header = $factory->createHBox($layout); - my $headLeft = $factory->createHBox($factory->createLeft($hbox_header)); - my $headRight = $factory->createHBox($factory->createRight($hbox_header)); - - my $logoImage = $factory->createImage($headLeft, $appIcon); - my $labelAppDescription = $factory->createLabel($headRight,$newTitle); - $logoImage->setWeight($yui::YD_HORIZ,0); - $labelAppDescription->setWeight($yui::YD_HORIZ,3); - - my $hbox_content = $factory->createHBox($layout); - - my $tableHeader = new yui::YTableHeader(); - $tableHeader->addColumn("IP Address"); - $tableHeader->addColumn("Hostname"); - $tableHeader->addColumn("Host Aliases"); - my $leftContent = $factory->createLeft($hbox_content); - $leftContent->setWeight($yui::YD_HORIZ,45); - $self->table($factory->createTable($leftContent,$tableHeader)); - - # initialize Config::Hosts - $self->cfgHosts(AdminPanel::Hosts::hosts->new()); - $self->setupTable(); - - my $rightContent = $factory->createRight($hbox_content); - $rightContent->setWeight($yui::YD_HORIZ,10); - my $topContent = $factory->createTop($rightContent); - my $vbox_commands = $factory->createVBox($topContent); - my $addButton = $factory->createPushButton($factory->createHBox($vbox_commands),"Add"); - my $edtButton = $factory->createPushButton($factory->createHBox($vbox_commands),"Edit"); - my $remButton = $factory->createPushButton($factory->createHBox($vbox_commands),"Remove"); - $addButton->setWeight($yui::YD_HORIZ,1); - $edtButton->setWeight($yui::YD_HORIZ,1); - $remButton->setWeight($yui::YD_HORIZ,1); - - my $hbox_foot = $factory->createHBox($layout); - my $vbox_foot_left = $factory->createVBox($factory->createLeft($hbox_foot)); - my $vbox_foot_right = $factory->createVBox($factory->createRight($hbox_foot)); - my $aboutButton = $factory->createPushButton($vbox_foot_left,"About"); - my $cancelButton = $factory->createPushButton($vbox_foot_right,"Cancel"); - my $okButton = $factory->createPushButton($vbox_foot_right,"OK"); - - # main loop - while(1) { - my $event = $self->dialog->waitForEvent(); - my $eventType = $event->eventType(); - - #event type checking - if ($eventType == $yui::YEvent::CancelEvent) { - last; - } - elsif ($eventType == $yui::YEvent::WidgetEvent) { -### Buttons and widgets ### - my $widget = $event->widget(); - if ($widget == $cancelButton) { - last; - } - elsif ($widget == $addButton) { - $self->_addHostDialog(); - $self->setupTable(); - } - elsif ($widget == $edtButton) { - my $tblItem = yui::toYTableItem($self->table->selectedItem()); - if($tblItem->cellCount() >= 3){ - $self->_edtHostDialog($tblItem->cell(0)->label(),$tblItem->cell(1)->label(),$tblItem->cell(2)->label()); - }else{ - $self->_edtHostDialog($tblItem->cell(0)->label(),$tblItem->cell(1)->label(),""); - } - $self->setupTable(); - } - elsif ($widget == $remButton) { - # implement deletion dialog - if(AdminPanel::Shared::ask_YesOrNo("Confirmation","Are you sure to drop this host?") == 1){ - my $tblItem = yui::toYTableItem($self->table->selectedItem()); - # drop the host using the ip - $self->cfgHosts->_dropHost($tblItem->cell(0)->label()); - # write changes - $self->cfgHosts->_writeHosts(); - $self->setupTable(); - } - }elsif ($widget == $aboutButton) { - AdminPanel::Shared::AboutDialog({ - name => $appTitle, - version => $VERSION, - copyright => "Copyright (c) 2013-2014 by Matteo Pasotti", - license => $AdminPanel::Shared::License, - comments => "Graphical manager for hosts definitions", - website => "http://gitweb.mageia.org/software/adminpanel", - website_label => "WebSite", - authors => "Matteo Pasotti " - } - ); - }elsif ($widget == $okButton) { - # write changes - $self->cfgHosts->_writeHosts(); - last; - } - } - } - - $self->dialog->destroy() ; - - #restore old application title - yui::YUI::app()->setApplicationTitle($appTitle); -} - -1; diff --git a/AdminPanel/Hosts/hosts.pm b/AdminPanel/Hosts/hosts.pm deleted file mode 100644 index 3186be11..00000000 --- a/AdminPanel/Hosts/hosts.pm +++ /dev/null @@ -1,103 +0,0 @@ -# vim: set et ts=4 sw=4: -#***************************************************************************** -# -# Copyright (c) 2013-2014 Matteo Pasotti -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2, as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -#***************************************************************************** -package AdminPanel::Hosts::hosts; - -use Moose; -use diagnostics; -use local::lib; -use Config::Hosts; -use utf8; - -# costants by Config::Hosts -my $is_ip = 1; -my $is_host = -1; -my $is_none = 0; - -has 'configHosts' => ( - is => 'rw', - init_arg => undef, - builder => '_initialize' -); - -sub _initialize { - my $self = shift(); - $self->configHosts(Config::Hosts->new()); -} - -=pod - -=head2 _getHosts - -=head3 OUTPUT - - @result: array of hashes; each one of them represent a host definition from the hosts configuration file - - NOTE: the 'hosts' item into each hash is an array: it contains the hostname and -eventually- the aliases - -=head3 DESCRIPTION - -retrieve data from the hosts file (/etc/hosts) using the Config::Hosts module - -=cut - -sub _getHosts { - my $self = shift(); - # $self->configHosts(Config::Hosts->new()); - my $hosts = $self->configHosts->read_hosts(); - my @result = (); - while( my ($key, $value) = each($hosts)){ - if($self->configHosts->determine_ip_or_host($key) == $is_ip){ - my $tmp = {}; - $tmp = $self->configHosts->query_host($key); - $tmp->{'ip'} = $key; - push @result,$tmp; - } - } - return @result; -} - -sub _insertHost { - my $self = shift(); - # remember that the order matters! - my $ip = shift(); - my @host_definitions = @_; - # $self->configHosts = Config::Hosts->new(); - return $self->configHosts->insert_host(ip => $ip, hosts => @host_definitions); -} - -sub _dropHost { - my $self = shift(); - my $host_ip = shift(); - return $self->configHosts->delete_host($host_ip); -} - -sub _modifyHost { - my $self = shift(); - my $host_ip = shift(); - my @host_definitions = @_; - return $self->configHosts->update_host($host_ip, hosts => @host_definitions); -} - -sub _writeHosts { - my $self = shift(); - return $self->configHosts->write_hosts(); -} - -1; diff --git a/AdminPanel/LogViewer/init.pm b/AdminPanel/LogViewer/init.pm deleted file mode 100644 index 1c961712..00000000 --- a/AdminPanel/LogViewer/init.pm +++ /dev/null @@ -1,31 +0,0 @@ -package AdminPanel::LogViewer::init; - -use strict; -use warnings; -use diagnostics; -use English; -use lib qw(/usr/lib/libDrakX); -use common; -use AdminPanel::Shared; -use base qw(Exporter); - -our @EXPORT = qw(warn_about_user_mode - interactive_msg); - -sub interactive_msg { - my ($title, $contents) = @_; - return ask_YesOrNo($title, $contents); -} - -sub warn_about_user_mode() { - my $title = N("Running in user mode"); - my $msg = N("You are launching this program as a normal user.\n". - "You will not be able to read system logs which you do not have rights to,\n". - "but you may still browse all the others."); - if(($EUID != 0) and (!interactive_msg($title, $msg))) { - return 0; - } - return 1; -} - -1; diff --git a/AdminPanel/Privileges.pm b/AdminPanel/Privileges.pm deleted file mode 100644 index 73f20984..00000000 --- a/AdminPanel/Privileges.pm +++ /dev/null @@ -1,61 +0,0 @@ -# vim: set et ts=4 sw=4: -# Copyright 2012-2013 Matteo Pasotti -# -# This file is part of AdminPanel -# -# AdminPanel is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# AdminPanel is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with AdminPanel. If not, see . - -package AdminPanel::Privileges; - -use strict; -use warnings; -use diagnostics; -require Exporter; -use base qw(Exporter); -use English qw(-no_match_vars); - -our @EXPORT = qw(require_root_capability - ask_for_authentication); - -my $wrappers = { "sudo" => "sudo", - "pkit" => "pkexec", - "chlp" => "consolehelper" - }; - -my $wrapper = 0; - -sub require_root_capability { - return $EUID != 0; -} - -sub ask_for_authentication { - my $wrapper_id = shift; - $wrapper = $wrappers->{$wrapper_id} if(defined($wrappers->{$wrapper_id})); - my ($command, @args) = wrap_command($0, @ARGV); - unshift(@args,$command->[1]); - unshift(@args, '-n') if($wrapper_id eq "sudo"); # let sudo die if password is needed - exec { $command->[0] } $command->[1], @args or die ("command %s missing", $command->[0]); -} - -sub wrap_command { - my ($app, @args) = @_; - return ([$wrapper, $app], @args); -} - -sub get_wrapper { - my $id = shift; - return $wrappers->{$id} if(defined($wrappers->{$id})); -} - -1; diff --git a/AdminPanel/Rpmdragora/.perl_checker b/AdminPanel/Rpmdragora/.perl_checker deleted file mode 100644 index 202e0535..00000000 --- a/AdminPanel/Rpmdragora/.perl_checker +++ /dev/null @@ -1 +0,0 @@ -Basedir .. diff --git a/AdminPanel/Rpmdragora/edit_urpm_sources.pm b/AdminPanel/Rpmdragora/edit_urpm_sources.pm deleted file mode 100644 index 9ef5d00b..00000000 --- a/AdminPanel/Rpmdragora/edit_urpm_sources.pm +++ /dev/null @@ -1,1216 +0,0 @@ -# vim: set et ts=4 sw=4: -package AdminPanel::Rpmdragora::edit_urpm_sources; -#***************************************************************************** -# -# Copyright (c) 2002 Guillaume Cottenceau -# Copyright (c) 2002-2007 Thierry Vignaud -# Copyright (c) 2002-2007 Mandriva Linux -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2, as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -#***************************************************************************** -# -# $Id: edit_urpm_sources.pm 266598 2010-03-03 12:00:58Z tv $ - - -use strict; -use lib qw(/usr/lib/libDrakX); -use common; -use AdminPanel::rpmdragora; -use AdminPanel::Rpmdragora::open_db; -use AdminPanel::Rpmdragora::formatting; -use URPM::Signature; -use MDK::Common::Math qw(max); -use urpm::media; -use urpm::download; -use urpm::lock; - -use Exporter; -our @ISA = qw(Exporter); -our @EXPORT = qw(run); - -#use mygtk2 qw(gtknew gtkset); -#use ugtk2 qw(:all); - -my $urpm; -my ($mainw, $list_tv, $something_changed); - -my %col = ( - mainw => { - is_enabled => 0, - is_update => 1, - type => 2, - name => 3, - activatable => 4 - }, -); - - -sub get_medium_type { - my ($medium) = @_; - my %medium_type = ( - cdrom => N("CD-ROM"), - ftp => N("FTP"), - file => N("Local"), - http => N("HTTP"), - https => N("HTTPS"), - nfs => N("NFS"), - removable => N("Removable"), - rsync => N("rsync"), - ssh => N("NFS"), - ); - return N("Mirror list") if $medium->{mirrorlist}; - return $medium_type{$1} if $medium->{url} =~ m!^([^:]*)://!; - return 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() { - distro_type(0) eq 'updates' ? interactive_msg( - N("Choose media type"), -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 => N("Full set of sources"), no => 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; - my $distro = $rpmdragora::mandrake_release; - my ($mirror) = choose_mirror($urpm, message => -N("This will attempt to install all official sources corresponding to your -distribution (%s). - -I need to contact the Mageia website to get the mirror list. -Please check that your network is currently running. - -Is it ok to continue?", $distro), - transient => $::main_window, - ) or return 0; - ref $mirror or return; - my $wait = wait_msg(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; - warn_for_network_need(undef, transient => $::main_window) or return; - my $wait = wait_msg(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; -} - -sub add_callback() { - my $w = ugtk2->new(N("Add a medium"), grab => 1, center => 1, transient => $::main_window); - my $prev_main_window = $::main_window; - local $::main_window = $w->{real_window}; - my %radios_infos = ( - local => { name => N("Local files"), url => N("Medium path:"), dirsel => 1 }, - ftp => { name => N("FTP server"), url => N("URL:"), loginpass => 1 }, - rsync => { name => N("RSYNC server"), url => N("URL:") }, - http => { name => N("HTTP server"), url => N("URL:") }, - removable => { name => N("Removable device (CD-ROM, DVD, ...)"), url => N("Path or mount point:"), dirsel => 1 }, - ); - my @radios_names_ordered = qw(local ftp rsync http removable); - # TODO: replace NoteBook by sensitive widgets and Label->set() - my $notebook = gtknew('Notebook'); - $notebook->set_show_tabs(0); $notebook->set_show_border(0); - my ($count_nbs, %pages); - my $size_group = Gtk2::SizeGroup->new('horizontal'); - my ($cb1, $cb2); - foreach (@radios_names_ordered) { - my $info = $radios_infos{$_}; - my $url_entry = sub { - gtkpack_( - gtknew('HBox'), - 1, $info->{url_entry} = gtkentry(), - if_( - $info->{dirsel}, - 0, gtksignal_connect( - gtknew('Button', text => but(N("Browse..."))), - clicked => sub { $info->{url_entry}->set_text(ask_dir()) }, - ) - ), - ); - }; - my $checkbut_entry = sub { - my ($name, $label, $visibility, $callback, $tip) = @_; - my $w = [ gtksignal_connect( - $info->{$name . '_check'} = gtkset(gtknew('CheckButton', text => $label), tip => $tip), - clicked => sub { - $info->{$name . '_entry'}->set_sensitive($_[0]->get_active); - $callback and $callback->(@_); - }, - ), - gtkset_visibility(gtkset_sensitive($info->{$name . '_entry'} = gtkentry(), 0), $visibility) ]; - $size_group->add_widget($info->{$name . '_check'}); - $w; - }; - my $loginpass_entries = sub { - map { - $checkbut_entry->( - @$_, sub { - $info->{pass_check}->set_active($_[0]->get_active); - $info->{login_check}->set_active($_[0]->get_active); - } - ); - } ([ 'login', N("Login:"), 1 ], [ 'pass', N("Password:"), 0 ]); - }; - $pages{$info->{name}} = $count_nbs++; - $notebook->append_page( - gtkshow(create_packtable( - { xpadding => 0, ypadding => 0 }, - [ gtkset_alignment(gtknew('Label', text => N("Medium name:")), 0, 0.5), - $info->{name_entry} = gtkentry('') ], - [ gtkset_alignment(gtknew('Label', text => $info->{url}), 0, 0.5), - $url_entry->() ], - if_($info->{loginpass}, $loginpass_entries->()), - sub { - [ $info->{distrib_check} = $cb1 = gtknew('CheckButton', text => N("Create media for a whole distribution"), - toggled => sub { - return if !$cb2; - my ($w) = @_; - $info->{update_check}->set_sensitive(!$w->get_active); - }) - ]; - }->(), - sub { - [ $info->{update_check} = $cb2 = gtknew('CheckButton', text => N("Tag this medium as an update medium")) ]; - }->(), - )) - ); - } - $size_group->add_widget($_) foreach $cb1, $cb2; - - my $checkok = sub { - my $info = $radios_infos{$radios_names_ordered[$notebook->get_current_page]}; - my ($name, $url) = map { $info->{$_ . '_entry'}->get_text } qw(name url); - $name eq '' || $url eq '' and interactive_msg('rpmdragora', N("You need to fill up at least the two first entries.")), return 0; - if (member($name, map { $_->{name} } @{$urpm->{media}})) { - $info->{name_entry}->select_region(0, -1); - interactive_msg('rpmdragora', -N("There is already a medium by that name, do you -really want to replace it?"), yesno => 1) or return 0; - } - 1; - }; - - my $type = 'local'; - my (%i, %make_url); - gtkadd( - $w->{window}, - gtkpack( - gtknew('VBox', spacing => 5), - gtknew('Title2', label => N("Adding a medium:")), - gtknew('HBox', children_tight => [ - Gtk2::Label->new(but(N("Type of medium:"))), - gtknew('ComboBox', text_ref => \$type, - list => \@radios_names_ordered, - format => sub { $radios_infos{$_[0]}{name} }, - changed => sub { $notebook->set_current_page($pages{$_[0]->get_text}) }) - ]), - $notebook, - gtknew('HSeparator'), - gtkpack( - gtknew('HButtonBox'), - gtknew('Button', text => N("Cancel"), clicked => sub { $w->{retval} = 0; Gtk2->main_quit }), - gtksignal_connect( - gtknew('Button', text => N("Ok")), clicked => sub { - if ($checkok->()) { - $w->{retval} = { nb => $notebook->get_current_page }; - my $info = $radios_infos{$type}; - %i = ( - name => $info->{name_entry}->get_text, - url => $info->{url_entry}->get_text, - distrib => $info->{distrib_check} ? $info->{distrib_check}->get_active : 0, - update => $info->{update_check}->get_active ? 1 : undef, - ); - %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", - $info->{login_check}->get_active - ? ($info->{login_entry}->get_text . ':' . $info->{pass_entry}->get_text . '@') - : '', - $i{url}; - Gtk2->main_quit; - } - }, - ), - ), - ), - ); - - if ($w->main) { - $::main_window = $prev_main_window; - if ($i{distrib}) { - add_medium_and_check( - $urpm, - { nolock => 1, distrib => 1 }, - $i{name}, $make_url{$type}, 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{$type}, $i{hdlist}, update => $i{update}, - ); - } - return 1; - } - return 0; -} - -sub options_callback() { - my $w = ugtk2->new(N("Global options for package installation"), grab => 1, center => 1, transient => $::main_window); - local $::main_window = $w->{real_window}; - my %verif = (0 => N("never"), 1 => N("always")); - my $verify_rpm = $urpm->{global_config}{'verify-rpm'}; - my @avail_downloaders = urpm::download::available_ftp_http_downloaders(); - my $downloader = $urpm->{global_config}{downloader} || $avail_downloaders[0]; - my %xml_info_policies = ( - 'never' => N("Never"), - 'on-demand' => N("On-demand"), - 'update-only' => N("Update-only"), - 'always' => N("Always"), - ); - my $xml_info_policy = $urpm->{global_config}{'xml-info'}; - - gtkadd( - $w->{window}, - gtkpack( - gtknew('VBox', spacing => 5), - gtknew('HBox', children_loose => [ gtknew('Label', text => N("Verify RPMs to be installed:")), - gtknew('ComboBox', list => [ keys %verif ], text_ref => \$verify_rpm, - format => sub { $verif{$_[0]} || $_[0] }, - ) - ]), - gtknew('HBox', children_loose => [ gtknew('Label', text => N("Download program to use:")), - gtknew('ComboBox', list => \@avail_downloaders, text_ref => \$downloader, - format => sub { $verif{$_[0]} || $_[0] }, - ) - ]), - gtknew('HBox', - children_loose => - [ gtknew('Label', text => N("XML meta-data download policy:")), - gtknew('ComboBox', - list => [ keys %xml_info_policies ], text_ref => \$xml_info_policy, - - format => sub { $xml_info_policies{$_[0]} || $_[0] }, - tip => - join("\n", - N("For remote media, specify when XML meta-data (file lists, changelogs & information) are downloaded."), - '', - N("Never"), - N("For remote media, XML meta-data are never downloaded."), - '', - N("On-demand"), - N("(This is the default)"), - N("The specific XML info file is downloaded when clicking on package."), - '', - N("Update-only"), - N("Updating media implies updating XML info files already required at least once."), - '', - N("Always"), - N("All XML info files are downloaded when adding or updating media."), - ), - ), - ]), - - gtkpack( - gtknew('HButtonBox'), - gtknew('Button', text => N("Cancel"), clicked => sub { Gtk2->main_quit }), - gtksignal_connect( - gtknew('Button', text => N("Ok")), clicked => sub { - $urpm->{global_config}{'verify-rpm'} = $verify_rpm; - $urpm->{global_config}{downloader} = $downloader; - $urpm->{global_config}{'xml-info'} = $xml_info_policy; - $something_changed = 1; - urpm::media::write_config($urpm); - $urpm = fast_open_urpmi_db(); - Gtk2->main_quit; - }, - ), - ), - ), - ); - $w->main; -} - -sub remove_callback() { - my @rows = selected_rows(); - @rows == 0 and return; - interactive_msg( - N("Source Removal"), - @rows == 1 ? - N("Are you sure you want to remove source \"%s\"?", $urpm->{media}[$rows[0]]{name}) : - N("Are you sure you want to remove the following sources?") . "\n\n" . - format_list(map { $urpm->{media}[$_]{name} } @rows), - yesno => 1, scroll => 1, - transient => $::main_window, - ) or return; - - my $wait = wait_msg(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; -} - -sub renum_media ($$$) { - my ($model, @iters) = @_; - my @rows = map { $model->get_path($_)->to_string } @iters; - my @media = map { $urpm->{media}[$_] } @rows; - $urpm->{media}[$rows[$_]] = $media[1 - $_] foreach 0, 1; - $model->swap(@iters); - $something_changed = 1; - urpm::media::write_config($urpm); - $urpm = fast_open_urpmi_db(); -} - -sub upwards_callback() { - my @rows = selected_rows(); - @rows == 0 and return; - my $model = $list_tv->get_model; - my $prev = $model->get_iter_from_string($rows[0] - 1); - defined $prev and renum_media($model, $model->get_iter_from_string($rows[0]), $prev); - $list_tv->get_selection->signal_emit('changed'); -} - -sub downwards_callback() { - my @rows = selected_rows(); - @rows == 0 and return; - my $model = $list_tv->get_model; - my $iter = $model->get_iter_from_string($rows[0]); - my $next = $model->iter_next($iter); - defined $next and renum_media($model, $iter, $next); - $list_tv->get_selection->signal_emit('changed'); -} - -#- returns the name of the media for which edition failed, or undef on success -sub edit_callback() { - my ($row) = selected_rows(); - $row == -1 and return; - 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 $old_main_window = $::main_window; - my $w = ugtk2->new(N("Edit a medium"), grab => 1, center => 1, transient => $::main_window); - local $::main_window = $w->{real_window}; - my ($url_entry, $downloader_entry, $url, $downloader); - gtkadd( - $w->{window}, - gtkpack_( - gtknew('VBox', spacing => 5), - 0, gtknew('Title2', label => N("Editing medium \"%s\":", $medium->{name})), - 0, create_packtable( - {}, - [ gtknew('Label_Left', text => N("URL:")), $url_entry = gtkentry($verbatim_medium->{url} || $verbatim_medium->{mirrorlist}) ], - [ gtknew('Label_Left', text => N("Downloader:")), - my $download_combo = Gtk2::ComboBox->new_with_strings([ urpm::download::available_ftp_http_downloaders() ], - $verbatim_medium->{downloader} || '') ], - ), - 0, gtknew('HSeparator'), - 0, gtkpack( - gtknew('HButtonBox'), - gtksignal_connect( - gtknew('Button', text => N("Cancel")), - clicked => sub { $w->{retval} = 0; Gtk2->main_quit }, - ), - gtksignal_connect( - gtknew('Button', text => N("Save changes")), - clicked => sub { - $w->{retval} = 1; - $url = $url_entry->get_text; - $downloader = $downloader_entry->get_text; - Gtk2->main_quit; - }, - ), - gtksignal_connect( - gtknew('Button', text => N("Proxy...")), - clicked => sub { proxy_callback($medium) }, - ), - ) - ) - ); - $downloader_entry = $download_combo->entry; - $w->{rwindow}->set_size_request(600, -1); - if ($w->main) { - my ($name, $update) = map { $medium->{$_} } qw(name update); - $url =~ m|^removable://| and ( - interactive_msg( - N("You need to insert the medium to continue"), - N("In order to save the changes, you need to insert the medium in the drive."), - yesno => 1, text => { yes => N("Ok"), no => N("Cancel") } - ) or return 0 - ); - my $saved_proxy = urpm::download::get_proxy($name); - undef $saved_proxy if !defined $saved_proxy->{http_proxy} && !defined $saved_proxy->{ftp_proxy}; - urpm::media::select_media($urpm, $name); - if (my ($media) = grep { $_->{name} eq $name } @{$urpm->{media}}) { - put_in_hash($media, { - ($verbatim_medium->{mirrorlist} ? 'mirrorlist' : 'url') => $url, - name => $name, - if_($update ne $media->{update} || $update, update => $update), - if_($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); - local $::main_window = $old_main_window; - update_sources_noninteractive($urpm, [ $name ], transient => $::main_window, nolock => 1); - } else { - urpm::media::remove_selected_media($urpm); - add_medium_and_check($urpm, { nolock => 1, proxy => $saved_proxy }, $name, $url, undef, update => $update, if_($downloader, downloader => $downloader)); - } - return $name; - } - return undef; -} - -sub update_callback() { - update_sources_interactive($urpm, transient => $::main_window, nolock => 1); -} - -sub proxy_callback { - my ($medium) = @_; - my $medium_name = $medium ? $medium->{name} : ''; - my $w = ugtk2->new(N("Configure proxies"), grab => 1, center => 1, transient => $::main_window); - local $::main_window = $w->{real_window}; - require curl_download; - my ($proxy, $proxy_user) = curl_download::readproxy($medium_name); - my ($user, $pass) = $proxy_user =~ /^([^:]*):(.*)$/; - my ($proxybutton, $proxyentry, $proxyuserbutton, $proxyuserentry, $proxypasswordentry); - my $sg = Gtk2::SizeGroup->new('horizontal'); - gtkadd( - $w->{window}, - gtkpack__( - gtknew('VBox', spacing => 5), - gtknew('Title2', label => - $medium_name - ? N("Proxy settings for media \"%s\"", $medium_name) - : N("Global proxy settings") - ), - gtknew('Label_Left', text => N("If you need a proxy, enter the hostname and an optional port (syntax: ):")), - gtkpack_( - gtknew('HBox', spacing => 10), - 1, gtkset_active($proxybutton = gtknew('CheckButton', text => N("Proxy hostname:")), to_bool($proxy)), - 0, gtkadd_widget($sg, gtkset_sensitive($proxyentry = gtkentry($proxy), to_bool($proxy))), - ), - gtkset_active($proxyuserbutton = gtknew('CheckButton', text => N("You may specify a username/password for the proxy authentication:")), to_bool($proxy_user)), - gtkpack_( - my $hb_user = gtknew('HBox', spacing => 10, sensitive => to_bool($proxy_user)), - 1, gtknew('Label_Left', text => N("User:")), - 0, gtkadd_widget($sg, $proxyuserentry = gtkentry($user)), - ), - gtkpack_( - my $hb_pswd = gtknew('HBox', spacing => 10, sensitive => to_bool($proxy_user)), - 1, gtknew('Label_Left', text => N("Password:")), - 0, gtkadd_widget($sg, gtkset_visibility($proxypasswordentry = gtkentry($pass), 0)), - ), - gtknew('HSeparator'), - gtkpack( - gtknew('HButtonBox'), - gtksignal_connect( - gtknew('Button', text => N("Ok")), - clicked => sub { - $w->{retval} = 1; - $proxy = $proxybutton->get_active ? $proxyentry->get_text : ''; - $proxy_user = $proxyuserbutton->get_active - ? ($proxyuserentry->get_text . ':' . $proxypasswordentry->get_text) : ''; - Gtk2->main_quit; - }, - ), - gtksignal_connect( - gtknew('Button', text => N("Cancel")), - clicked => sub { $w->{retval} = 0; Gtk2->main_quit }, - ) - ) - ) - ); - $sg->add_widget($_) foreach $proxyentry, $proxyuserentry, $proxypasswordentry; - $proxybutton->signal_connect( - clicked => sub { - $proxyentry->set_sensitive($_[0]->get_active); - $_[0]->get_active and return; - $proxyuserbutton->set_active(0); - $hb_user->set_sensitive(0); - $hb_pswd->set_sensitive(0); - } - ); - $proxyuserbutton->signal_connect(clicked => sub { $_->set_sensitive($_[0]->get_active) foreach $hb_user, $hb_pswd; - $proxypasswordentry->set_sensitive($_[0]->get_active) }); - - $w->main and do { - $something_changed = 1; - curl_download::writeproxy($proxy, $proxy_user, $medium_name); - }; -} - -sub parallel_read_sysconf() { - my @conf; - foreach (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 => N("Ok"), clicked => sub { $w->{retval} = 1; $get_value->(); Gtk2->main_quit }), - gtknew('Button', text => 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 ? N("Add a parallel group") : 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_(N("Add a medium limit"), 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_(N("Add a host"), 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 => N("Editing parallel group \"%s\":", $edited->{name})) - ), - 1, create_packtable( - {}, - [ N("Group name:"), $name_entry = gtkentry($edited->{name}) ], - [ N("Protocol:"), gtknew('HBox', children_tight => [ - @protocols = gtkradio($edited->{protocol}, @protocols_names) ]) ], - [ 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(N("Add"))), clicked => sub { $add_media->() }), - gtksignal_connect(Gtk2::Button->new(but(N("Remove"))), clicked => sub { - remove_from_list($medias, $edited->{medias}, $medias_ls); - }) ]) ]) ], - [ 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(N("Add"))), clicked => sub { $add_host->() }), - gtksignal_connect(Gtk2::Button->new(but(N("Remove"))), clicked => sub { - remove_from_list($hosts, $hosts_list, $hosts_ls); - }) ]) ]) ] - ), - 0, gtknew('HSeparator'), - 0, gtkpack( - gtknew('HButtonBox'), - gtksignal_connect( - gtknew('Button', text => 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 => 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(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)) } N("Group"), N("Protocol"), N("Media limit"); - $list->append_column(my $commandcol = Gtk2::TreeViewColumn->new_with_attributes(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}}) : 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(N("Remove"))), - clicked => sub { remove_parallel(selrow($list), $conf); $reread->() }, - ), - gtksignal_connect( - Gtk2::Button->new(but(N("Edit..."))), - clicked => sub { - my $row = selrow($list); - $row != -1 and edit_parallel($row, $conf); - $reread->(); - }, - ), - gtksignal_connect( - Gtk2::Button->new(but(N("Add..."))), - clicked => sub { edit_parallel(-1, $conf) and $reread->() }, - ) - ) - ), - 0, gtknew('HSeparator'), - 0, gtkpack( - gtknew('HButtonBox'), - gtknew('Button', text => N("Ok"), clicked => sub { Gtk2->main_quit }) - ) - ) - ); - $w->main; -} - -sub keys_callback() { - my $w = ugtk2->new(N("Manage keys for digital signatures of packages"), grab => 1, center => 1, transient => $mainw->{real_window}); - local $::main_window = $w->{real_window}; - $w->{real_window}->set_size_request(600, 300); - - my $media_list_ls = Gtk2::ListStore->new("Glib::String"); - my $media_list = Gtk2::TreeView->new_with_model($media_list_ls); - $media_list->append_column(Gtk2::TreeViewColumn->new_with_attributes(N("Medium"), Gtk2::CellRendererText->new, 'text' => 0)); - $media_list->get_selection->set_mode('browse'); - - my $key_col_size = 200; - my $keys_list_ls = Gtk2::ListStore->new("Glib::String", "Glib::String"); - my $keys_list = Gtk2::TreeView->new_with_model($keys_list_ls); - $keys_list->set_rules_hint(1); - $keys_list->append_column(my $col = Gtk2::TreeViewColumn->new_with_attributes(N("_:cryptographic keys\nKeys"), my $renderer = Gtk2::CellRendererText->new, 'text' => 0)); - $col->set_sizing('fixed'); - $col->set_fixed_width($key_col_size); - $renderer->set_property('width' => 1); - $renderer->set_property('wrap-width', $key_col_size); - $keys_list->get_selection->set_mode('browse'); - - my ($current_medium, $current_medium_nb, @keys); - - 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->(); - $media_list->get_selection->signal_emit('changed'); - }; - $read_conf->(); - my $key_name = sub { - exists $urpm->{keys}{$_[0]} ? $urpm->{keys}{$_[0]}{name} - : N("no name found, key doesn't exist in rpm keyring!"); - }; - $media_list_ls->append_set([ 0 => $_->{name} ]) foreach @{$urpm->{media}}; - $media_list->get_selection->signal_connect(changed => sub { - my ($model, $iter) = $_[0]->get_selected; - $model && $iter or return; - $current_medium = $model->get($iter, 0); - $current_medium_nb = $model->get_path($iter)->to_string; - $keys_list_ls->clear; - $keys_list_ls->append_set([ 0 => sprintf("%s (%s)", $_, $key_name->($_)), 1 => $_ ]) foreach @{$keys[$current_medium_nb]}; - }); - - my $add_key = sub { - my $available_keyz_ls = Gtk2::ListStore->new("Glib::String", "Glib::String"); - my $available_keyz = Gtk2::TreeView->new_with_model($available_keyz_ls); - $available_keyz->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, 'text' => 0)); - $available_keyz->set_headers_visible(0); - $available_keyz->get_selection->set_mode('browse'); - $available_keyz_ls->append_set([ 0 => sprintf("%s (%s)", $_, $key_name->($_)), 1 => $_ ]) foreach keys %{$urpm->{keys}}; - my $key; - add_callback_(N("Add a key"), N("Choose a key to add to the medium %s", $current_medium), $w, $available_keyz, - sub { - my ($model, $iter) = $available_keyz->get_selection->get_selected; - $model && $iter and $key = $model->get($iter, 1); - }, - sub { - return if !defined $key; - $urpm->{media}[$current_medium_nb]{'key-ids'} = join(',', sort(uniq(@{$keys[$current_medium_nb]}, $key))); - $write->(); - } - ); - - - }; - - my $remove_key = sub { - my ($model, $iter) = $keys_list->get_selection->get_selected; - $model && $iter or return; - my $key = $model->get($iter, 1); - interactive_msg(N("Remove a key"), - N("Are you sure you want to remove the key %s from medium %s?\n(name of the key: %s)", - $key, $current_medium, $key_name->($key)), - yesno => 1, transient => $w->{real_window}) or return; - $urpm->{media}[$current_medium_nb]{'key-ids'} = join(',', difference2(\@{$keys[$current_medium_nb]}, [ $key ])); - $write->(); - }; - - gtkadd( - $w->{window}, - gtkpack_( - gtknew('VBox', spacing => 5), - 1, gtkpack_( - gtknew('HBox', spacing => 10), - 1, create_scrolled_window($media_list), - 1, create_scrolled_window($keys_list), - 0, gtkpack__( - gtknew('VBox', spacing => 5), - gtksignal_connect( - Gtk2::Button->new(but(N("Add"))), - clicked => \&$add_key, - ), - gtksignal_connect( - Gtk2::Button->new(but(N("Remove"))), - clicked => \&$remove_key, - ) - ) - ), - 0, gtknew('HSeparator'), - 0, gtkpack( - gtknew('HButtonBox'), - gtknew('Button', text => N("Ok"), clicked => sub { Gtk2->main_quit }) - ), - ), - ); - $w->main; -} - -sub mainwindow() { - undef $something_changed; - $mainw = ugtk2->new(N("Configure media"), center => 1, transient => $::main_window, modal => 1); - local $::main_window = $mainw->{real_window}; - - my $reread_media; - - my ($menu, $_factory) = create_factory_menu( - $mainw->{real_window}, - [ N("/_File"), undef, undef, undef, '' ], - [ N("/_File") . N("/_Update"), N("U"), sub { update_callback() and $reread_media->() }, undef, '', ], - [ N("/_File") . N("/Add a specific _media mirror"), N("M"), sub { easy_add_callback_with_mirror() and $reread_media->() }, undef, '' ], - [ N("/_File") . N("/_Add a custom medium"), N("A"), sub { add_callback() and $reread_media->() }, undef, '' ], - [ N("/_File") . N("/Close"), N("W"), sub { Gtk2->main_quit }, undef, '', ], - [ N("/_Options"), undef, undef, undef, '' ], - [ N("/_Options") . N("/_Global options"), N("G"), \&options_callback, undef, '' ], - [ N("/_Options") . N("/Manage _keys"), N("K"), \&keys_callback, undef, '' ], - [ N("/_Options") . N("/_Parallel"), N("P"), \¶llel_callback, undef, '' ], - [ N("/_Options") . N("/P_roxy"), N("R"), \&proxy_callback, undef, '' ], - if_($0 =~ /edit-urpm-sources/, - [ N("/_Help"), undef, undef, undef, '' ], - [ N("/_Help") . N("/_Report Bug"), undef, sub { run_drakbug('edit-urpm-sources.pl') }, undef, '' ], - [ N("/_Help") . N("/_Help"), undef, sub { rpmdragora::open_help('sources') }, undef, '' ], - [ N("/_Help") . N("/_About..."), undef, sub { - my $license = formatAlaTeX(translate($::license)); - $license =~ s/\n/\n\n/sg; # nicer formatting - my $w = gtknew('AboutDialog', name => N("Rpmdragora"), - version => $rpmdragora::distro_version, - copyright => N("Copyright (C) %s by Mandriva", '2002-2008'), - license => $license, wrap_license => 1, - comments => N("Rpmdragora is the Mageia package management tool."), - website => 'http://www.mageia.org/', - website_label => N("Mageia"), - authors => 'Thierry Vignaud ', - artists => 'Hรฉlรจne Durosini ', - translator_credits => - #-PO: put here name(s) and email(s) of translator(s) (eg: "John Smith ") - N("_: Translator(s) name(s) & email(s)\n"), - transient_for => $::main_window, modal => 1, position_policy => 'center-on-parent', - ); - $w->show_all; - $w->run; - }, undef, '' - ] - ), - ); - - my $list = Gtk2::ListStore->new("Glib::Boolean", "Glib::Boolean", "Glib::String", "Glib::String", "Glib::Boolean"); - $list_tv = Gtk2::TreeView->new_with_model($list); - $list_tv->get_selection->set_mode('multiple'); - my ($dw_button, $edit_button, $remove_button, $up_button); - $list_tv->get_selection->signal_connect(changed => sub { - my ($selection) = @_; - my @rows = $selection->get_selected_rows; - my $model = $list; - # we can delete several medium at a time: - $remove_button and $remove_button->set_sensitive($#rows != -1); - # we can only edit/move one item at a time: - $_ and $_->set_sensitive(@rows == 1) foreach $up_button, $dw_button, $edit_button; - - # we can only up/down one item if not at begin/end: - return if @rows != 1; - - my $curr_path = $rows[0]; - my $first_path = $model->get_path($model->get_iter_first); - $up_button->set_sensitive($first_path && $first_path->compare($curr_path)); - - $curr_path->next; - my $next_item = $model->get_iter($curr_path); - $dw_button->set_sensitive($next_item); # && !$model->get($next_item, 0) - }); - - $list_tv->set_rules_hint(1); - $list_tv->set_reorderable(1); - - my $reorder_ok = 1; - $list->signal_connect( - row_deleted => sub { - $reorder_ok or return; - my ($model) = @_; - my @media; - $model->foreach( - sub { - my (undef, undef, $iter) = @_; - my $name = $model->get($iter, $col{mainw}{name}); - push @media, urpm::media::name2medium($urpm, $name); - 0; - }, undef); - @{$urpm->{media}} = @media; - }, - ); - - $list_tv->append_column(Gtk2::TreeViewColumn->new_with_attributes(N("Enabled"), - my $tr = Gtk2::CellRendererToggle->new, - 'active' => $col{mainw}{is_enabled})); - $list_tv->append_column(Gtk2::TreeViewColumn->new_with_attributes(N("Updates"), - my $cu = Gtk2::CellRendererToggle->new, - 'active' => $col{mainw}{is_update}, - activatable => $col{mainw}{activatable})); - $list_tv->append_column(Gtk2::TreeViewColumn->new_with_attributes(N("Type"), - Gtk2::CellRendererText->new, - 'text' => $col{mainw}{type})); - $list_tv->append_column(Gtk2::TreeViewColumn->new_with_attributes(N("Medium"), - Gtk2::CellRendererText->new, - 'text' => $col{mainw}{name})); - my $id; - $id = $tr->signal_connect( - toggled => sub { - my (undef, $path) = @_; - $tr->signal_handler_block($id); - my $_guard = before_leaving { $tr->signal_handler_unblock($id) }; - my $iter = $list->get_iter_from_string($path); - $urpm->{media}[$path]{ignore} = !$urpm->{media}[$path]{ignore} || undef; - $list->set($iter, $col{mainw}{is_enabled}, !$urpm->{media}[$path]{ignore}); - urpm::media::write_config($urpm); - my $ignored = $urpm->{media}[$path]{ignore}; - $reread_media->(); - if (!$ignored && $urpm->{media}[$path]{ignore}) { - # reread media failed to un-ignore an ignored medium - # probably because urpm::media::check_existing_medium() complains - # about missing synthesis when the medium never was enabled before; - # thus it restored the ignore bit - $urpm->{media}[$path]{ignore} = !$urpm->{media}[$path]{ignore} || undef; - urpm::media::write_config($urpm); - #- Enabling this media failed, force update - interactive_msg('rpmdragora', - N("This medium needs to be updated to be usable. Update it now?"), - yesno => 1, - ) and $reread_media->($urpm->{media}[$path]{name}); - } - }, - ); - - $cu->signal_connect( - toggled => sub { - my (undef, $path) = @_; - my $iter = $list->get_iter_from_string($path); - $urpm->{media}[$path]{update} = !$urpm->{media}[$path]{update} || undef; - $list->set($iter, $col{mainw}{is_update}, ! !$urpm->{media}[$path]{update}); - $something_changed = 1; - }, - ); - - $reread_media = sub { - my ($name) = @_; - $reorder_ok = 0; - $something_changed = 1; - if (defined $name) { - urpm::media::select_media($urpm, $name); - update_sources_check( - $urpm, - { nolock => 1 }, - 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(); - $list->clear; - foreach (grep { ! $_->{external} } @{$urpm->{media}}) { - my $name = $_->{name}; - $list->append_set($col{mainw}{is_enabled} => !$_->{ignore}, - $col{mainw}{is_update} => ! !$_->{update}, - $col{mainw}{type} => get_medium_type($_), - $col{mainw}{name} => $name, - $col{mainw}{activatable} => to_bool($::expert), - ); - } - $reorder_ok = 1; - }; - $reread_media->(); - $something_changed = 0; - - gtkadd( - $mainw->{window}, - gtkpack_( - gtknew('VBox', spacing => 5), - 0, $menu, - ($0 =~ /rpm-edit-media|edit-urpm-sources/ ? (0, Gtk2::Banner->new($ugtk2::wm_icon, N("Configure media"))) : ()), - 1, gtkpack_( - gtknew('HBox', spacing => 10), - 1, gtknew('ScrolledWindow', child => $list_tv), - 0, gtkpack__( - gtknew('VBox', spacing => 5), - gtksignal_connect( - $remove_button = Gtk2::Button->new(but(N("Remove"))), - clicked => sub { remove_callback() and $reread_media->() }, - ), - gtksignal_connect( - $edit_button = Gtk2::Button->new(but(N("Edit"))), - clicked => sub { - my $name = edit_callback(); defined $name and $reread_media->($name); - } - ), - gtksignal_connect( - Gtk2::Button->new(but(N("Add"))), - clicked => sub { easy_add_callback() and $reread_media->() }, - ), - gtkpack( - gtknew('HBox'), - gtksignal_connect( - $up_button = gtknew('Button', - image => gtknew('Image', stock => 'gtk-go-up')), - clicked => \&upwards_callback), - - gtksignal_connect( - $dw_button = gtknew('Button', - image => gtknew('Image', stock => 'gtk-go-down')), - clicked => \&downwards_callback), - ), - ) - ), - 0, gtknew('HSeparator'), - 0, gtknew('HButtonBox', layout => 'edge', children_loose => [ - gtksignal_connect(Gtk2::Button->new(but(N("Help"))), clicked => sub { rpmdragora::open_help('sources') }), - gtksignal_connect(Gtk2::Button->new(but(N("Ok"))), clicked => sub { Gtk2->main_quit }) - ]) - ) - ); - $_->set_sensitive(0) foreach $dw_button, $edit_button, $remove_button, $up_button; - - $mainw->{rwindow}->set_size_request(600, 400); - $mainw->main; - return $something_changed; -} - - -sub run() { - # ignore rpmdragora's option regarding ignoring debug media: - local $ignore_debug_media = [ 0 ]; - local $ugtk2::wm_icon = get_icon('rpmdragora-mdk', 'title-media'); - my $lock; - { - $urpm = fast_open_urpmi_db(); - my $err_msg = "urpmdb locked\n"; - local $urpm->{fatal} = sub { - interactive_msg('rpmdragora', - N("The Package Database is locked. Please close other applications -working with the Package Database. Do you have another media -manager on another desktop, or are you currently installing -packages as well?")); - die $err_msg; - }; - # lock urpmi DB - eval { $lock = urpm::lock::urpmi_db($urpm, 'exclusive', wait => $urpm->{options}{wait_lock}) }; - if (my $err = $@) { - return if $err eq $err_msg; - die $err; - } - } - - my $res = mainwindow(); - urpm::media::write_config($urpm); - - writeconf(); - - undef $lock; - $res; -} - - -1; diff --git a/AdminPanel/Rpmdragora/formatting.pm b/AdminPanel/Rpmdragora/formatting.pm deleted file mode 100644 index ccbdf0c8..00000000 --- a/AdminPanel/Rpmdragora/formatting.pm +++ /dev/null @@ -1,192 +0,0 @@ -# vim: set et ts=4 sw=4: -package AdminPanel::Rpmdragora::formatting; -#***************************************************************************** -# -# Copyright (c) 2002 Guillaume Cottenceau -# Copyright (c) 2002-2006 Thierry Vignaud -# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA -# Copyright (c) 2005, 2006 Mandriva SA -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2, as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -#***************************************************************************** -# -# $Id: formatting.pm 261189 2009-10-01 14:44:39Z tv $ - -use strict; -use utf8; -use POSIX qw(strftime); -use AdminPanel::rpmdragora; -use lib qw(/usr/lib/libDrakX); -use MDK::Common::Various; # included for internal_error subroutine -use common; -#use ugtk2 qw(escape_text_for_TextView_markup_format); - -use Exporter; -our @ISA = qw(Exporter); -our @EXPORT = qw( - $spacing - ensure_utf8 - format_changelog_changelogs - format_changelog_string - format_field - format_header - format_list - format_name_n_summary - format_size - format_filesize - format_update_field - my_fullname - pkg2medium - rpm_description - split_fullname - urpm_name - ); - - -sub escape_text_for_TextView_markup_format { - my ($str) = @_; - my %rules = ('&' => '&', - '<' => '<', - '>' => '>', - ); - eval { $str =~ s!([&<>])!$rules{$1}!g }; #^(&(amp|lt|gt);)!!) { - if (my $err = $@) { - internal_error("$err\n$str"); - } - $str; -} - -# from rpmtools, #37482: -sub ensure_utf8 { - if (utf8::is_utf8($_[0])) { - utf8::valid($_[0]) and return; - - utf8::encode($_[0]); #- disable utf8 flag - utf8::upgrade($_[0]); - } else { - utf8::decode($_[0]); #- try to set utf8 flag - utf8::valid($_[0]) and return; - warn "do not know what to with $_[0]\n"; - } -} - -sub rpm_description { - my ($description) = @_; - ensure_utf8($description); - my ($t, $tmp); - foreach (split "\n", $description) { - s/^\s*//; - if (/^$/ || /^\s*(-|\*|\+|o)\s/) { - $t || $tmp and $t .= "$tmp\n"; - $tmp = $_; - } else { - $tmp = ($tmp ? "$tmp " : ($t && "\n") . $tmp) . $_; - } - } - "$t$tmp\n"; -} - -sub split_fullname { $_[0] =~ /^(.*)-([^-]+)-([^-]+)\.([^.-]+)$/ } - -sub my_fullname { - return '?-?-?' unless ref $_[0]; - my ($name, $version, $release) = $_[0]->fullname; - "$name-$version-$release"; -} - -sub urpm_name { - return '?-?-?.?' unless ref $_[0]; - scalar $_[0]->fullname; -} - -sub pkg2medium { - my ($p, $urpm) = @_; - return if !ref $p; - return { name => N("None (installed)") } if !defined($p->id); # if installed - URPM::pkg2media($urpm->{media}, $p) || { name => N("Unknown"), fake => 1 }; -} - -# [ duplicate urpmi's urpm::msg::localtime2changelog() ] -#- strftime returns a string in the locale charset encoding; -#- but gtk2 requires UTF-8, so we use to_utf8() to ensure the -#- output of localtime2changelog() is always in UTF-8 -#- as to_utf8() uses LC_CTYPE for locale encoding and strftime() uses LC_TIME, -#- it doesn't work if those two variables have values with different -#- encodings; but if a user has a so broken setup we can't do much anyway -sub localtime2changelog { to_utf8(POSIX::strftime("%c", localtime($_[0]))) } - -our $spacing = " "; -sub format_changelog_string { - my ($installed_version, $string) = @_; - #- preprocess changelog for faster TextView insert reaction - require Gtk2::Pango; - my %date_attr = ('weight' => Gtk2::Pango->PANGO_WEIGHT_BOLD); - my %update_attr = ('style' => 'italic'); - my $version; - my $highlight; - [ map { - my %attrs; - if (/^\*/) { - add2hash(\%attrs, \%date_attr); - ($version) = /(\S*-\S*)\s*$/; - $highlight = $installed_version ne N("(none)") && 0 < URPM::rpmvercmp($version, $installed_version); - } - add2hash(\%attrs, \%update_attr) if $highlight; - [ "$spacing$_\n", if_(%attrs, \%attrs) ]; - } split("\n", $string) ]; -} - -sub format_changelog_changelogs { - my ($installed_version, @changelogs) = @_; - format_changelog_string($installed_version, join("\n", map { - "* " . localtime2changelog($_->{time}) . " $_->{name}\n\n$_->{text}\n"; - } @changelogs)); -} - -sub format_update_field { - my ($name) = @_; - '' . eval { escape_text_for_TextView_markup_format($name) } . ''; -} - -sub format_name_n_summary { - my ($name, $summary) = @_; - join("\n", '' . $name . '', escape_text_for_TextView_markup_format($summary)); -} - -sub format_header { - my ($str) = @_; - '' . escape_text_for_TextView_markup_format($str) . ''; -} - -sub format_field { - my ($str) = @_; - '' . escape_text_for_TextView_markup_format($str) . ''; -} - -sub format_size { - my ($size) = @_; - $size >= 0 ? - N("%s of additional disk space will be used.", formatXiB($size)) : - N("%s of disk space will be freed.", formatXiB(-$size)); -} - -sub format_filesize { - my ($filesize) = @_; - $filesize ? N("%s of packages will be retrieved.", formatXiB($filesize)) : (); -} - -sub format_list { join("\n", map { s/^(\s)/ $1/mg; "- $_" } sort { uc($a) cmp uc($b) } @_) } - -1; diff --git a/AdminPanel/Rpmdragora/gui.pm b/AdminPanel/Rpmdragora/gui.pm deleted file mode 100644 index 66d41fda..00000000 --- a/AdminPanel/Rpmdragora/gui.pm +++ /dev/null @@ -1,1220 +0,0 @@ -# vim: set et ts=4 sw=4: -package AdminPanel::Rpmdragora::gui; -#***************************************************************************** -# -# Copyright (c) 2002 Guillaume Cottenceau -# Copyright (c) 2002-2007 Thierry Vignaud -# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA -# Copyright (c) 2005-2007 Mandriva SA -# Copyright (c) 2013 Matteo Pasotti -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2, as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -#***************************************************************************** -# -# $Id$ - -############################################################ -# WARNING: do not modify before asking matteo or anaselli -############################################################ - -use strict; -our @ISA = qw(Exporter); -use lib qw(/usr/lib/libDrakX); -use common; - -# TO WORKAROUND LOCALIZATION ISSUE -use AdminPanel::Rpmdragora::localization; - -use AdminPanel::rpmdragora; -use AdminPanel::Rpmdragora::open_db; -use AdminPanel::Rpmdragora::formatting; -use AdminPanel::Rpmdragora::init; -use AdminPanel::Rpmdragora::icon; -use AdminPanel::Rpmdragora::pkg; -use AdminPanel::Shared; -use yui; -use feature 'state'; - -our @EXPORT = qw( - $descriptions - $find_entry - $force_displaying_group - $force_rebuild - $pkgs - $results_ok - $results_none - $size_free - $size_selected - $urpm - %grp_columns - %pkg_columns - @filtered_pkgs - @initial_selection - ask_browse_tree_given_widgets_for_rpmdragora - build_tree - callback_choices - compute_main_window_size - do_action - get_info - get_summary - group_has_parent - group_parent - groups_tree - is_locale_available - node_state - pkgs_provider - real_quit - reset_search - set_node_state - sort_callback - switch_pkg_list_mode - toggle_all - toggle_nodes - fast_toggle - ); - -our ($descriptions, %filters, @filtered_pkgs, %filter_methods, $force_displaying_group, $force_rebuild, @initial_selection, $pkgs, $size_free, $size_selected, $urpm); -our ($results_ok, $results_none) = (N("Search results"), N("Search results (none)")); - -our %grp_columns = ( - label => 0, - icon => 2, -); - -our %pkg_columns = ( - text => 0, - state_icon => 1, - state => 2, - selected => 3, - short_name => 4, - version => 5, - release => 6, - 'arch' => 7, - selectable => 8, -); - -sub compute_main_window_size { - my ($w) = @_; - ($typical_width) = string_size($w->{real_window}, translate("Graphical Environment") . "xmms-more-vis-plugins"); - $typical_width > 600 and $typical_width = 600; #- try to not being crazy with a too large value - $typical_width < 150 and $typical_width = 150; -} - -sub get_summary { - my ($key) = @_; - my $summary = translate($pkgs->{$key}{pkg}->summary); - require utf8; - utf8::valid($summary) ? $summary : @{[]}; -} - -sub build_expander { - my ($pkg, $label, $type, $get_data, $o_installed_version) = @_; - my $textview; - gtkadd( - gtkshow(my $exp = gtksignal_connect( - Gtk2::Expander->new(format_field($label)), - activate => sub { - state $first; - return if $first; - $first = 1; - slow_func($::main_window->window, sub { - extract_header($pkg, $urpm, $type, $o_installed_version); - gtktext_insert($textview, $get_data->() || [ [ N("(Not available)") ] ]); - }); - })), - $textview = gtknew('TextView') - ); - $exp->set_use_markup(1); - $exp; -} - - -sub get_advisory_link { - my ($update_descr) = @_; - my $link = gtkshow(Gtk2::LinkButton->new($update_descr->{URL}, N("Security advisory"))); - $link->set_uri_hook(\&run_help_callback); - [ $link ]; -} - -sub get_description { - my ($pkg, $update_descr) = @_; - - join("
", - (eval { - $pkg->{description} || $update_descr->{description}; - } || ''. N("No description").'')); -} - -sub get_string_from_keywords { - my ($medium, $name) = @_; - my @media_types; - if ($medium->{mediacfg}) { - my ($distribconf, $medium_path) = @{$medium->{mediacfg}}; - @media_types = split(':', $distribconf->getvalue($medium_path, 'media_type')) if $distribconf; - } - - my $unsupported = N("It is not supported by Mageia."); - my $dangerous = N("It may break your system."); - my $s; - $s .= N("This package is not free software") . "\n" if member('non-free', @media_types); - if ($pkgs->{$name}{is_backport} || member('backport', @media_types)) { - return join("\n", - N("This package contains a new version that was backported."), - $unsupported, $dangerous, $s); - } elsif (member('testing', @media_types)) { - return join("\n", - N("This package is a potential candidate for an update."), - $unsupported, $dangerous, $s); - } elsif (member('updates', @media_types)) { - return join("\n", - (member('official', @media_types) ? - N("This is an official update which is supported by Mageia.") - : (N("This is an unofficial update."), $unsupported)) - , - $s); - } else { - $s .= N("This is an official package supported by Mageia") . "\n" if member('official', @media_types); - return $s; - } -} - -sub get_main_text { - my ($medium, $fullname, $name, $summary, $is_update, $update_descr) = @_; - - my $txt = get_string_from_keywords($medium, $fullname); - - join("
", - format_header(join(' - ', $name, $summary)) . - if_($txt, format_field(N("Notice: ")) . $txt), - if_($is_update, # is it an update? - format_field(N("Importance: ")) . format_update_field($update_descr->{importance}), - format_field(N("Reason for update: ")) . format_update_field(rpm_description($update_descr->{pre})), - ), - '' # extra empty line - ); -} - -sub get_details { - my ($pkg, $upkg, $installed_version, $raw_medium) = @_; - my @details = (); - push @details, format_field(N("Version: ")) . $upkg->EVR; - push @details, format_field(N("Currently installed version: ")) . $installed_version if($upkg->flag_installed); - push @details, format_field(N("Group: ")) . translate_group($upkg->group); - push @details, format_field(N("Architecture: ")) . $upkg->arch; - push @details, format_field(N("Size: ")) . N("%s KB", int($upkg->size/1024)); - push @details, eval { format_field(N("Medium: ")) . $raw_medium->{name} }; - - my @link = get_url_link($upkg, $pkg); - push @details, join("
   ",@link) if(@link); - unshift @details, "
   "; - join("
   ", @details); -} - -sub get_new_deps { - my ($urpm, $upkg) = @_; - my $deps_textview; - my @a = [ gtkadd( - gtksignal_connect( - gtkshow(my $dependencies = Gtk2::Expander->new(format_field(N("New dependencies:")))), - activate => sub { - slow_func($::main_window->window, sub { - my $state = {}; - my $db = open_rpm_db(); - my @requested = $urpm->resolve_requested__no_suggests_( - $db, $state, - { $upkg->id => 1 }, - ); - @requested = $urpm->resolve_requested_suggests($db, $state, \@requested); - undef $db; - my @nodes_with_deps = map { urpm_name($_) } @requested; - my @deps = sort { $a cmp $b } difference2(\@nodes_with_deps, [ urpm_name($upkg) ]); - @deps = N("All dependencies installed.") if !@deps; - gtktext_insert($deps_textview, join("\n", @deps)); - }); - } - ), - $deps_textview = gtknew('TextView') - ) ]; - $dependencies->set_use_markup(1); - @a; -} - -sub get_url_link { - my ($upkg, $pkg) = @_; - - my $url = $upkg->url || $pkg->{url}; - - if (!$url) { - open_rpm_db()->traverse_tag_find('name', $upkg->name, sub { $url = $_[0]->url }); - } - - return if !$url; - - my @a; - push @a, format_field(N("URL: "))."${spacing}$url"; - @a; -} - -sub files_format { - my ($files) = @_; - ugtk2::markup_to_TextView_format( - '' . $spacing #- to highlight information - . join("\n$spacing", map { "\x{200e}$_" } @$files) - . ''); -} - -sub format_pkg_simplifiedinfo { - my ($pkgs, $key, $urpm, $descriptions) = @_; - my ($name) = split_fullname($key); - my $pkg = $pkgs->{$key}; - my $upkg = $pkg->{pkg}; - return if !$upkg; - my $raw_medium = pkg2medium($upkg, $urpm); - my $medium = !$raw_medium->{fake} ? $raw_medium->{name} : undef; - my $update_descr = $descriptions->{$medium}{$name}; - # discard update fields if not matching: - my $is_update = ($upkg->flag_upgrade && $update_descr && $update_descr->{pre}); - my $summary = get_summary($key); - my $dummy_string = get_main_text($raw_medium, $key, $name, $summary, $is_update, $update_descr); - my $s; - push @$s, $dummy_string; - push @$s, get_advisory_link($update_descr) if $is_update; - - push @$s, get_description($pkg, $update_descr); - push @$s, [ "\n" ]; - my $installed_version = eval { find_installed_version($upkg) }; - - #push @$s, [ gtkadd(gtkshow(my $details_exp = Gtk2::Expander->new(format_field(N("Details:")))), - # gtknew('TextView', text => get_details($pkg, $upkg, $installed_version, $raw_medium))) ]; - push @$s, join("\n", format_field(N("Details:"))."\n".get_details($pkg, $upkg, $installed_version, $raw_medium)); - #$details_exp->set_use_markup(1); - push @$s, [ "\n\n" ]; - #push @$s, [ build_expander($pkg, N("Files:"), 'files', sub { files_format($pkg->{files}) }) ]; - push @$s, [ "\n\n" ]; - #push @$s, [ build_expander($pkg, N("Changelog:"), 'changelog', sub { $pkg->{changelog} }, $installed_version) ]; - - push @$s, [ "\n\n" ]; - if ($upkg->id) { # If not installed - # push @$s, get_new_deps($urpm, $upkg); - } - $s; -} - -sub format_pkg_info { - my ($pkgs, $key, $urpm, $descriptions) = @_; - my $pkg = $pkgs->{$key}; - my $upkg = $pkg->{pkg}; - my ($name, $version) = split_fullname($key); - my @files = ( - format_field(N("Files:\n")), - exists $pkg->{files} - ? '' . join("\n", map { "\x{200e}$_" } @{$pkg->{files}}) . '' #- to highlight information - : N("(Not available)"), - ); - my @chglo = (format_field(N("Changelog:\n")), ($pkg->{changelog} ? @{$pkg->{changelog}} : N("(Not available)"))); - my @source_info = ( - $MODE eq 'remove' || !@$max_info_in_descr - ? () - : ( - format_field(N("Medium: ")) . pkg2medium($upkg, $urpm)->{name}, - format_field(N("Currently installed version: ")) . find_installed_version($upkg), - ) - ); - my @max_info = @$max_info_in_descr && $changelog_first ? (@chglo, @files) : (@files, '', @chglo); - ugtk2::markup_to_TextView_format(join("\n", format_field(N("Name: ")) . $name, - format_field(N("Version: ")) . $version, - format_field(N("Architecture: ")) . $upkg->arch, - format_field(N("Size: ")) . N("%s KB", int($upkg->size/1024)), - if_( - $MODE eq 'update', - format_field(N("Importance: ")) . $descriptions->{$name}{importance} - ), - @source_info, - '', # extra empty line - format_field(N("Summary: ")) . $upkg->summary, - '', # extra empty line - if_( - $MODE eq 'update', - format_field(N("Reason for update: ")) . rpm_description($descriptions->{$name}{pre}), - ), - format_field(N("Description: ")), ($pkg->{description} || $descriptions->{$name}{description} || N("No description")), - @max_info, - )); -} - -sub warn_if_no_pkg { - my ($name) = @_; - my ($short_name) = split_fullname($name); - state $warned; - if (!$warned) { - $warned = 1; - interactive_msg(N("Warning"), - join("\n", - N("The package \"%s\" was found.", $name), - N("However this package is not in the package list."), - N("You may want to update your urpmi database."), - '', - N("Matching packages:"), - '', - join("\n", sort map { - #-PO: this is list fomatting: "- (medium: )" - #-PO: eg: "- rpmdragora (medium: "Main Release" - N("- %s (medium: %s)", $_, pkg2medium($pkgs->{$_}{pkg}, $urpm)->{name}); - } grep { /^$short_name/ } keys %$pkgs), - ), - scroll => 1, - ); - } - return 'XXX'; -} - -sub node_state { - my ($name) = @_; - #- checks $_[0] -> hack for partial tree displaying - return 'XXX' if !$name; - my $pkg = $pkgs->{$name}; - my $urpm_obj = $pkg->{pkg}; - return warn_if_no_pkg($name) if !$urpm_obj; - $pkg->{selected} ? - ($urpm_obj->flag_installed ? - ($urpm_obj->flag_upgrade ? 'to_install' : 'to_remove') - : 'to_install') - : ($urpm_obj->flag_installed ? - ($pkgs->{$name}{is_backport} ? 'backport' : - ($urpm_obj->flag_upgrade ? 'to_update' - : ($urpm_obj->flag_base ? 'base' : 'installed'))) - : 'uninstalled'); -} - -my ($common, $w, %wtree, %ptree, %pix, @table_item_list); - -sub set_node_state { - my ($tblItem, $state, $detail_list) = @_; - return if $state eq 'XXX' || !$state; - $detail_list->parent()->parent()->startMultipleChanges(); - $tblItem->addCell($state,"/usr/share/rpmdrake/icons/state_$state.png") if(ref $tblItem eq "yui::YCBTableItem"); - if(to_bool(member($state, qw(base installed to_install)))){ - # it should be parent()->setChecked(1) - $detail_list->checkItem($tblItem, 1); - # $tblItem->setSelected(1); - }else{ - $detail_list->checkItem($tblItem, 0); - # $tblItem->setSelected(0); - } - if(!to_bool($state ne 'base')){ - #$iter->cell(0)->setLabel('-'); - $tblItem->cell(0)->setLabel('-'); - } - $detail_list->parent()->parent()->doneMultipleChanges(); -} - -sub set_leaf_state { - my ($leaf, $state, $detail_list) = @_; - # %ptree is a hash using the pkg name as key and a monodimensional array (?) as value - # were it is stored the index of the item into the table - my $nodeIndex = $ptree{$leaf}[0]; - my $node = itemAt($detail_list,$nodeIndex); - set_node_state($node, $state, $detail_list); -} - -sub grep_unselected { - my @l = shift(); - my @result = grep { exists $pkgs->{$_} && !$pkgs->{$_}{selected} } @l ; - return @result; -} - -my %groups_tree = (); - -sub add_parent { - my ($tree, $root, $state) = @_; - $tree or return undef; - #$root or return undef; - my $parent = 0; - my @items = split('\|', $root); - my $i = 0; - for my $item (@items) { - chomp $item; - $item = trim($item); - my $treeItem; - if($i == 0){ - $parent = $item; - $treeItem = new yui::YTreeItem($item,get_icon_path($item,0),0); - if(!defined($groups_tree{$parent})) { - $groups_tree{$parent}{parent} = $treeItem; - $groups_tree{$parent}{children} = (); - $tree->addItem($groups_tree{$parent}{'parent'}); - } - }else{ - #if(any { $_ ne $item } @{$groups_tree{$parent}{'children'}}){ - # push @{$groups_tree{$parent}{'children'}}, $item; - #} - if(!defined($groups_tree{$parent}{'children'}{$item})){ - $treeItem = new yui::YTreeItem($item,get_icon_path($item,$parent),0); - $groups_tree{$parent}{'children'}{$item} = $treeItem; - $groups_tree{$parent}{'parent'}->addChild($treeItem); - } - } - $i++; - } - $tree->rebuildTree(); -} - -sub add_node { - my ($leaf, $root, $o_options) = @_; - my $state = node_state($leaf) or return; - if ($leaf) { - my $iter; - if (is_a_package($leaf)) { - my ($name, $version, $release, $arch) = split_fullname($leaf); - #OLD $iter = $w->{detail_list_model}->append_set([ $pkg_columns{text} => $leaf, - # $pkg_columns{short_name} => format_name_n_summary($name, get_summary($leaf)), - # $pkg_columns{version} => $version, - # $pkg_columns{release} => $release, - # $pkg_columns{arch} => $arch, - # ]); - $name = "" if(!defined($name)); - $version = "" if(!defined($version)); - $release = "" if(!defined($release)); - $arch = "" if(!defined($arch)); - #my $newTableItem = new yui::YTableItem(format_name_n_summary($name, get_summary($leaf)), - my $newTableItem = new yui::YCBTableItem($name."\n".get_summary($leaf), - $version, - $release, - $arch); - $w->{detail_list}->addItem($newTableItem); - set_node_state($newTableItem, $state, $w->{detail_list}); - # $ptree{$leaf} = [ $newTableItem->label() ]; - $ptree{$leaf} = [ $newTableItem->index() ]; - $table_item_list[$newTableItem->index()] = $leaf; - $newTableItem->DISOWN(); - } else { - $iter = $w->{tree_model}->append_set(add_parent($w->{tree},$root, $state), [ $grp_columns{label} => $leaf ]); - #push @{$wtree{$leaf}}, $iter; - } - } else { - my $parent = add_parent($w->{tree}, $root, $state); - #- hackery for partial displaying of trees, used in rpmdragora: - #- if leaf is void, we may create the parent and one child (to have the [+] in front of the parent in the ctree) - #- though we use '' as the label of the child; then rpmdragora will connect on tree_expand, and whenever - #- the first child has '' as the label, it will remove the child and add all the "right" children - $o_options->{nochild} or $w->{tree_model}->append_set($parent, [ $grp_columns{label} => '' ]); # test $leaf? - } -} - -my ($prev_label); -sub update_size { - my ($common) = shift @_; - if ($w->{status}) { - my $new_label = $common->{get_status}(); - $prev_label="" if(!defined($prev_label)); - $prev_label ne $new_label and $w->{status}->setText($prev_label = $new_label); - } -} - -sub treeview_children { - my($tbl) = @_; - my $it; - my @l; - my $i=0; - # using iterators - for ($it = $tbl->itemsBegin(); $it != $tbl->itemsEnd(); ) { - my $item = $tbl->YItemIteratorToYItem($it); - push @l, $item; - $it = $tbl->nextItem($it); - $i++; - if ($i == $tbl->itemsCount()) { - last; - } - } - # using items - #for($i=0;$i<$tbl->itemsCount();$i++) { - # print " item label " . $tbl->item($i)->cell(0)->label() . "\n"; - # push @l, $tbl->item($i); - #} - return @l; -} - -sub children { - my ($w, @table_item_list) = @_; - # map { $w->{detail_list}->get($_, $pkg_columns{text}) } treeview_children($w->{detail_list}); - # map { $table_item_list[$_->index()] } treeview_children($w->{detail_list}); - my @children = treeview_children($w->{detail_list}); - my @result; - for my $child(@children){ - push @result, $table_item_list[$child->index()]; - } - return @result; -} - -sub itemAt { - my ($table, $index) = @_; - return $table->item($index); - #return bless ($table->item($index),'yui::YTableItem'); - #foreach my $item(treeview_children($table)){ - # if($item->index() == $index){ - # print "\n== item label ".$item->label()."\n"; - # return bless ($item, 'yui::YTableItem'); - # } - #} -} - -sub toggle_all { - my ($common, $_val) = @_; - my $w = $common->{widgets}; - my @l = children($w, $common->{table_item_list}) or return; - - my @unsel = grep_unselected(@l); - my @p = @unsel ? - #- not all is selected, select all if no option to potentially override - (exists $common->{partialsel_unsel} && $common->{partialsel_unsel}->(\@unsel, \@l) ? difference2(\@l, \@unsel) : @unsel) - : @l; - # toggle_nodes($w->{detail_list}, $w->{detail_list_model}, \&set_leaf_state, node_state($p[0]), @p); - toggle_nodes($w->{detail_list}, $w->{detail_list}, \&set_leaf_state, node_state($p[0][0]), @{$p[0]}); - update_size($common); -} - -sub fast_toggle { - my ($item) = @_; - #gtkset_mousecursor_wait($w->{w}{rwindow}->window); - #my $_cleaner = before_leaving { gtkset_mousecursor_normal($w->{w}{rwindow}->window) }; - my $name = $common->{table_item_list}[$item->index()]; - my $urpm_obj = $pkgs->{$name}{pkg}; - if ($urpm_obj->flag_base) { - interactive_msg(N("Warning"), N("Removing package %s would break your system", $name)); - return ''; - } - if ($urpm_obj->flag_skip) { - interactive_msg(N("Warning"), N("The \"%s\" package is in urpmi skip list.\nDo you want to select it anyway?", $name), yesno => 1) or return ''; - $urpm_obj->set_flag_skip(0); - } - if ($Rpmdragora::pkg::need_restart && !$priority_up_alread_warned) { - $priority_up_alread_warned = 1; - interactive_msg(N("Warning"), '' . N("Rpmdragora or one of its priority dependencies needs to be updated first. Rpmdragora will then restart.") . '' . "\n\n"); - } - # toggle_nodes($w->{tree}->window, $w->{detail_list_model}, \&set_leaf_state, $w->{detail_list_model}->get($iter, $pkg_columns{state}), - my $state; -#pasmatt checked should be to install no? - if($item->checked()){ - $state = "to_install"; - }else{ - $state = "to_remove"; - } - toggle_nodes($w->{tree}, $w->{detail_list}, \&set_leaf_state, $state, $name); - update_size($common); -}; - -# ask_browse_tree_given_widgets_for_rpmdragora will run gtk+ loop. its main parameter "common" is a hash containing: -# - a "widgets" subhash which holds: -# o a "w" reference on a ugtk2 object -# o "tree" & "info" references a TreeView -# o "info" is a TextView -# o "tree_model" is the associated model of "tree" -# o "status" references a Label -# - some methods: get_info, node_state, build_tree, partialsel_unsel, grep_unselected, rebuild_tree, toggle_nodes, get_status -# - "tree_submode": the default mode (by group, ...), ... -# - "state": a hash of misc flags: => { flat => '0' }, -# o "flat": is the tree flat or not -# - "tree_mode": mode of the tree ("gui_pkgs", "by_group", ...) (mainly used by rpmdragora) - -sub ask_browse_tree_given_widgets_for_rpmdragora { - ($common) = @_; - $w = $common->{widgets}; - - $common->{table_item_list} = \@table_item_list; - - $w->{detail_list} ||= $w->{tree}; - #$w->{detail_list_model} ||= $w->{tree_model}; - - $common->{add_parent} = \&add_parent; - my $clear_all_caches = sub { - %ptree = %wtree = (); - @table_item_list = (); - }; - $common->{clear_all_caches} = $clear_all_caches; - $common->{delete_all} = sub { - $clear_all_caches->(); - $w->{detail_list}->deleteAllItems() if($w->{detail_list}->hasItems()); - $w->{tree}->deleteAllItems() if($w->{tree}->hasItems()); - %groups_tree = (); - }; - $common->{rebuild_tree} = sub { - $common->{delete_all}->(); - $common->{build_tree}($common->{state}{flat}, $common->{tree_mode}); - update_size($common); - }; - $common->{delete_category} = sub { - my ($cat) = @_; - exists $wtree{$cat} or return; - %ptree = (); - - if (exists $wtree{$cat}) { - my $_iter_str = $w->{tree_model}->get_path_str($wtree{$cat}); - $w->{tree_model}->remove($wtree{$cat}); - delete $wtree{$cat}; - } - update_size($common); - }; - $common->{add_nodes} = sub { - my (@nodes) = @_; - $w->{detail_list}->deleteAllItems(); - #$w->{detail_list}->scroll_to_point(0, 0); - foreach(@nodes){ - add_node($_->[0], $_->[1], $_->[2]); - } - update_size($common); - }; - - $common->{display_info} = sub { - gtktext_insert($w->{info}, get_info($_[0], $w->{tree}->window)); - $w->{info}->scroll_to_iter($w->{info}->get_buffer->get_start_iter, 0, 0, 0, 0); - 0; - }; - - my $fast_toggle = sub { - my ($item) = @_; - #gtkset_mousecursor_wait($w->{w}{rwindow}->window); - #my $_cleaner = before_leaving { gtkset_mousecursor_normal($w->{w}{rwindow}->window) }; - my $name = $common->{table_item_list}[$item->index()]; - my $urpm_obj = $pkgs->{$name}{pkg}; - - if ($urpm_obj->flag_base) { - interactive_msg(N("Warning"), - N("Removing package %s would break your system", $name)); - return ''; - } - - if ($urpm_obj->flag_skip) { - interactive_msg(N("Warning"), N("The \"%s\" package is in urpmi skip list.\nDo you want to select it anyway?", $name), yesno => 1) or return ''; - $urpm_obj->set_flag_skip(0); - } - - if ($Rpmdragora::pkg::need_restart && !$priority_up_alread_warned) { - $priority_up_alread_warned = 1; - interactive_msg(N("Warning"), '' . N("Rpmdragora or one of its priority dependencies needs to be updated first. Rpmdragora will then restart.") . '' . "\n\n"); - } - - # toggle_nodes($w->{tree}->window, $w->{detail_list_model}, \&set_leaf_state, $w->{detail_list_model}->get($iter, $pkg_columns{state}), - toggle_nodes($w->{tree}->window, $w->{detail_list_model}, \&set_leaf_state, $item->selected, $common->{table_item_list}[$item->index()]); - update_size($common); - }; - #$w->{detail_list}->get_selection->signal_connect(changed => sub { - #my ($model, $iter) = $_[0]->get_selected; - #$model && $iter or return; - # $common->{display_info}($model->get($iter, $pkg_columns{text})); - #}); - # WARNING: รจ interessante! - #($w->{detail_list}->get_column(0)->get_cell_renderers)[0]->signal_connect(toggled => sub { - # my ($_cell, $path) = @_; #text_ - # my $iter = $w->{detail_list_model}->get_iter_from_string($path); - # $fast_toggle->($iter) if $iter; - # 1; - #}); - $common->{rebuild_tree}->(); - update_size($common); - $common->{initial_selection} and toggle_nodes($w->{tree}->window, $w->{detail_list}, \&set_leaf_state, undef, @{$common->{initial_selection}}); - my $_b = before_leaving { $clear_all_caches->() }; - $common->{init_callback}->() if $common->{init_callback}; - #OLD $w->{w}->main; - $w->{w}; -} - -our $find_entry; - -sub reset_search() { - return if !$common; - $common->{delete_category}->($_) foreach $results_ok, $results_none; - # clear package list: - $common->{add_nodes}->(); -} - -sub is_a_package { - my ($pkg) = @_; - return exists $pkgs->{$pkg}; -} - -sub switch_pkg_list_mode { - my ($mode) = @_; - return if !$mode; - return if !$filter_methods{$mode}; - $force_displaying_group = 1; - $filter_methods{$mode}->(); -} - -sub is_updatable { - my $p = $pkgs->{$_[0]}; - $p->{pkg} && !$p->{selected} && $p->{pkg}->flag_installed && $p->{pkg}->flag_upgrade; -} - -sub pkgs_provider { - my ($mode, %options) = @_; - return if !$mode; - my $h = &get_pkgs(%options); - ($urpm, $descriptions) = @$h{qw(urpm update_descr)}; - $pkgs = $h->{all_pkgs}; - %filters = ( - non_installed => $h->{installable}, - installed => $h->{installed}, - all => [ keys %$pkgs ], - ); - my %tmp_filter_methods = ( - all => sub { - [ difference2([ keys %$pkgs ], $h->{inactive_backports}) ]; - }, - all_updates => sub { - # potential "updates" from media not tagged as updates: - if (!$options{pure_updates} && !$Rpmdragora::pkg::need_restart) { - [ @{$h->{updates}}, - difference2([ grep { is_updatable($_) } @{$h->{installable}} ], $h->{backports}) ]; - } else { - [ difference2($h->{updates}, $h->{inactive_backports}) ]; - } - }, - backports => sub { $h->{backports} }, - meta_pkgs => sub { - [ difference2($h->{meta_pkgs}, $h->{inactive_backports}) ]; - }, - gui_pkgs => sub { - [ difference2($h->{gui_pkgs}, $h->{inactive_backports}) ]; - }, - ); - foreach my $importance (qw(bugfix security normal)) { - $tmp_filter_methods{$importance} = sub { - my @media = keys %$descriptions; - [ grep { - my ($name) = split_fullname($_); - my $medium = find { $descriptions->{$_}{$name} } @media; - $medium && $descriptions->{$medium}{$name}{importance} eq $importance } @{$h->{updates}} ]; - }; - } - - undef %filter_methods; - foreach my $type (keys %tmp_filter_methods) { - $filter_methods{$type} = sub { - $force_rebuild = 1; # force rebuilding tree since we changed filter (FIXME: switch to SortModel) - @filtered_pkgs = intersection($filters{$filter->[0]}, $tmp_filter_methods{$type}->()); - }; - } - - switch_pkg_list_mode($mode); -} - -sub closure_removal { - local $urpm->{state} = {}; - urpm::select::find_packages_to_remove($urpm, $urpm->{state}, \@_); -} - -sub is_locale_available { - my ($name) = @_; - any { $urpm->{depslist}[$_]->flag_selected } keys %{$urpm->{provides}{$name} || {}} and return 1; - my $found; - open_rpm_db()->traverse_tag_find('name', $name, sub { $found = 1 }); - return $found; -} - -sub callback_choices { - my (undef, undef, undef, $choices) = @_; - return $choices->[0] if $::rpmdragora_options{auto}; - foreach my $pkg (@$choices) { - foreach ($pkg->requires_nosense) { - /locales-/ or next; - is_locale_available($_) and return $pkg; - } - } - my $callback = sub { interactive_msg(N("More information on package..."), get_info($_[0]), scroll => 1) }; - $choices = [ sort { $a->name cmp $b->name } @$choices ]; - my @choices = interactive_list_(N("Please choose"), (scalar(@$choices) == 1 ? - N("The following package is needed:") : N("One of the following packages is needed:")), - [ map { urpm_name($_) } @$choices ], $callback, nocancel => 1); - defined $choices[0] ? $choices->[$choices[0]] : undef; -} - -sub deps_msg { - return 1 if $dont_show_selections->[0]; - my ($title, $msg, $nodes, $nodes_with_deps) = @_; - my @deps = sort { $a cmp $b } difference2($nodes_with_deps, $nodes); - @deps > 0 or return 1; - deps_msg_again: - my $results = interactive_msg( - $title, $msg . - format_list(map { scalar(urpm::select::translate_why_removed_one($urpm, $urpm->{state}, $_)) } @deps) - . "\n\n" . format_size($urpm->selected_size($urpm->{state})), - yesno => [ N("Cancel"), N("More info"), N("Ok") ], - scroll => 1, - ); - if ($results eq - #-PO: Keep it short, this is gonna be on a button - N("More info")) { - interactive_packtable( - N("Information on packages"), - $::main_window, - undef, - [ map { my $pkg = $_; - [ gtknew('HBox', children_tight => [ gtkset_selectable(gtknew('Label', text => $pkg), 1) ]), - gtknew('Button', text => N("More information on package..."), - clicked => sub { - interactive_msg(N("More information on package..."), get_info($pkg), scroll => 1); - }) ] } @deps ], - [ gtknew('Button', text => N("Ok"), - clicked => sub { Gtk2->main_quit }) ] - ); - goto deps_msg_again; - } else { - return $results eq N("Ok"); - } -} - -sub toggle_nodes { - my ($widget, $detail_list, $set_state, $old_state, @nodes) = @_; - @nodes = grep { exists $pkgs->{$_} } @nodes - or return; - #- avoid selecting too many packages at once - return if !$dont_show_selections->[0] && @nodes > 2000; - my $new_state = !$pkgs->{$nodes[0]}{selected}; - - my @nodes_with_deps; - - my $bar_id = statusbar_msg(N("Checking dependencies of package..."), 0); - - my $warn_about_additional_packages_to_remove = sub { - my ($msg) = @_; - statusbar_msg_remove($bar_id); - deps_msg(N("Some additional packages need to be removed"), - formatAlaTeX($msg) . "\n\n", - \@nodes, \@nodes_with_deps) or @nodes_with_deps = (); - }; - - if (member($old_state, qw(to_remove installed))) { # remove pacckages - if ($new_state) { - my @remove; - slow_func($widget, sub { @remove = closure_removal(@nodes) }); - @nodes_with_deps = grep { !$pkgs->{$_}{selected} && !/^basesystem/ } @remove; - $warn_about_additional_packages_to_remove->( - N("Because of their dependencies, the following package(s) also need to be removed:")); - my @impossible_to_remove; - foreach (grep { exists $pkgs->{$_}{base} } @remove) { - ${$pkgs->{$_}{base}} == 1 ? push @impossible_to_remove, $_ : ${$pkgs->{$_}{base}}--; - } - @impossible_to_remove and interactive_msg(N("Some packages cannot be removed"), - N("Removing these packages would break your system, sorry:\n\n") . - format_list(@impossible_to_remove)); - @nodes_with_deps = difference2(\@nodes_with_deps, \@impossible_to_remove); - } else { - @nodes_with_deps = grep { intersection(\@nodes, [ closure_removal($_) ]) } - grep { $pkgs->{$_}{selected} && !member($_, @nodes) } keys %$pkgs; - push @nodes_with_deps, @nodes; - $warn_about_additional_packages_to_remove->( - N("Because of their dependencies, the following package(s) must be unselected now:\n\n")); - $pkgs->{$_}{base} && ${$pkgs->{$_}{base}}++ foreach @nodes_with_deps; - } - } else { - if ($new_state) { - if (@nodes > 1) { - #- unselect i18n packages of which locales is not already present (happens when user clicks on KDE group) - my @bad_i18n_pkgs; - foreach my $sel (@nodes) { - foreach ($pkgs->{$sel}{pkg}->requires_nosense) { - /locales-([^-]+)/ or next; - $sel =~ /-$1[-_]/ && !is_locale_available($_) and push @bad_i18n_pkgs, $sel; - } - } - @nodes = difference2(\@nodes, \@bad_i18n_pkgs); - } - my @requested; - @requested = $urpm->resolve_requested( - open_rpm_db(), $urpm->{state}, - { map { $pkgs->{$_}{pkg}->id => 1 } @nodes }, - callback_choices => \&callback_choices, - ); - @nodes_with_deps = map { urpm_name($_) } @requested; - statusbar_msg_remove($bar_id); - if (!deps_msg(N("Additional packages needed"), - formatAlaTeX(N("To satisfy dependencies, the following package(s) also need to be installed:\n\n")) . "\n\n", - \@nodes, \@nodes_with_deps)) { - @nodes_with_deps = (); - $urpm->disable_selected(open_rpm_db(), $urpm->{state}, @requested); - goto packages_selection_ok; - } - - if (my $conflicting_msg = urpm::select::conflicting_packages_msg($urpm, $urpm->{state})) { - if (!interactive_msg(N("Conflicting Packages"), $conflicting_msg, yesno => 1, scroll => 1)) { - @nodes_with_deps = (); - $urpm->disable_selected(open_rpm_db(), $urpm->{state}, @requested); - goto packages_selection_ok; - } - } - - if (my @cant = sort(difference2(\@nodes, \@nodes_with_deps))) { - my @ask_unselect = urpm::select::unselected_packages($urpm->{state}); - my @reasons = map { - my $cant = $_; - my $unsel = find { $_ eq $cant } @ask_unselect; - $unsel - ? join("\n", urpm::select::translate_why_unselected($urpm, $urpm->{state}, $unsel)) - : ($pkgs->{$_}{pkg}->flag_skip ? N("%s (belongs to the skip list)", $cant) : $cant); - } @cant; - my $count = @reasons; - interactive_msg( - ($count == 1 ? N("One package cannot be installed") : N("Some packages cannot be installed")), - ($count == 1 ? - N("Sorry, the following package cannot be selected:\n\n%s", format_list(@reasons)) - : N("Sorry, the following packages cannot be selected:\n\n%s", format_list(@reasons))), - scroll => 1, - ); - foreach (@cant) { - next unless $pkgs->{$_}{pkg}; - $pkgs->{$_}{pkg}->set_flag_requested(0); - $pkgs->{$_}{pkg}->set_flag_required(0); - } - } - packages_selection_ok: - } else { - my @unrequested; - @unrequested = $urpm->disable_selected(open_rpm_db(), $urpm->{state}, - map { $pkgs->{$_}{pkg} } @nodes); - @nodes_with_deps = map { urpm_name($_) } @unrequested; - statusbar_msg_remove($bar_id); - if (!deps_msg(N("Some packages need to be removed"), - N("Because of their dependencies, the following package(s) must be unselected now:\n\n"), - \@nodes, \@nodes_with_deps)) { - @nodes_with_deps = (); - $urpm->resolve_requested(open_rpm_db(), $urpm->{state}, { map { $_->id => 1 } @unrequested }); - goto packages_unselection_ok; - } - packages_unselection_ok: - } - } - - foreach (@nodes_with_deps) { - #- some deps may exist on some packages which aren't listed because - #- not upgradable (older than what currently installed) - exists $pkgs->{$_} or next; - if (!$pkgs->{$_}{pkg}) { #- can't be removed # FIXME; what about next packages in the loop? - undef $pkgs->{$_}{selected}; - log::explanations("can't be removed: $_"); - } else { - $pkgs->{$_}{selected} = $new_state; - } - # invoke set_leaf_state($pkgname, node_state, ) - # node_state = {to_install, to_remove,...} - $set_state->($_, node_state($_), $detail_list); - if (my $pkg = $pkgs->{$_}{pkg}) { - # FIXME: shouldn't we threat all of them as POSITIVE (as selected size) - $size_selected += $pkg->size * ($pkg->flag_installed && !$pkg->flag_upgrade ? ($new_state ? -1 : 1) : ($new_state ? 1 : -1)); - } - } -} - -sub is_there_selected_packages() { - int(grep { $pkgs->{$_}{selected} } keys %$pkgs); -} - -sub real_quit() { - if (is_there_selected_packages()) { - interactive_msg(N("Some packages are selected."), N("Some packages are selected.") . "\n" . N("Do you really want to quit?"), yesno => 1) or return; - } - Gtk2->main_quit; -} - -sub do_action__real { - my ($options, $callback_action, $o_info) = @_; - require urpm::sys; - if (!urpm::sys::check_fs_writable()) { - $urpm->{fatal}(1, N("Error: %s appears to be mounted read-only.", $urpm::sys::mountpoint)); - return 1; - } - if (!$Rpmdragora::pkg::need_restart && !is_there_selected_packages()) { - interactive_msg(N("You need to select some packages first."), N("You need to select some packages first.")); - return 1; - } - my $size_added = sum(map { if_($_->flag_selected && !$_->flag_installed, $_->size) } @{$urpm->{depslist}}); - if ($MODE eq 'install' && $size_free - $size_added/1024 < 50*1024) { - interactive_msg(N("Too many packages are selected"), - N("Warning: it seems that you are attempting to add so many -packages that your filesystem may run out of free diskspace, -during or after package installation ; this is particularly -dangerous and should be considered with care. - -Do you really want to install all the selected packages?"), yesno => 1) - or return 1; - } - my $res = $callback_action->($urpm, $pkgs); - if (!$res) { - $force_rebuild = 1; - pkgs_provider($options->{tree_mode}, if_($Rpmdragora::pkg::probe_only_for_updates, pure_updates => 1), skip_updating_mu => 1); - reset_search(); - $size_selected = 0; - (undef, $size_free) = MDK::Common::System::df('/usr'); - $options->{rebuild_tree}->() if $options->{rebuild_tree}; - gtktext_insert($o_info, '') if $o_info; - } - $res; -} - -sub do_action { - my ($options, $callback_action, $o_info) = @_; - my $res = eval { do_action__real($options, $callback_action, $o_info) }; - my $err = $@; - # FIXME: offer to report the problem into bugzilla: - if ($err && $err !~ /cancel_perform/) { - interactive_msg(N("Fatal error"), - N("A fatal error occurred: %s.", $err)); - } - $res; -} - -sub translate_group { - join('/', map { translate($_) } split m|/|, $_[0]); -} - -sub ctreefy { - join('|', map { translate($_) } split m|/|, $_[0]); -} - -sub _build_tree { - my ($tree, $elems, @elems) = @_; - #- we populate all the groups tree at first - %$elems = (); - # better loop on packages, create groups tree and push packages in the proper place: - foreach my $pkg (@elems) { - my $grp = $pkg->[1]; - # no state for groups (they're not packages and thus have no state) - add_parent($tree, $grp, undef); - $elems->{$grp} ||= []; - push @{$elems->{$grp}}, $pkg; - } -} - - -sub build_tree { - my ($tree, $tree_model, $elems, $options, $force_rebuild, $flat, $mode) = @_; - state $old_mode; - $mode = $options->{rmodes}{$mode} || $mode; - $old_mode = '' if(!defined($old_mode)); - return if $old_mode eq $mode && !$force_rebuild; - $old_mode = $mode; - undef $force_rebuild; - my @elems; - my $wait; $wait = statusbar_msg(N("Please wait, listing packages...")) if $MODE ne 'update'; - { - my @keys = @filtered_pkgs; - if (member($mode, qw(all_updates security bugfix normal))) { - @keys = grep { - my ($name) = split_fullname($_); - member($descriptions->{$name}{importance}, @$mandrakeupdate_wanted_categories) - || ! $descriptions->{$name}{importance}; - } @keys; - if (@keys == 0) { - add_node('', N("(none)"), { nochild => 1 }); - state $explanation_only_once; - $explanation_only_once or interactive_msg(N("No update"), - N("The list of updates is empty. This means that either there is -no available update for the packages installed on your computer, -or you already installed all of them.")); - $explanation_only_once = 1; - } - } - # FIXME: better do this on first group access for faster startup... - @elems = map { [ $_, !$flat && ctreefy($pkgs->{$_}{pkg}->group) ] } sort_packages(@keys); - } - my %sortmethods = ( - by_size => sub { sort { $pkgs->{$b->[0]}{pkg}->size <=> $pkgs->{$a->[0]}{pkg}->size } @_ }, - by_selection => sub { sort { $pkgs->{$b->[0]}{selected} <=> $pkgs->{$a->[0]}{selected} - || uc($a->[0]) cmp uc($b->[0]) } @_ }, - by_leaves => sub { - # inlining part of MDK::Common::Data::difference2(): - my %l; @l{map { $_->[0] } @_} = (); - my @pkgs_times = ('rpm', '-q', '--qf', '%{name}-%{version}-%{release}.%{arch} %{installtime}\n', - map { chomp_($_) } run_program::get_stdout('urpmi_rpm-find-leaves')); - sort { $b->[1] <=> $a->[1] } grep { exists $l{$_->[0]} } map { chomp; [ split ] } run_rpm(@pkgs_times); - }, - flat => sub { no locale; sort { uc($a->[0]) cmp uc($b->[0]) } @_ }, - by_medium => sub { sort { $a->[2] <=> $b->[2] || uc($a->[0]) cmp uc($b->[0]) } @_ }, - ); - if ($flat) { - add_node($tree->currentItem()->label(), '') foreach $sortmethods{$::mode->[0] || 'flat'}->(@elems); - } else { - if (0 && $MODE eq 'update') { - foreach ($sortmethods{flat}->(@elems)){ - add_node($tree->currentItem()->label(), $_->[0], N("All")) - } - $tree->expand_row($tree_model->get_path($tree_model->get_iter_first), 0); - } elsif ($::mode->[0] eq 'by_source') { - _build_tree($tree, $elems, $sortmethods{by_medium}->(map { - my $m = pkg2medium($pkgs->{$_->[0]}{pkg}, $urpm); [ $_->[0], $m->{name}, $m->{priority} ]; - } @elems)); - } elsif ($::mode->[0] eq 'by_presence') { - _build_tree($tree, $elems, map { - my $pkg = $pkgs->{$_->[0]}{pkg}; - [ $_->[0], $pkg->flag_installed ? - (!$pkg->flag_skip && $pkg->flag_upgrade ? N("Upgradable") : N("Installed")) - : N("Addable") ]; - } $sortmethods{flat}->(@elems)); - } else { - _build_tree($tree, $elems, @elems); - # INFO: $elems contains references to the packages of the group, see _build_tree - } - } - statusbar_msg_remove($wait) if defined $wait; -} - -sub get_info { - my ($key, $widget) = @_; - #- the package information hasn't been loaded. Instead of rescanning the media, just give up. - exists $pkgs->{$key} or return [ [ N("Description not available for this package\n") ] ]; - #- get the description if needed: - exists $pkgs->{$key}{description} or slow_func($widget, sub { extract_header($pkgs->{$key}, $urpm, 'info', find_installed_version($pkgs->{$key}{pkg})) }); - format_pkg_simplifiedinfo($pkgs, $key, $urpm, $descriptions); -} - -sub sort_callback { - my ($store, $treeiter1, $treeiter2) = @_; - URPM::rpmvercmp(map { $store->get_value($_, $pkg_columns{version}) } $treeiter1, $treeiter2); -} - -sub run_help_callback { - my (undef, $url) = @_; - my ($user) = grep { $_->[2] eq $ENV{USERHELPER_UID} } list_passwd(); - local $ENV{HOME} = $user->[7] if $user && $ENV{USERHELPER_UID}; - run_program::raw({ detach => 1, as_user => 1 }, 'www-browser', $url); -} - -sub groups_tree { - return %groups_tree; -} - -sub group_has_parent { - my ($group) = shift; - return 0 if(!defined($group)); - return defined($groups_tree{$group}{parent}); -} - -sub group_parent { - my ($group) = shift; - # if group is a parent itself return it - # who use group_parent have to take care of the comparison - # between a group and its parent - # e.g. group System has groups_tree{'System'}{parent}->label() = 'System' - return $groups_tree{$group}{parent} if(group_has_parent($group)); - for my $sup (keys %groups_tree){ - for my $item(keys %{$groups_tree{$sup}{children}}){ - if(defined($group) && ($item eq $group)){ - return $groups_tree{$sup}{parent}; - } - } - } - return undef; -} - -1; diff --git a/AdminPanel/Rpmdragora/gurpm.pm b/AdminPanel/Rpmdragora/gurpm.pm deleted file mode 100644 index 983f0554..00000000 --- a/AdminPanel/Rpmdragora/gurpm.pm +++ /dev/null @@ -1,138 +0,0 @@ -# vim: set et ts=4 sw=4: -package AdminPanel::Rpmdragora::gurpm; -#***************************************************************************** -# -# Copyright (c) 2002 Guillaume Cottenceau -# Copyright (c) 2002-2007 Thierry Vignaud -# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA -# Copyright (c) 2005-2007 Mandriva SA -# Copyright (c) 2013 Matteo Pasotti -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2, as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -#***************************************************************************** -# -# $Id: gurpm.pm 255450 2009-04-03 16:00:16Z tv $ - -use strict; -use lib qw(/usr/lib/libDrakX); -use yui; -use Time::HiRes; -use feature 'state'; - -sub new { - my ($class, $title, $initializing, %options) = @_; - my $self = { - my $label = 0, - my $factory = 0, - my $mainw = 0, - my $vbox = 0, - my $progressbar = 0, - my $cancel = 0 - }; - bless $self, 'AdminPanel::Rpmdragora::gurpm'; - #my $mainw = bless(ugtk2->new($title, %options, default_width => 600, width => 600), $self); - $self->{factory} = yui::YUI::widgetFactory; - $self->{mainw} = $self->{factory}->createPopupDialog(); - #$::main_window = $self->{mainw}; - $self->{vbox} = $self->{factory}->createVBox($self->{mainw}); - #OLD $mainw->{label} = gtknew('Label', text => $initializing, alignment => [ 0.5, 0 ]); - $self->{label} = $self->{factory}->createLabel($self->{vbox}, $initializing); - # size label's heigh to 2 lines in order to prevent dummy vertical resizing: - #my $context = $mainw->{label}->get_layout->get_context; - #my $metrics = $context->get_metrics($mainw->{label}->style->font_desc, $context->get_language); - #$mainw->{label}->set_size_request(-1, 2 * Gtk2::Pango->PANGO_PIXELS($metrics->get_ascent + $metrics->get_descent)); - - #OLD $mainw->{progressbar} = gtknew('ProgressBar'); - $self->{progressbar} = $self->{factory}->createProgressBar($self->{vbox}, ""); - #gtkadd($mainw->{window}, $mainw->{vbox} = gtknew('VBox', spacing => 5, border_width => 6, children_tight => [ - # $mainw->{label}, - # $mainw->{progressbar} - #])); - #$mainw->{rwindow}->set_position('center-on-parent'); - #$mainw->{real_window}->show_all; - #select(undef, undef, undef, 0.1); #- hackish :-( - #$mainw->SUPER::sync; - $self->{mainw}->pollEvent(); - $self->flush(); - $self; -} - -sub flush { - my ($self) = @_; - $self->{mainw}->recalcLayout(); - $self->{mainw}->doneMultipleChanges(); -} - -sub label { - my ($self, $label) = @_; - $self->{label} = $self->{factory}->createLabel($self->{vbox},$label); - #select(undef, undef, undef, 0.1); #- hackish :-( - $self->flush(); -} - -sub progress { - my ($self, $value) = @_; - state $time; - $time = 0 if(!defined($time)); - $value = 0 if $value < 0; - $value = 100 if 1 < $value; - $self->{progressbar}->setValue($value); - return if Time::HiRes::clock_gettime() - $time < 0.333; - $time = Time::HiRes::clock_gettime(); - $self->flush(); -} - -sub DESTROY { - my ($self) = @_; - #mygtk2::may_destroy($self); - $self and $self->{mainw}->destroy; - #$self = undef; - $self->{cancel} = undef; #- in case we'll do another one later -} - -sub validate_cancel { - my ($self, $cancel_msg, $cancel_cb) = @_; - if (!$self->{cancel}) { - $self->{cancel} = $self->{factory}->createIconButton($self->{vbox},"",$cancel_msg); - #gtkpack__( - #$self->{vbox}, - #$self->{hbox_cancel} = gtkpack__( - #gtknew('HButtonBox'), - #$self->{cancel} = gtknew('Button', text => $cancel_msg, clicked => \&$cancel_cb), - #), - #); - } - #$self->{cancel}->set_sensitive(1); - #$self->{cancel}->show; - $self->flush(); -} - -sub invalidate_cancel { - my ($self) = @_; - $self->{cancel} and $self->{cancel}->setEnabled(0); -} - -sub invalidate_cancel_forever { - my ($self) = @_; - #$self->{hbox_cancel} or return; - #$self->{hbox_cancel}->destroy; - # FIXME: temporary workaround that prevents - # Gtk2::Label::set_text() set_text_internal() -> queue_resize() -> - # size_allocate() call chain to mess up when ->shrink_topwindow() - # has been called (#32613): - #$self->shrink_topwindow; -} - -1; diff --git a/AdminPanel/Rpmdragora/icon.pm b/AdminPanel/Rpmdragora/icon.pm deleted file mode 100644 index 1dee4e5c..00000000 --- a/AdminPanel/Rpmdragora/icon.pm +++ /dev/null @@ -1,236 +0,0 @@ -# vim: set et ts=4 sw=4: -package AdminPanel::Rpmdragora::icon; -#***************************************************************************** -# -# Copyright (c) 2002 Guillaume Cottenceau -# Copyright (c) 2002-2007 Thierry Vignaud -# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA -# Copyright (c) 2005-2007 Mandriva SA -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2, as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -#***************************************************************************** -# -# $Id: icon.pm 237459 2008-02-26 14:20:47Z tv $ - -use strict; -our @ISA = qw(Exporter); -use lib qw(/usr/lib/libDrakX); -use POSIX; -use common; - -# TO WORKAROUND LOCALIZATION ISSUE -use AdminPanel::Rpmdragora::localization; - -our @EXPORT = qw(get_icon_path); -#- /usr/share/rpmlint/config (duplicates are normal, so that we are not too far away from .py) -my %group_icons = ( - N("All") => 'system_section', - N("Accessibility") => 'accessibility_section', - N("Archiving") => 'archiving_section', - join('|', N("Archiving"), N("Backup")) => 'backup_section', - join('|', N("Archiving"), N("Cd burning")) => 'cd_burning_section', - join('|', N("Archiving"), N("Compression")) => 'compression_section', - join('|', N("Archiving"), N("Other")) => 'other_archiving', - N("Communications") => 'communications_section', - join('|', N("Communications"), N("Bluetooth")) => 'communications_bluetooth_section', - join('|', N("Communications"), N("Dial-Up")) => 'communications_dialup_section', - join('|', N("Communications"), N("Fax")) => 'communications_fax_section', - join('|', N("Communications"), N("Mobile")) => 'communications_mobile_section', - join('|', N("Communications"), N("Radio")) => 'communications_radio_section', - join('|', N("Communications"), N("Serial")) => 'communications_serial_section', - join('|', N("Communications"), N("Telephony")) => 'communications_phone_section', - N("Databases") => 'databases_section', - N("Development") => 'development_section', - join('|', N("Development"), N("Basic")) => '', - join('|', N("Development"), N("C")) => '', - join('|', N("Development"), N("C++")) => '', - join('|', N("Development"), N("C#")) => '', - join('|', N("Development"), N("Databases")) => 'databases_section', - join('|', N("Development"), N("Debug")) => '', - join('|', N("Development"), N("Erlang")) => '', - join('|', N("Development"), N("GNOME and GTK+")) => 'gnome_section', - join('|', N("Development"), N("Java")) => '', - join('|', N("Development"), N("KDE and Qt")) => 'kde_section', - join('|', N("Development"), N("Kernel")) => '', - join('|', N("Development"), N("OCaml")) => '', - join('|', N("Development"), N("Other")) => '', - join('|', N("Development"), N("Perl")) => '', - join('|', N("Development"), N("PHP")) => '', - join('|', N("Development"), N("Python")) => '', - join('|', N("Development"), N("Tools")) => 'development_tools_section', - join('|', N("Development"), N("X11")) => '', - N("Documentation") => 'documentation_section', - N("Editors") => 'editors_section', - N("Education") => 'education_section', - N("Emulators") => 'emulators_section', - N("File tools") => 'file_tools_section', - N("Games") => 'amusement_section', - join('|', N("Games"), N("Adventure")) => 'adventure_section', - join('|', N("Games"), N("Arcade")) => 'arcade_section', - join('|', N("Games"), N("Boards")) => 'boards_section', - join('|', N("Games"), N("Cards")) => 'cards_section', - join('|', N("Games"), N("Other")) => 'other_amusement', - join('|', N("Games"), N("Puzzles")) => 'puzzle_section', - join('|', N("Games"), N("Shooter")) => 'shooter_section', - join('|', N("Games"), N("Simulation")) => 'simulation_section', - join('|', N("Games"), N("Sports")) => 'sport_section', - join('|', N("Games"), N("Strategy")) => 'strategy_section', - N("Geography") => 'geography_section', - N("Graphical desktop") => 'graphical_desktop_section', - join('|', N("Graphical desktop"), - #-PO: This is a package/product name. Only translate it if needed: - N("Enlightenment")) => 'enlightment_section', - join('|', N("Graphical desktop"), - #-PO: This is a package/product name. Only translate it if needed: - N("GNOME")) => 'gnome_section', - join('|', N("Graphical desktop"), - #-PO: This is a package/product name. Only translate it if needed: - N("Icewm")) => 'icewm_section', - join('|', N("Graphical desktop"), - #-PO: This is a package/product name. Only translate it if needed: - N("KDE")) => 'kde_section', - join('|', N("Graphical desktop"), N("Other")) => 'more_applications_other_section', - join('|', N("Graphical desktop"), - #-PO: This is a package/product name. Only translate it if needed: - N("WindowMaker")) => 'windowmaker_section', - join('|', N("Graphical desktop"), - #-PO: This is a package/product name. Only translate it if needed: - N("Xfce")) => 'xfce_section', - N("Graphics") => 'graphics_section', - join('|', N("Graphics"), N("3D")) => 'graphics_3d_section', - join('|', N("Graphics"), N("Editors and Converters")) => 'graphics_editors_section', - join('|', N("Graphics"), N("Utilities")) => 'graphics_utilities_section', - join('|', N("Graphics"), N("Photography")) => 'graphics_photography_section', - join('|', N("Graphics"), N("Scanning")) => 'graphics_scanning_section', - join('|', N("Graphics"), N("Viewers")) => 'graphics_viewers_section', - N("Monitoring") => 'monitoring_section', - N("Networking") => 'networking_section', - join('|', N("Networking"), N("File transfer")) => 'file_transfer_section', - join('|', N("Networking"), N("IRC")) => 'irc_section', - join('|', N("Networking"), N("Instant messaging")) => 'instant_messaging_section', - join('|', N("Networking"), N("Mail")) => 'mail_section', - join('|', N("Networking"), N("News")) => 'news_section', - join('|', N("Networking"), N("Other")) => 'other_networking', - join('|', N("Networking"), N("Remote access")) => 'remote_access_section', - join('|', N("Networking"), N("WWW")) => 'networking_www_section', - N("Office") => 'office_section', - join('|', N("Office"), N("Dictionary")) => 'office_dictionary_section', - join('|', N("Office"), N("Finance")) => 'finances_section', - join('|', N("Office"), N("Management")) => 'timemanagement_section', - join('|', N("Office"), N("Organizer")) => 'timemanagement_section', - join('|', N("Office"), N("Utilities")) => 'office_accessories_section', - join('|', N("Office"), N("Spreadsheet")) => 'spreadsheet_section', - join('|', N("Office"), N("Suite")) => 'office_suite', - join('|', N("Office"), N("Word processor")) => 'wordprocessor_section', - N("Publishing") => 'publishing_section', - N("Sciences") => 'sciences_section', - join('|', N("Sciences"), N("Astronomy")) => 'astronomy_section', - join('|', N("Sciences"), N("Biology")) => 'biology_section', - join('|', N("Sciences"), N("Chemistry")) => 'chemistry_section', - join('|', N("Sciences"), N("Computer science")) => 'computer_science_section', - join('|', N("Sciences"), N("Geosciences")) => 'geosciences_section', - join('|', N("Sciences"), N("Mathematics")) => 'mathematics_section', - join('|', N("Sciences"), N("Other")) => 'other_sciences', - join('|', N("Sciences"), N("Physics")) => 'physics_section', - N("Security") => 'security_section', - N("Shells") => 'shells_section', - N("Sound") => 'sound_section', - join('|', N("Sound"), N("Editors and Converters")) => 'sound_editors_section', - join('|', N("Sound"), N("Midi")) => 'sound_midi_section', - join('|', N("Sound"), N("Mixers")) => 'sound_mixers_section', - join('|', N("Sound"), N("Players")) => 'sound_players_section', - join('|', N("Sound"), N("Utilities")) => 'sound_utilities_section', - N("System") => 'system_section', - join('|', N("System"), N("Base")) => 'system_section', - join('|', N("System"), N("Boot and Init")) => 'boot_init_section', - join('|', N("System"), N("Cluster")) => 'parallel_computing_section', - join('|', N("System"), N("Configuration")) => 'configuration_section', - join('|', N("System"), N("Fonts")) => 'chinese_section', - join('|', N("System"), N("Fonts"), N("True type")) => '', - join('|', N("System"), N("Fonts"), N("Type1")) => '', - join('|', N("System"), N("Fonts"), N("X11 bitmap")) => '', - join('|', N("System"), N("Internationalization")) => 'chinese_section', - join('|', N("System"), N("Kernel and hardware")) => 'hardware_configuration_section', - join('|', N("System"), N("Libraries")) => 'system_section', - join('|', N("System"), N("Networking")) => 'networking_configuration_section', - join('|', N("System"), N("Packaging")) => 'packaging_section', - join('|', N("System"), N("Printing")) => 'printing_section', - join('|', N("System"), N("Servers")) => 'servers_section', - join('|', N("System"), - #-PO: This is a package/product name. Only translate it if needed: - N("X11")) => 'x11_section', - N("Terminals") => 'terminals_section', - N("Text tools") => 'text_tools_section', - N("Toys") => 'toys_section', - N("Video") => 'video_section', - join('|', N("Video"), N("Editors and Converters")) => 'video_editors_section', - join('|', N("Video"), N("Players")) => 'video_players_section', - join('|', N("Video"), N("Television")) => 'video_television_section', - join('|', N("Video"), N("Utilities")) => 'video_utilities_section', - - # for Mageia Choice: - N("Workstation") => 'system_section', - join('|', N("Workstation"), N("Configuration")) => 'configuration_section', - join('|', N("Workstation"), N("Console Tools")) => 'interpreters_section', - join('|', N("Workstation"), N("Documentation")) => 'documentation_section', - join('|', N("Workstation"), N("Game station")) => 'amusement_section', - join('|', N("Workstation"), N("Internet station")) => 'networking_section', - join('|', N("Workstation"), N("Multimedia station")) => 'multimedia_section', - join('|', N("Workstation"), N("Network Computer (client)")) => 'other_networking', - join('|', N("Workstation"), N("Office Workstation")) => 'office_section', - join('|', N("Workstation"), N("Scientific Workstation")) => 'sciences_section', - N("Graphical Environment") => 'graphical_desktop_section', - - join('|', N("Graphical Environment"), N("GNOME Workstation")) => 'gnome_section', - join('|', N("Graphical Environment"), N("IceWm Desktop")) => 'icewm_section', - join('|', N("Graphical Environment"), N("KDE Workstation")) => 'kde_section', - join('|', N("Graphical Environment"), N("Other Graphical Desktops")) => 'more_applications_other_section', - N("Development") => 'development_section', - join('|', N("Development"), N("Development")) => 'development_section', - join('|', N("Development"), N("Documentation")) => 'documentation_section', - N("Server") => 'servers_section', - join('|', N("Server"), N("DNS/NIS")) => 'networking_section', - join('|', N("Server"), N("Database")) => 'databases_section', - join('|', N("Server"), N("Firewall/Router")) => 'networking_section', - join('|', N("Server"), N("Mail")) => 'mail_section', - join('|', N("Server"), N("Mail/Groupware/News")) => 'mail_section', - join('|', N("Server"), N("Network Computer server")) => 'networking_section', - join('|', N("Server"), N("Web/FTP")) => 'networking_www_section', - - ); - -sub get_icon_path { - my ($group, $parent) = @_; - my $path; - if(isdigit($parent) && $parent == 0){ - $path = '/usr/share/icons/'; - }else{ - $path = '/usr/share/icons/mini/'; - } - my $icon_path = ""; - if(defined($group_icons{$group})){ - $icon_path = join('', $path, $group_icons{$group}, '.png'); - }elsif(defined($group_icons{$parent."\|".$group})){ - $icon_path = join('', $path, $group_icons{$parent."\|".$group}, '.png'); - }else{ - $icon_path = join('', $path, 'applications_section', '.png'); - } - unless(-e $icon_path){ - $icon_path = join('', $path, 'applications_section', '.png'); - } - return $icon_path; -} - -1; diff --git a/AdminPanel/Rpmdragora/init.pm b/AdminPanel/Rpmdragora/init.pm deleted file mode 100644 index 34581bf2..00000000 --- a/AdminPanel/Rpmdragora/init.pm +++ /dev/null @@ -1,174 +0,0 @@ -# vim: set et ts=4 sw=4: -package AdminPanel::Rpmdragora::init; -#***************************************************************************** -# -# Copyright (c) 2002 Guillaume Cottenceau -# Copyright (c) 2002-2007 Thierry Vignaud -# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA -# Copyright (c) 2005-2007 Mandriva SA -# Copyright (c) 2013 Matteo Pasotti -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2, as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -#***************************************************************************** -# -# $Id: init.pm 263915 2009-12-03 17:41:04Z tv $ - -use strict; -use MDK::Common::Func 'any'; -use lib qw(/usr/lib/libDrakX); -use common; -use English; -BEGIN { $::no_global_argv_parsing = 1 } -require urpm::args; - -use Exporter; -our @ISA = qw(Exporter); -our @EXPORT = qw(init - warn_about_user_mode - $MODE - $changelog_first - $default_list_mode - %rpmdragora_options - @ARGV_copy - ); - -our @ARGV_copy = @ARGV; - -BEGIN { #- we want to run this code before the Gtk->init of the use-my_gtk - my $basename = sub { local $_ = shift; s|/*\s*$||; s|.*/||; $_ }; - any { /^--?h/ } @ARGV and do { - printf join("\n", N("Usage: %s [OPTION]...", $basename->($0)), -N(" --auto assume default answers to questions"), -N(" --changelog-first display changelog before filelist in the description window"), -N(" --media=medium1,.. limit to given media"), -N(" --merge-all-rpmnew propose to merge all .rpmnew/.rpmsave files found"), -N(" --mode=MODE set mode (install (default), remove, update)"), -N(" --justdb update the database, but do not modify the filesystem"), -N(" --no-confirmation don't ask first confirmation question in update mode"), -N(" --no-media-update don't update media at startup"), -N(" --no-verify-rpm don't verify package signatures"), -if_($0 !~ /MageiaUpdate/, N(" --parallel=alias,host be in parallel mode, use \"alias\" group, use \"host\" machine to show needed deps")), -N(" --rpm-root=path use another root for rpm installation"), -N(" --urpmi-root use another root for urpmi db & rpm installation"), -N(" --run-as-root force to run as root"), -N(" --search=pkg run search for \"pkg\""), -N(" --test only verify if the installation can be achieved correctly"), -chomp_(N(" --version print this tool's version number -")), -"" -); - exit 0; - }; -} - -BEGIN { #- for mcc - if ("@ARGV" =~ /--embedded (\w+)/) { - $::XID = $1; - $::isEmbedded = 1; - } -} - - -#- 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. -use POSIX qw(setlocale LC_ALL LC_COLLATE strftime); -use locale; -my $collation_locale = $ENV{LC_ALL}; -if ($collation_locale) { - $collation_locale =~ /UTF-8/ or setlocale(LC_ALL, "$collation_locale.UTF-8"); -} else { - $collation_locale = setlocale(LC_COLLATE); - $collation_locale =~ /UTF-8/ or setlocale(LC_COLLATE, "$collation_locale.UTF-8"); -} - -our $version = 1; -our %rpmdragora_options; - -my $i; -foreach (@ARGV) { - $i++; - /^-?-(\S+)$/ or next; - my $val = $1; - if ($val =~ /=/) { - my ($name, $values) = split /=/, $val; - my @values = split /,/, $values; - $rpmdragora_options{$name} = \@values if @values; - } else { - if ($val eq 'version') { - print "$0 $version\n"; - exit(0); - } elsif ($val =~ /^(test|expert)$/) { - eval "\$::$1 = 1"; - } elsif ($val =~ /^(q|quiet)$/) { - urpm::args::set_verbose(-1); - } elsif ($val =~ /^(v|verbose)$/) { - urpm::args::set_verbose(1); - } else { - $rpmdragora_options{$val} = 1; - } - } -} - -foreach my $option (qw(media mode parallel rpm-root search)) { - if (defined $rpmdragora_options{$option} && !ref($rpmdragora_options{$option})) { - warn qq(wrong usage of "$option" option!\n); - exit(-1); # too early for my_exit() - } -} - -$urpm::args::options{basename} = 1; - -our $MODE = ref $rpmdragora_options{mode} ? $rpmdragora_options{mode}[0] : undef; -our $overriding_config = defined $MODE; -unless ($MODE) { - $MODE = 'install'; - $0 =~ m|remove$| and $MODE = 'remove'; - $0 =~ m|update$|i and $MODE = 'update'; -} - -our $default_list_mode; -$default_list_mode = 'gui_pkgs' if $MODE eq 'install'; -if ($MODE eq 'remove') { - $default_list_mode = 'installed'; -} elsif ($MODE eq 'update') { - $default_list_mode = 'all_updates'; -} - -$MODE eq 'update' || $rpmdragora_options{'run-as-root'} and require_root_capability(); -$::noborderWhenEmbedded = 1; - -require AdminPanel::rpmdragora; - -our $changelog_first = $rpmdragora::changelog_first_config->[0]; -$changelog_first = 1 if $rpmdragora_options{'changelog-first'}; - -sub warn_about_user_mode() { - my $title = N("Running in user mode"); - my $msg = N("You are launching this program as a normal user.\n". - "You will not be able to perform modifications on the system,\n". - "but you may still browse the existing database."); - - if(($EUID != 0) and (!AdminPanel::rpmdragora::interactive_msg($title, $msg))) { - return 0; - } - return 1; -} - -sub init() { - URPM::bind_rpm_textdomain_codeset(); -} - -1; diff --git a/AdminPanel/Rpmdragora/localization.pm b/AdminPanel/Rpmdragora/localization.pm deleted file mode 100644 index fb199d93..00000000 --- a/AdminPanel/Rpmdragora/localization.pm +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/perl -# vim: set et ts=4 sw=4: -package AdminPanel::Rpmdragora::localization; -#***************************************************************************** -# -# Copyright (c) 2013 Matteo Pasotti -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2, as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -#***************************************************************************** -use strict; -use warnings; -use diagnostics; -use lib qw(/usr/lib/libDrakX); -use common; - -Locale::gettext::bind_textdomain_codeset($_, 'UTF8') foreach 'libDrakX', if_(!$::isInstall, 'libDrakX-standalone'), - if_($::isRestore, 'draksnapshot'), if_($::isInstall, 'urpmi'), - 'drakx-net', 'drakx-kbd-mouse-x11', # shared translation - @::textdomains; - -#========= UGLY WORKAROUND ============ -push @::textdomains, 'rpmdrake'; -#========= UGLY WORKAROUND ============ diff --git a/AdminPanel/Rpmdragora/open_db.pm b/AdminPanel/Rpmdragora/open_db.pm deleted file mode 100644 index aa1fd14d..00000000 --- a/AdminPanel/Rpmdragora/open_db.pm +++ /dev/null @@ -1,162 +0,0 @@ -# vim: set et ts=4 sw=4: -package AdminPanel::Rpmdragora::open_db; -#***************************************************************************** -# -# Copyright (c) 2002 Guillaume Cottenceau -# Copyright (c) 2002-2007 Thierry Vignaud -# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA -# Copyright (c) 2005-2007 Mandriva SA -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2, as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -#***************************************************************************** -# -# $Id: open_db.pm 268344 2010-05-06 13:06:08Z jvictor $ - -use strict; -use common; -use AdminPanel::rpmdragora; -use URPM; -use urpm; -use urpm::args; -use urpm::select; -use urpm::media; -use feature 'state'; - -use Exporter; -our @ISA = qw(Exporter); -our @EXPORT = qw(fast_open_urpmi_db - get_backport_media - get_inactive_backport_media - get_update_medias - is_it_a_devel_distro - open_rpm_db - open_urpmi_db - ); - - -# because rpm blocks some signals when rpm DB is opened, we don't keep open around: -sub open_rpm_db { - my ($o_force) = @_; - my $host; - log::explanations("opening the RPM database"); - if ($::rpmdragora_options{parallel} && ((undef, $host) = @{$::rpmdragora_options{parallel}})) { - state $done; - my $dblocation = "/var/cache/urpmi/distantdb/$host"; - if (!$done || $o_force) { - print "syncing db from $host to $dblocation..."; - mkdir_p "$dblocation/var/lib/rpm"; - system "rsync -Sauz -e ssh $host:/var/lib/rpm/ $dblocation/var/lib/rpm"; - $? == 0 or die "Couldn't sync db from $host to $dblocation"; - $done = 1; - print "done.\n"; - } - URPM::DB::open($dblocation) or die "Couldn't open RPM DB"; - } else { - my $db; - if ($::env) { - #- URPM has same methods as URPM::DB and empty URPM will be seen as empty URPM::DB. - $db = new URPM; - $db->parse_synthesis("$::env/rpmdb.cz"); - } else { - $db = URPM::DB::open($::rpmdragora_options{'rpm-root'}[0]); - } - $db or die "Couldn't open RPM DB (" . ($::env ? "$::env/rpmdb.cz" : $::rpmdragora_options{'rpm-root'}[0]) . ")"; - } -} - -# do not pay the urpm::media::configure() heavy cost: -sub fast_open_urpmi_db() { - my $urpm = urpm->new; - my $error_happened; - $urpm->{fatal} = sub { - $error_happened = 1; - interactive_msg(N("Fatal error"), - N("A fatal error occurred: %s.", $_[1])); - }; - - urpm::set_files($urpm, $::rpmdragora_options{'urpmi-root'}[0]) if $::rpmdragora_options{'urpmi-root'}[0]; - $::rpmdragora_options{'rpm-root'}[0] ||= $::rpmdragora_options{'urpmi-root'}[0]; - urpm::args::set_root($urpm, $::rpmdragora_options{'rpm-root'}[0]) if $::rpmdragora_options{'rpm-root'}[0]; - urpm::args::set_debug($urpm) if $::rpmdragora_options{debug}; - $urpm->get_global_options; - $urpm->{options}{wait_lock} = $::rpmdragora_options{'wait-lock'}; - $urpm->{options}{'verify-rpm'} = !$::rpmdragora_options{'no-verify-rpm'} if defined $::rpmdragora_options{'no-verify-rpm'}; - $urpm->{options}{auto} = $::rpmdragora_options{auto} if defined $::rpmdragora_options{auto}; - urpm::args::set_verbosity(); - if ($::rpmdragora_options{env} && $::rpmdragora_options{env}[0]) { - $::env = $::rpmdragora_options{env}[0]; - # prevent crashing in URPM.pm prevent when using --env: - $::env = "$ENV{PWD}/$::env" if $::env !~ m!^/!; - urpm::set_env($urpm, $::env); - } - - $urpm::args::options{justdb} = $::rpmdragora_options{justdb}; - - urpm::media::read_config($urpm, 0); - foreach (@{$urpm->{media}}) { - next if $_->{ignore}; - urpm::media::_tempignore($_, 1) if $ignore_debug_media->[0] && $_->{name} =~ /debug/i; - } - # FIXME: seems uneeded with newer urpmi: - if ($error_happened) { - touch('/etc/urpmi/urpmi.cfg'); - exec('edit-urpm-sources.pl'); - } - $urpm; -} - -sub is_it_a_devel_distro() { - state $res; - return $res if defined $res; - - my $path = $::rpmdragora_options{'urpmi-root'}[0] . '/etc/product.id'; - $res = common::parse_LDAP_namespace_structure(cat_($path))->{branch} eq 'Devel'; - return $res; -} - -sub get_backport_media { - my ($urpm) = @_; - grep { $_->{name} =~ /backport/i && - $_->{name} !~ /debug|sources/i } @{$urpm->{media}}; -} - -sub get_inactive_backport_media { - my ($urpm) = @_; - map { $_->{name} } grep { $_->{ignore} } get_backport_media($urpm); -} - -sub get_update_medias { - my ($urpm) = @_; - if (is_it_a_devel_distro()) { - grep { !$_->{ignore} } @{$urpm->{media}}; - } else { - grep { !$_->{ignore} && $_->{update} } @{$urpm->{media}}; - } -} - -sub open_urpmi_db { - my (%urpmi_options) = @_; - my $urpm = fast_open_urpmi_db(); - my $media = ref $::rpmdragora_options{media} ? join(',', @{$::rpmdragora_options{media}}) : ''; - - my $searchmedia = $urpmi_options{update} ? undef : join(',', get_inactive_backport_media($urpm)); - $urpm->{lock} = urpm::lock::urpmi_db($urpm, undef, wait => $urpm->{options}{wait_lock}) if !$::env; - my $previous = $::rpmdragora_options{'previous-priority-upgrade'}; - urpm::select::set_priority_upgrade_option($urpm, (ref $previous ? join(',', @$previous) : ())); - urpm::media::configure($urpm, media => $media, if_($searchmedia, searchmedia => $searchmedia), %urpmi_options); - $urpm; -} - -1; diff --git a/AdminPanel/Rpmdragora/pkg.pm b/AdminPanel/Rpmdragora/pkg.pm deleted file mode 100644 index e8c1a08a..00000000 --- a/AdminPanel/Rpmdragora/pkg.pm +++ /dev/null @@ -1,997 +0,0 @@ -# vim: set et ts=4 sw=4: -package AdminPanel::Rpmdragora::pkg; -#***************************************************************************** -# -# Copyright (c) 2002 Guillaume Cottenceau -# Copyright (c) 2002-2007 Thierry Vignaud -# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA -# Copyright (c) 2005-2007 Mandriva SA -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2, as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -#***************************************************************************** -# -# $Id: pkg.pm 270160 2010-06-22 19:55:40Z jvictor $ - -use strict; -use MDK::Common::Func 'any'; -use lib qw(/usr/lib/libDrakX); -use common; -use POSIX qw(_exit); -use URPM; -use utf8; -use AdminPanel::Rpmdragora::open_db; -use AdminPanel::Rpmdragora::gurpm; -use AdminPanel::Rpmdragora::formatting; -use AdminPanel::Rpmdragora::rpmnew; - -use AdminPanel::rpmdragora; -use urpm; -use urpm::lock; -use urpm::install; -use urpm::signature; -use urpm::get_pkgs; -use urpm::select; -use urpm::main_loop; -use urpm::args qw(); - - -use Exporter; -our @ISA = qw(Exporter); -our @EXPORT = qw( - $priority_up_alread_warned - download_callback - extract_header - find_installed_version - get_pkgs - perform_installation - perform_removal - run_rpm - sort_packages - ); - -#use mygtk2 qw(gtknew); -#use ugtk2 qw(:all); - -our $priority_up_alread_warned; - -sub sort_packages_biarch { - sort { - my ($na, $aa) = $a =~ /^(.*-[^-]+-[^-]+)\.([^.-]+)$/; - my ($nb, $ab) = $b =~ /^(.*-[^-]+-[^-]+)\.([^.-]+)$/; - $na cmp $nb || ($ab =~ /64$/) <=> ($aa =~ /64$/); - } @_; -} - -sub sort_packages_monoarch { - sort { uc($a) cmp uc($b) } @_; -} - -*sort_packages = arch() =~ /x86_64/ ? \&sort_packages_biarch : \&sort_packages_monoarch; - -sub run_rpm { - foreach (qw(LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT LC_IDENTIFICATION LC_ALL)) { - local $ENV{$_} = $ENV{$_} . '.UTF-8' if $ENV{$_} && $ENV{$_} !~ /UTF-8/; - } - my @l = map { ensure_utf8($_); $_ } run_program::get_stdout(@_); - wantarray() ? @l : join('', @l); -} - - -sub extract_header { - my ($pkg, $urpm, $xml_info, $o_installed_version) = @_; - my %fields = ( - info => 'description', - files => 'files', - changelog => 'changelog', - ); - # already extracted: - return if $pkg->{$fields{$xml_info}}; - - my $p = $pkg->{pkg}; - - if (!$p) { - warn ">> ghost package '$pkg' has no URPM object!!!\n"; - return; - } - - my $name = $p->fullname; - # fix extracting info for SRPMS and RPM GPG keys: - $name =~ s!\.src!!; - - if ($p->flag_installed && !$p->flag_upgrade) { - my @files = map { chomp_($_) } run_rpm("rpm -ql $name"); - add2hash($pkg, { files => [ @files ? @files : N("(none)") ], - description => rpm_description(scalar(run_rpm("rpm -q --qf '%{description}' $name"))), - changelog => format_changelog_string($o_installed_version, scalar(run_rpm("rpm -q --changelog $name"))) }); - } else { - my $medium = pkg2medium($p, $urpm); - my ($local_source, %xml_info_pkgs, $bar_id); - my $_statusbar_clean_guard = before_leaving { $bar_id and statusbar_msg_remove($bar_id) }; - my $dir = urpm::file_from_local_url($medium->{url}); - print "p->filename: ". $p->filename."\n"; - $local_source = "$dir/" . $p->filename if $dir; - print "local_source: $local_source\n"; - if (-e $local_source) { - $bar_id = statusbar_msg(N("Getting information from %s...", $dir), 0); - $urpm->{log}("getting information from rpms from $dir"); - } else { - my $gurpm; - $bar_id = statusbar_msg(N("Getting '%s' from XML meta-data...", $xml_info), 0); - my $_gurpm_clean_guard = before_leaving { undef $gurpm }; - if (my $xml_info_file = eval { urpm::media::any_xml_info($urpm, $medium, $xml_info, undef, sub { - $gurpm ||= Rpmdragora::gurpm->new(N("Please wait"), - '', # FIXME: add a real string after cooker - transient => $::main_window); - download_callback($gurpm, @_) - or goto header_non_available; - }) }) { - require urpm::xml_info; - require urpm::xml_info_pkg; - $urpm->{log}("getting information from $xml_info_file"); - my %nodes = eval { urpm::xml_info::get_nodes($xml_info, $xml_info_file, [ $name ]) }; - goto header_non_available if $@; - put_in_hash($xml_info_pkgs{$name} ||= {}, $nodes{$name}); - } else { - if ($xml_info eq 'info') { - $urpm->{info}(N("No xml info for medium \"%s\", only partial result for package %s", $medium->{name}, $name)); - } else { - $urpm->{error}(N("No xml info for medium \"%s\", unable to return any result for package %s", $medium->{name}, $name)); - } - } - } - - #- even if non-root, search for a header in the global cachedir - if (-s $local_source) { - $p->update_header($local_source) or do { - warn "Warning, could not extract header for $name from $medium!"; - goto header_non_available; - }; - my @files = $p->files; - @files = N("(none)") if !@files; - add2hash($pkg, { description => rpm_description($p->description), - files => \@files, - url => $p->url, - changelog => format_changelog_changelogs($o_installed_version, $p->changelogs) }); - $p->pack_header; # needed in order to call methods on objects outside ->traverse - } elsif ($xml_info_pkgs{$name}) { - if ($xml_info eq 'info') { - add2hash($pkg, { description => rpm_description($xml_info_pkgs{$name}{description}), - url => $xml_info_pkgs{$name}{url} - }); - } elsif ($xml_info eq 'files') { - my @files = map { chomp_(to_utf8($_)) } split("\n", $xml_info_pkgs{$name}{files}); - add2hash($pkg, { files => [ @files ? @files : N("(none)") ] }); - } elsif ($xml_info eq 'changelog') { - add2hash($pkg, { - changelog => format_changelog_changelogs($o_installed_version, - @{$xml_info_pkgs{$name}{changelogs}}) - }); - } - } else { - goto header_non_available; - } - return; - header_non_available: - add2hash($pkg, { summary => $p->summary || N("(Not available)"), description => undef }); - } -} - -sub find_installed_version { - my ($p) = @_; - my $version; - open_rpm_db()->traverse_tag_find('name', $p->name, sub { $version = $_[0]->EVR }); - $version || N("(none)"); -} - -my $canceled; -sub download_callback { - my ($gurpm, $mode, $file, $percent, $total, $eta, $speed) = @_; - $canceled = 0; - if ($mode eq 'start') { - $gurpm->label(N("Downloading package `%s'...", basename($file))); - $gurpm->validate_cancel(but(N("Cancel")), sub { $canceled = 1 }); - } elsif ($mode eq 'progress') { - $gurpm->label( - join("\n", - N("Downloading package `%s'...", basename($file)), - (defined $total && defined $eta ? - N(" %s%% of %s completed, ETA = %s, speed = %s", $percent, $total, $eta, $speed) - : N(" %s%% completed, speed = %s", $percent, $speed) - ) =~ /^\s*(.*)/ - ), - ); - #$gurpm->progress($percenti/100); - $gurpm->progress($percent); - } elsif ($mode eq 'end') { - $gurpm->progress(100); - $gurpm->invalidate_cancel; - } - !$canceled; -} - - -# -=-=-=---=-=-=---=-=-=-- install packages -=-=-=---=-=-=---=-=-=- - -my (@update_medias, $is_update_media_already_asked); - -sub warn_about_media { - my ($w, %options) = @_; - - return if $::MODE ne 'update'; - return if $::rpmdragora_options{'no-media-update'}; - - # we use our own instance of the urpmi db in order not to mess up with skip-list managment (#31092): - # and no need to fully configure urpmi since we may have to do it again anyway because of new media: - my $urpm = fast_open_urpmi_db(); - - my $_lock = urpm::lock::urpmi_db($urpm, undef, wait => $urpm->{options}{wait_lock}); - - # build media list: - @update_medias = get_update_medias($urpm); - - # do not update again media after installing/removing some packages: - $::rpmdragora_options{'no-media-update'} ||= 1; - - if (@update_medias > 0) { - if (!$options{skip_updating_mu} && !$is_update_media_already_asked) { - $is_update_media_already_asked = 1; - $::rpmdragora_options{'no-confirmation'} or interactive_msg(N("Confirmation"), -N("I need to contact the mirror to get latest update packages. -Please check that your network is currently running. - -Is it ok to continue?"), yesno => 1, - widget => gtknew('CheckButton', text => N("Do not ask me next time"), - active_ref => \$::rpmdragora_options{'no-confirmation'} - )) or myexit(-1); - writeconf(); - urpm::media::select_media($urpm, map { $_->{name} } @update_medias); - update_sources($urpm, noclean => 1, medialist => [ map { $_->{name} } @update_medias ]); - } - } else { - if (any { $_->{update} } @{$urpm->{media}}) { - interactive_msg(N("Already existing update media"), -N("You already have at least one update medium configured, but -all of them are currently disabled. You should run the Software -Media Manager to enable at least one (check it in the \"%s\" -column). - -Then, restart \"%s\".", N("Enabled"), $rpmdragora::myname_update)); - myexit(-1); - } - my ($mirror) = choose_mirror($urpm, transient => $w->{real_window} || $::main_window, - message => join("\n\n", - N("You have no configured update media. MageiaUpdate cannot operate without any update media."), - N("I need to contact the Mageia website to get the mirror list. -Please check that your network is currently running. - -Is it ok to continue?"), - ), - ); - my $m = ref($mirror) ? $mirror->{url} : ''; - $m or interactive_msg(N("How to choose manually your mirror"), -N("You may also choose your desired mirror manually: to do so, -launch the Software Media Manager, and then add a `Security -updates' medium. - -Then, restart %s.", $rpmdragora::myname_update)), myexit(-1); - add_distrib_update_media($urpm, $mirror, only_updates => 1); - } -} - - -sub get_parallel_group() { - $::rpmdragora_options{parallel} ? $::rpmdragora_options{parallel}[0] : undef; -} - -my ($count, $level, $limit, $new_stage, $prev_stage, $total); - -sub init_progress_bar { - my ($urpm) = @_; - undef $_ foreach $count, $prev_stage, $new_stage, $limit; - $level = 0.05; - $total = @{$urpm->{depslist}}; -} - -sub reset_pbar_count { - undef $prev_stage; - $count = 0; - $limit = $_[0]; -} - -sub update_pbar { - my ($gurpm) = @_; - return if !$total; # don't die if there's no source - $count++; - $new_stage = $level+($limit-$level)*$count/$total; - $prev_stage = 0 if(!defined($prev_stage)); - if ($prev_stage + 0.01*100 < $new_stage) { - $prev_stage = $new_stage; - $gurpm->progress($new_stage); - } -} - - -sub get_installed_packages { - my ($urpm, $db, $all_pkgs, $gurpm) = @_; - - $urpm->{global_config}{'prohibit-remove'} = '' if(!defined($urpm->{global_config}{'prohibit-remove'})); - my @base = ("basesystem", split /,\s*/, $urpm->{global_config}{'prohibit-remove'}); - my (%base, %basepackages, @installed_pkgs, @processed_base); - reset_pbar_count(0.33); - while (defined(local $_ = shift @base)) { - exists $basepackages{$_} and next; - $db->traverse_tag(m|^/| ? 'path' : 'whatprovides', [ $_ ], sub { - update_pbar($gurpm); - my $name = $_[0]->fullname; - # workaround looping in URPM: - return if member($name, @processed_base); - push @processed_base, $name; - push @{$basepackages{$_}}, $name; - push @base, $_[0]->requires_nosense; - }); - } - foreach (values %basepackages) { - my $n = @$_; #- count number of times it's provided - foreach (@$_) { - $base{$_} = \$n; - } - } - # costly: - $db->traverse(sub { - my ($pkg) = @_; - update_pbar($gurpm); - my $fullname = urpm_name($pkg); - return if $fullname =~ /@/; - $all_pkgs->{$fullname} = { - pkg => $pkg, urpm_name => $fullname, - } if !($all_pkgs->{$fullname} && $all_pkgs->{$fullname}{description}); - if (my $name = $base{$fullname}) { - $all_pkgs->{$fullname}{base} = \$name; - $pkg->set_flag_base(1) if $$name == 1; - } - push @installed_pkgs, $fullname; - $pkg->set_flag_installed; - $pkg->pack_header; # needed in order to call methods on objects outside ->traverse - }); - @installed_pkgs; -} - -urpm::select::add_packages_to_priority_upgrade_list('rpmdragora', 'perl-Glib', 'perl-Gtk2'); - -my ($priority_state, $priority_requested); -our $need_restart; - -our $probe_only_for_updates; - -sub get_updates_list { - my ($urpm, $db, $state, $requested, $requested_list, $requested_strict, $all_pkgs, %limit_preselect) = @_; - - $urpm->request_packages_to_upgrade( - $db, - $state, - $requested, - %limit_preselect - ); - - my %common_opts = ( - callback_choices => \&Rpmdragora::gui::callback_choices, - priority_upgrade => $urpm->{options}{'priority-upgrade'}, - ); - - if ($urpm->{options}{'priority-upgrade'}) { - $need_restart = - urpm::select::resolve_priority_upgrades_after_auto_select($urpm, $db, $state, - $requested, %common_opts); - } - - # list of updates (including those matching /etc/urpmi/skip.list): - @$requested_list = sort map { - my $name = urpm_name($_); - $all_pkgs->{$name} = { pkg => $_ }; - $name; - } @{$urpm->{depslist}}[keys %$requested]; - - # list of pure updates (w/o those matching /etc/urpmi/skip.list but with their deps): - if ($probe_only_for_updates && !$need_restart) { - @$requested_strict = sort map { - urpm_name($_); - } $urpm->resolve_requested($db, $state, $requested, callback_choices => \&Rpmdragora::gui::callback_choices); - - if (my @l = grep { $state->{selected}{$_->id} } - urpm::select::_priority_upgrade_pkgs($urpm, $urpm->{options}{'priority-upgrade'})) { - if (!$need_restart) { - $need_restart = - urpm::select::_resolve_priority_upgrades($urpm, $db, $state, $state->{selected}, - \@l, %common_opts); - } - } - } - - if ($need_restart) { - $requested_strict = [ map { scalar $_->fullname } @{$urpm->{depslist}}[keys %{$state->{selected}}] ]; - # drop non priority updates: - @$requested_list = (); - } - - # list updates including skiped ones + their deps in MageiaUpdate: - @$requested_list = uniq(@$requested_list, @$requested_strict); - - # do not pre select updates in rpmdragora: - @$requested_strict = () if !$probe_only_for_updates; -} - -sub get_pkgs { - my (%options) = @_; - my $w = $::main_window; - - my $gurpm = AdminPanel::Rpmdragora::gurpm->new(1 ? N("Please wait") : N("Package installation..."), N("Initializing..."), transient => $::main_window); - my $_gurpm_clean_guard = before_leaving { undef $gurpm }; - #my $_flush_guard = Gtk2::GUI_Update_Guard->new; - - warn_about_media($w, %options); - - my $urpm = open_urpmi_db(update => $probe_only_for_updates && !is_it_a_devel_distro()); - - my $_drop_lock = before_leaving { undef $urpm->{lock} }; - - $priority_up_alread_warned = 0; - - # update media list in case warn_about_media() added some: - @update_medias = get_update_medias($urpm); - - $gurpm->label(N("Reading updates description")); - $gurpm->progress(100); - - #- parse the description file - my $update_descr = urpm::get_updates_description($urpm, @update_medias); - - my $_unused = N("Please wait, finding available packages..."); - - # find out installed packages: - - init_progress_bar($urpm); - - $gurpm->label(N("Please wait, listing base packages...")); - $gurpm->progress($level*100); - - my $db = eval { open_rpm_db() }; - if (my $err = $@) { - interactive_msg(N("Error"), N("A fatal error occurred: %s.", $err)); - return; - } - - my $sig_handler = sub { undef $db; exit 3 }; - local $SIG{INT} = $sig_handler; - local $SIG{QUIT} = $sig_handler; - - $gurpm->label(N("Please wait, finding installed packages...")); - $gurpm->progress($level = 0.33*100); - reset_pbar_count(0.66*100); - my (@installed_pkgs, %all_pkgs); - if (!$probe_only_for_updates) { - @installed_pkgs = get_installed_packages($urpm, $db, \%all_pkgs, $gurpm); - } - - if (my $group = get_parallel_group()) { - urpm::media::configure($urpm, parallel => $group); - } - - # find out availlable packages: - - $urpm->{state} = {}; - - $gurpm->label(N("Please wait, finding available packages...")); - $gurpm->progress($level = 0.66*100); - - check_update_media_version($urpm, @update_medias); - - my $requested = {}; - my $state = {}; - my (@requested, @requested_strict); - - if ($compute_updates->[0] || $::MODE eq 'update') { - my %filter; - if ($options{pure_updates}) { - # limit to packages from update-media (dependencies can still come from other media) - %filter = (idlist => [ map { $_->{start} .. $_->{end} } @update_medias ]); - } - get_updates_list($urpm, $db, $state, $requested, \@requested, \@requested_strict, \%all_pkgs, %filter); - } - - if ($need_restart) { - $priority_state = $state; - $priority_requested = $requested; - } else { - ($priority_state, $priority_requested) = (); - } - - if (!$probe_only_for_updates) { - $urpm->compute_installed_flags($db); # TODO/FIXME: not for updates - $urpm->{depslist}[$_]->set_flag_installed foreach keys %$requested; #- pretend it's installed - } - $urpm->{rpmdragora_state} = $state; #- Don't forget it - $gurpm->progress($level = 0.7*100); - - my %l; - reset_pbar_count(1); - foreach my $pkg (@{$urpm->{depslist}}) { - update_pbar($gurpm); - $pkg->flag_upgrade or next; - my $key = $pkg->name . $pkg->arch; - $l{$key} = $pkg if !$l{$key} || $l{$key}->compare($pkg); - } - my @installable_pkgs = map { my $n = $_->fullname; $all_pkgs{$n} = { pkg => $_ }; $n } values %l; - undef %l; - - my @inactive_backports; - my @active_backports; - my @backport_medias = get_backport_media($urpm); - - foreach my $medium (@backport_medias) { - update_pbar($gurpm); - - # The 'searchmedia' flag differentiates inactive backport medias - # (because that option was passed to urpm::media::configure to - # temporarily enable them) - - my $backports = - $medium->{searchmedia} ? \@inactive_backports : \@active_backports; - - foreach my $pkg_id ($medium->{start} .. $medium->{end}) { - next if !$pkg_id; - my $pkg = $urpm->{depslist}[$pkg_id]; - $pkg->flag_upgrade or next; - my $name = $pkg->fullname; - push @$backports, $name; - $all_pkgs{$name} = { pkg => $pkg, is_backport => 1 }; - } - } - my @updates = @requested; - # selecting updates by default but skipped ones (MageiaUpdate only): - foreach (@requested_strict) { - $all_pkgs{$_}{selected} = 1; - } - - # urpmi only care about the first medium where it found the package, - # so there's no need to list the same package several time: - @installable_pkgs = uniq(difference2(\@installable_pkgs, \@updates)); - - my @meta_pkgs = grep { /^task-|^basesystem/ } keys %all_pkgs; - - my @gui_pkgs = map { chomp; $_ } cat_('/usr/share/rpmdrake/gui.lst'); - # add meta packages to GUI packages list (which expect basic names not fullnames): - push @gui_pkgs, map { (split_fullname($_))[0] } @meta_pkgs; - - +{ urpm => $urpm, - all_pkgs => \%all_pkgs, - installed => \@installed_pkgs, - installable => \@installable_pkgs, - updates => \@updates, - meta_pkgs => \@meta_pkgs, - gui_pkgs => [ grep { my $p = $all_pkgs{$_}{pkg}; $p && member(($p->fullname)[0], @gui_pkgs) } keys %all_pkgs ], - update_descr => $update_descr, - backports => [ @inactive_backports, @active_backports ], - inactive_backports => \@inactive_backports - }; -} - -sub display_READMEs_if_needed { - my ($urpm, $w) = @_; - return if !$urpm->{readmes}; - my %Readmes = %{$urpm->{readmes}}; - if (keys %Readmes) { #- display the README*.urpmi files - interactive_packtable( - N("Upgrade information"), - $w, - N("These packages come with upgrade information"), - [ map { - my $fullname = $_; - [ gtkpack__( - gtknew('HBox'), - gtkset_selectable(gtknew('Label', text => $Readmes{$fullname}),1), - ), - gtksignal_connect( - gtknew('Button', text => N("Upgrade information about this package")), - clicked => sub { - interactive_msg( - N("Upgrade information about package %s", $Readmes{$fullname}), - (join '' => map { s/$/\n/smg; $_ } formatAlaTeX(scalar cat_($fullname))), - scroll => 1, - ); - }, - ), - ] } keys %Readmes ], - [ gtknew('Button', text => N("Ok"), clicked => sub { Gtk2->main_quit }) ] - ); - } -} - -sub perform_parallel_install { - my ($urpm, $group, $w, $statusbar_msg_id) = @_; - my @pkgs = map { if_($_->flag_requested, urpm_name($_)) } @{$urpm->{depslist}}; - - my @error_msgs; - my $res = !run_program::run('urpmi', '2>', \@error_msgs, '-v', '--X', '--parallel', $group, @pkgs); - - if ($res) { - $$statusbar_msg_id = statusbar_msg( - #N("Everything installed successfully"), - N("All requested packages were installed successfully."), - ); - } else { - interactive_msg( - N("Problem during installation"), - N("There was a problem during the installation:\n\n%s", join("\n", @error_msgs)), - scroll => 1, - ); - } - open_rpm_db('force_sync'); - $w->set_sensitive(1); - return 0; -} - -sub perform_installation { #- (partially) duplicated from /usr/sbin/urpmi :-( - my ($urpm, $pkgs) = @_; - - my @error_msgs; - my $statusbar_msg_id; - my $gurpm; - local $urpm->{fatal} = sub { - my $fatal_msg = $_[1]; - printf STDERR "Fatal: %s\n", $fatal_msg; - undef $gurpm; - interactive_msg(N("Installation failed"), - N("There was a problem during the installation:\n\n%s", $fatal_msg)); - goto return_with_exit_code; - }; - local $urpm->{error} = sub { printf STDERR "Error: %s\n", $_[0]; push @error_msgs, $_[0] }; - - my $w = $::main_window; - #$w->set_sensitive(0); - #my $_restore_sensitive = before_leaving { $w->set_sensitive(1) }; - - # my $_flush_guard = Gtk2::GUI_Update_Guard->new; - - if (my $group = get_parallel_group()) { - return perform_parallel_install($urpm, $group, $w, \$statusbar_msg_id); - } - - my ($lock, $rpm_lock); - if (!$::env) { - $lock = urpm::lock::urpmi_db($urpm, undef, wait => $urpm->{options}{wait_lock}); - $rpm_lock = urpm::lock::rpm_db($urpm, 'exclusive'); - } - my $state = $priority_state || $probe_only_for_updates ? { } : $urpm->{rpmdragora_state}; - - my $bar_id = statusbar_msg(N("Checking validity of requested packages..."), 0); - - # FIXME: THIS SET flag_requested on all packages!!!! - # select packages to install / enssure selected pkg set is consistant: - my %saved_flags; - my $requested = { map { - $saved_flags{$_->id} = $_->flag_requested; - $_->id => undef; - } grep { $_->flag_selected } @{$urpm->{depslist}} }; - urpm::select::resolve_dependencies( - $urpm, $state, $requested, - rpmdb => $::env && "$::env/rpmdb.cz", - callback_choices => \&Rpmdragora::gui::callback_choices, - ); - statusbar_msg_remove($bar_id); - - my ($local_sources, $blist) = urpm::get_pkgs::selected2local_and_blists($urpm, $state->{selected}); - if (!$local_sources && (!$blist || !@$blist)) { - interactive_msg( - N("Unable to get source packages."), - N("Unable to get source packages, sorry. %s", - @error_msgs ? N("\n\nError(s) reported:\n%s", join("\n", @error_msgs)) : ''), - scroll => 1, - ); - goto return_with_exit_code; - } - - my @to_install = @{$urpm->{depslist}}[keys %{$state->{selected}}]; - my @pkgs = map { scalar($_->fullname) } sort(grep { $_->flag_selected } @to_install); - - @{$urpm->{ask_remove}} = sort(urpm::select::removed_packages($urpm->{state})); - my @to_remove = map { if_($pkgs->{$_}{selected} && !$pkgs->{$_}{pkg}->flag_upgrade, $pkgs->{$_}{urpm_name}) } keys %$pkgs; - - my $r = format_list(map { scalar(urpm::select::translate_why_removed_one($urpm, $urpm->{state}, $_)) } @to_remove); - - my ($size, $filesize) = $urpm->selected_size_filesize($state); - my $install_count = int(@pkgs); - my $to_install = $install_count == 0 ? '' : - ($priority_state ? '' . N("Rpmdragora or one of its priority dependencies needs to be updated first. Rpmdragora will then restart.") . '' . "\n\n" : '') . - (P("The following package is going to be installed:", "The following %d packages are going to be installed:", $install_count, $install_count) - . "\n\n" . format_list(map { s!.*/!!; $_ } @pkgs)); - my $remove_count = scalar(@to_remove); - interactive_msg(($to_install ? N("Confirmation") : N("Some packages need to be removed")), - join("\n\n", - ($r ? - (!$to_install ? (P("Remove one package?", "Remove %d packages?", $remove_count, $remove_count), $r) : - (($remove_count == 1 ? - N("The following package has to be removed for others to be upgraded:") - : N("The following packages have to be removed for others to be upgraded:")), $r), if_($to_install, $to_install)) - : $to_install), - format_size($size), - format_filesize($filesize), - N("Is it ok to continue?")), - scroll => 1, - yesno => 1) or return 1; - - my $_umount_guard = before_leaving { urpm::removable::try_umounting_removables($urpm) }; - - # select packages to uninstall for !update mode: - perform_removal($urpm, { map { $_ => $pkgs->{$_} } @to_remove }) if !$probe_only_for_updates; - - # $gurpm = Rpmdragora::gurpm->new(1 ? N("Please wait") : N("Package installation..."), N("Initializing..."), transient => $::main_window); - # my $_gurpm_clean_guard = before_leaving { undef $gurpm }; - my $something_installed; - - if (@to_install && $::rpmdragora_options{auto_orphans}) { - urpm::orphans::compute_future_unrequested_orphans($urpm, $state); - if (my @orphans = map { scalar $_->fullname } @{$state->{orphans_to_remove}}) { - interactive_msg(N("Orphan packages"), P("The following orphan package will be removed.", - "The following orphan packages will be removed.", scalar(@orphans)) - . "\n" . urpm::orphans::add_leading_spaces(join("\n", @orphans) . "\n"), scroll => 1); - } - } - - urpm::orphans::mark_as_requested($urpm, $state, 0); - - my ($progress, $total, @rpms_upgrade); - my $transaction; - my ($progress_nb, $transaction_progress_nb, $remaining, $done); - my $callback_inst = sub { - my ($urpm, $type, $id, $subtype, $amount, $total) = @_; - my $pkg = defined $id ? $urpm->{depslist}[$id] : undef; - if ($subtype eq 'start') { - if ($type eq 'trans') { - print(1 ? N("Preparing package installation...") : N("Preparing package installation transaction...")); - # $gurpm->label(1 ? N("Preparing package installation...") : N("Preparing package installation transaction...")); - } elsif (defined $pkg) { - $something_installed = 1; - print(N("Installing package `%s' (%s/%s)...", $pkg->name, ++$transaction_progress_nb, scalar(@{$transaction->{upgrade}}))."\n" . N("Total: %s/%s", ++$progress_nb, $install_count)); - # $gurpm->label(N("Installing package `%s' (%s/%s)...", $pkg->name, ++$transaction_progress_nb, scalar(@{$transaction->{upgrade}})) - # . "\n" . N("Total: %s/%s", ++$progress_nb, $install_count)); - } - } elsif ($subtype eq 'progress') { - $gurpm->progress($total ? ($amount/$total)*100 : 100); - print("Progress: ".($total ? ($amount/$total)*100 : 100)."\n"); - } - }; - - # FIXME: sometimes state is lost: - my @ask_unselect = urpm::select::unselected_packages($state); - - # fix flags for orphan computing: - foreach (keys %{$state->{selected}}) { - my $pkg = $urpm->{depslist}[$_]; - $pkg->set_flag_requested($saved_flags{$pkg->id}); - } - my $exit_code = - urpm::main_loop::run($urpm, $state, 1, \@ask_unselect, - { - completed => sub { - # explicitly destroy the progress window when it's over; we may - # have sg to display before returning (errors, rpmnew/rpmsave, ...): - undef $gurpm; - - undef $lock; - undef $rpm_lock; - }, - inst => $callback_inst, - trans => $callback_inst, - ask_yes_or_no => sub { - # handle 'allow-force' and 'allow-nodeps' options: - my ($title, $msg) = @_; - local $::main_window = $gurpm->{real_window}; - interactive_msg($title, $msg, yesno => 1, scroll => 1, - ); - }, - message => sub { - my ($title, $message) = @_; - interactive_msg($title, $message, scroll => 1); - }, - # cancel installation when 'cancel' button is pressed: - trans_log => sub { download_callback($gurpm, @_) or goto return_with_exit_code }, - post_extract => sub { - my ($set, $transaction_sources, $transaction_sources_install) = @_; - $transaction = $set; - $transaction_progress_nb = 0; - $done += grep { !/\.src\.rpm$/ } values %$transaction_sources; #updates - $total = keys(%$transaction_sources_install) + keys %$transaction_sources; - push @rpms_upgrade, keys %$transaction_sources; - $done += grep { !/\.src\.rpm$/ } values %$transaction_sources_install; # installs - }, - pre_removable => sub { - # Gtk2::GUI_Update_Guard->new use of alarm() kill us when - # running system(), thus making DVD being ejected and printing - # wrong error messages (#30463) - - local $SIG{ALRM} = sub { die "ALARM" }; - $remaining = alarm(0); - }, - - post_removable => sub { alarm $remaining }, - copy_removable => sub { - my ($medium) = @_; - interactive_msg( - N("Change medium"), - N("Please insert the medium named \"%s\"", $medium), - yesno => 1, text => { no => N("Cancel"), yes => N("Ok") }, - ); - }, - pre_check_sig => sub { $gurpm->label(N("Verifying package signatures...")) }, - check_sig => sub { $gurpm->progress((++$progress/$total)*100) }, - bad_signature => sub { - my ($msg, $msg2) = @_; - local $::main_window = $gurpm->{real_window}; - $msg =~ s/:$/\n\n/m; # FIXME: to be fixed in urpmi after 2008.0 - interactive_msg( - N("Warning"), "$msg\n\n$msg2", yesno => 1, if_(10 < ($msg =~ tr/\n/\n/), scroll => 1), - ); - }, - post_download => sub { - $canceled and goto return_with_exit_code; - $gurpm->invalidate_cancel_forever; - }, - need_restart => sub { - my ($need_restart_formatted) = @_; - # FIXME: offer to restart the system - interactive_msg(N("Warning"), join("\n", values %$need_restart_formatted), scroll => 1); - }, - trans_error_summary => sub { - my ($nok, $errors) = @_; - interactive_msg( - N("Problem during installation"), - if_($nok, N("%d installation transactions failed", $nok) . "\n\n") . - N("There was a problem during the installation:\n\n%s", - join("\n\n", @$errors, @error_msgs)), - scroll => 1, - ); - }, - need_restart => sub { - my ($need_restart_formatted) = @_; - interactive_msg(N("Warning"), - join("\n\n", values %$need_restart_formatted)); - }, - success_summary => sub { - if (!($done || @to_remove)) { - interactive_msg(N("Error"), - N("Unrecoverable error: no package found for installation, sorry.")); - return; - } - my $id = statusbar_msg(N("Inspecting configuration files..."), 0); - my %pkg2rpmnew; - foreach my $id (@rpms_upgrade) { - my $pkg = $urpm->{depslist}[$id]; - next if $pkg->arch eq 'src'; - $pkg2rpmnew{$pkg->fullname} = [ grep { -r "$_.rpmnew" || -r "$_.rpmsave" } $pkg->conf_files ]; - } - statusbar_msg_remove($id); - dialog_rpmnew(N("The installation is finished; everything was installed correctly. - -Some configuration files were created as `.rpmnew' or `.rpmsave', -you may now inspect some in order to take actions:"), - %pkg2rpmnew) - and statusbar_msg(N("All requested packages were installed successfully."), 1); - statusbar_msg(N("Looking for \"README\" files..."), 1); - display_READMEs_if_needed($urpm, $w); - }, - already_installed_or_not_installable => sub { - my ($msg1, $msg2) = @_; - my $msg = join("\n", @$msg1, @$msg2); - return if !$msg; # workaround missing state - interactive_msg(N("Error"), $msg); - }, - }, - ); - - #- restart rpmdragora if needed, keep command line for that. - if ($need_restart && !$exit_code && $something_installed) { - log::explanations("restarting rpmdragora"); - #- it seems to work correctly with exec instead of system, provided we stop timers - #- added --previous-priority-upgrade to allow checking if yet if - #- priority-upgrade list has changed. and make sure we don't uselessly restart - my @argv = ('--previous-priority-upgrade=' . $urpm->{options}{'priority-upgrade'}, - grep { !/^--no-priority-upgrade$|--previous-priority-upgrade=/ } @Rpmdragora::init::ARGV_copy); - # remove "--emmbedded " from argv: - my $i = 0; - foreach (@argv) { - splice @argv, $i, 2 if /^--embedded$/; - $i++; - } - alarm(0); - # remember not to ask again questions and the like: - writeconf(); - exec($0, @argv); - exit(0); - } - - my $_s1 = N("RPM transaction %d/%d", 0, 0); - my $_s2 = N("Unselect all"); - my $_s3 = N("Details"); - - statusbar_msg_remove($statusbar_msg_id); #- XXX maybe remove this - - if ($exit_code == 0 && !$::rpmdragora_options{auto_orphans}) { - if (urpm::orphans::check_unrequested_orphans_after_auto_select($urpm)) { - if (my $msg = urpm::orphans::get_now_orphans_gui_msg($urpm)) { - interactive_msg(N("Orphan packages"), $msg, scroll => 1); - } - } - } - - return_with_exit_code: - return !($something_installed || scalar(@to_remove)); -} - - -# -=-=-=---=-=-=---=-=-=-- remove packages -=-=-=---=-=-=---=-=-=- - -sub perform_removal { - my ($urpm, $pkgs) = @_; - my @toremove = map { if_($pkgs->{$_}{selected}, $pkgs->{$_}{urpm_name}) } keys %$pkgs; - return if !@toremove; - my $gurpm = Rpmdragora::gurpm->new(1 ? N("Please wait") : N("Please wait, removing packages..."), N("Initializing..."), transient => $::main_window); - my $_gurpm_clean_guard = before_leaving { undef $gurpm }; - - my $may_be_orphans = 1; - urpm::orphans::unrequested_orphans_after_remove($urpm, \@toremove) - or $may_be_orphans = 0; - - my $progress = -1; - local $urpm->{log} = sub { - my $str = $_[0]; - print $str; - $progress++; - return if $progress <= 0; # skip first "creating transaction..." message - $gurpm->label($str); # display "removing package %s" - $gurpm->progress(min(0.99*100, scalar($progress/@toremove)*100)); - #gtkflush(); - }; - - my @results; - slow_func_statusbar( - N("Please wait, removing packages..."), - $::main_window, - sub { - @results = $::rpmdragora_options{parallel} - ? urpm::parallel::remove($urpm, \@toremove) - : urpm::install::install($urpm, \@toremove, {}, {}, - callback_report_uninst => sub { $gurpm->label($_[0]) }, - ); - open_rpm_db('force_sync'); - }, - ); - if (@results) { - interactive_msg( - N("Problem during removal"), - N("There was a problem during the removal of packages:\n\n%s", join("\n", @results)), - if_(@results > 1, scroll => 1), - ); - return 1; - } else { - if ($may_be_orphans && !$::rpmdragora_options{auto_orphans}) { - if (my $msg = urpm::orphans::get_now_orphans_gui_msg($urpm)) { - interactive_msg(N("Information"), $msg, scroll => 1); - } - } - return 0; - } -} - -1; diff --git a/AdminPanel/Rpmdragora/rpmnew.pm b/AdminPanel/Rpmdragora/rpmnew.pm deleted file mode 100644 index 3c4335d0..00000000 --- a/AdminPanel/Rpmdragora/rpmnew.pm +++ /dev/null @@ -1,205 +0,0 @@ -# vim: set et ts=4 sw=4: -package AdminPanel::Rpmdragora::rpmnew; -#***************************************************************************** -# -# Copyright (c) 2002 Guillaume Cottenceau -# Copyright (c) 2002-2007 Thierry Vignaud -# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA -# Copyright (c) 2005-2007 Mandriva SA -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2, as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -#***************************************************************************** -# -# $Id: rpmnew.pm 263914 2009-12-03 17:41:02Z tv $ - -use strict; -use lib qw(/usr/lib/libDrakX); -use common; -use AdminPanel::rpmdragora; -use AdminPanel::Rpmdragora::init; -use AdminPanel::Rpmdragora::pkg; -use AdminPanel::Rpmdragora::open_db; -use AdminPanel::Rpmdragora::formatting; -use Exporter; -our @ISA = qw(Exporter); -our @EXPORT = qw(dialog_rpmnew do_merge_if_needed); - -# /var/lib/nfs/etab /var/lib/nfs/rmtab /var/lib/nfs/xtab /var/cache/man/whatis -my %ignores_rpmnew = map { $_ => 1 } qw( - /etc/adjtime - /etc/fstab - /etc/group - /etc/ld.so.conf - /etc/localtime - /etc/modules - /etc/passwd - /etc/security/fileshare.conf - /etc/shells - /etc/sudoers - /etc/sysconfig/alsa - /etc/sysconfig/autofsck - /etc/sysconfig/harddisks - /etc/sysconfig/harddrake2/previous_hw - /etc/sysconfig/init - /etc/sysconfig/installkernel - /etc/sysconfig/msec - /etc/sysconfig/nfs - /etc/sysconfig/pcmcia - /etc/sysconfig/rawdevices - /etc/sysconfig/saslauthd - /etc/sysconfig/syslog - /etc/sysconfig/usb - /etc/sysconfig/xinetd -); - -sub inspect { - my ($file) = @_; - my ($rpmnew, $rpmsave) = ("$file.rpmnew", "$file.rpmsave"); - my @inspect_wsize = ($typical_width*2.5, 500); - my $rpmfile = 'rpmnew'; - -r $rpmnew or $rpmfile = 'rpmsave'; - -r $rpmnew && -r $rpmsave && (stat $rpmsave)[9] > (stat $rpmnew)[9] and $rpmfile = 'rpmsave'; - $rpmfile eq 'rpmsave' and $rpmnew = $rpmsave; - - foreach (qw(LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT LC_IDENTIFICATION LC_ALL)) { - local $ENV{$_} = $ENV{$_} . '.UTF-8' if $ENV{$_} && $ENV{$_} !~ /UTF-8/; - } - my @diff = map { ensure_utf8($_); $_ } `/usr/bin/diff -u '$file' '$rpmnew'`; - @diff = N("(none)") if !@diff; - my $d = ugtk2->new(N("Inspecting %s", $file), grab => 1, transient => $::main_window); - my $save_wsize = sub { @inspect_wsize = $d->{rwindow}->get_size }; - my %texts; - require Gtk2::SourceView2; - my $lang_manager = Gtk2::SourceView2::LanguageManager->get_default; - gtkadd( - $d->{window}, - gtkpack_( - gtknew('VBox', spacing => 5), - 1, create_vpaned( - create_vpaned( - gtkpack_( - gtknew('VBox'), - 0, gtknew('Label', text_markup => qq($file:)), - 1, gtknew('ScrolledWindow', child => $texts{file} = Gtk2::SourceView2::View->new), - ), - gtkpack_( - gtknew('VBox'), - 0, gtknew('Label', text_markup => qq($rpmnew:)), - 1, gtknew('ScrolledWindow', child => $texts{rpmnew} = Gtk2::SourceView2::View->new), - ), - resize1 => 1, - ), - gtkpack_( - gtknew('VBox'), - 0, gtknew('Label', text => N("Changes:")), - 1, gtknew('ScrolledWindow', child => $texts{diff} = Gtk2::SourceView2::View->new), - ), - resize1 => 1, - ), - 0, Gtk2::HSeparator->new, - 0, gtknew('WrappedLabel', - # prevent bad sizing of Gtk2::WrappedLabel: - width => $inspect_wsize[0], - text => N("You can either remove the .%s file, use it as main file or do nothing. If unsure, keep the current file (\"%s\").", - $rpmfile, N("Remove .%s", $rpmfile)), - ), - 0, gtkpack__( - gtknew('HButtonBox'), - gtksignal_connect( - gtknew('Button', text => N("Remove .%s", $rpmfile)), - clicked => sub { $save_wsize->(); unlink $rpmnew; Gtk2->main_quit }, - ), - gtksignal_connect( - gtknew('Button', text => N("Use .%s as main file", $rpmfile)), - clicked => sub { $save_wsize->(); renamef($rpmnew, $file); Gtk2->main_quit }, - ), - gtksignal_connect( - gtknew('Button', text => N("Do nothing")), - clicked => sub { $save_wsize->(); Gtk2->main_quit }, - ), - ) - ) - ); - my %files = (file => $file, rpmnew => $rpmnew); - foreach (keys %files) { - gtktext_insert($texts{$_}, [ [ scalar(cat_($files{$_})), { 'font' => 'monospace' } ] ]); - my $lang = $lang_manager->guess_language($files{$_}); - $lang ||= $lang_manager->get_language('sh'); - my $buffer = $texts{$_}->get_buffer; - $buffer->set_language($lang) if $lang; - } - gtktext_insert($texts{diff}, [ [ join('', @diff), { 'font' => 'monospace' } ] ]); - my $buffer = $texts{diff}->get_buffer; - my $lang = $lang_manager->get_language('diff'); - $buffer->set_language($lang) if $lang; - $d->{rwindow}->set_default_size(@inspect_wsize); - $d->main; -} - -sub dialog_rpmnew { - my ($msg, %p2r) = @_; - @{$p2r{$_}} = grep { !$ignores_rpmnew{$_} } @{$p2r{$_}} foreach keys %p2r; - my $sum_rpmnew = sum(map { int @{$p2r{$_}} } keys %p2r); - $sum_rpmnew == 0 and return 1; - interactive_packtable( - N("Installation finished"), - $::main_window, - $msg, - [ map { my $pkg = $_; - map { - my $f = $_; - my $b; - [ gtkpack__( - gtknew('HBox'), - gtkset_markup( - gtkset_selectable(gtknew('Label'), 1), - qq($pkg:$f), - ) - ), - gtksignal_connect( - $b = gtknew('Button', text => N("Inspect...")), - clicked => sub { - inspect($f); - -r "$f.rpmnew" || -r "$f.rpmsave" or $b->set_sensitive(0); - }, - ) ]; - } @{$p2r{$pkg}}; - } keys %p2r ], - [ gtknew('Button', text => N("Ok"), - clicked => sub { Gtk2->main_quit }) ] - ); - return 0; -} - - -sub do_merge_if_needed() { - if ($rpmdragora_options{'merge-all-rpmnew'}) { - my %pkg2rpmnew; - my $wait = wait_msg(N("Please wait, searching...")); - print "Searching .rpmnew and .rpmsave files...\n"; - # costly: - open_rpm_db()->traverse(sub { - my $n = my_fullname($_[0]); - $pkg2rpmnew{$n} = [ grep { m|^/etc| && (-r "$_.rpmnew" || -r "$_.rpmsave") } map { chomp_($_) } $_[0]->conf_files ]; - }); - print "done.\n"; - undef $wait; - $typical_width = 330; - dialog_rpmnew('', %pkg2rpmnew) and print "Nothing to do.\n"; - myexit(0); - } -} - -1; diff --git a/AdminPanel/Rpmdragora/widgets.pm b/AdminPanel/Rpmdragora/widgets.pm deleted file mode 100644 index 84844069..00000000 --- a/AdminPanel/Rpmdragora/widgets.pm +++ /dev/null @@ -1,52 +0,0 @@ -# vim: set et ts=4 sw=4: -package Gtk2::Mdv::TextView; -#***************************************************************************** -# -# Copyright (c) 2002 Guillaume Cottenceau -# Copyright (c) 2002-2007 Thierry Vignaud -# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA -# Copyright (c) 2005-2007 Mandriva SA -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2, as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -#***************************************************************************** -# -# $Id: widgets.pm 233986 2008-02-06 14:14:06Z tv $ - -use strict; -use MDK::Common::Func 'any'; -use lib qw(/usr/lib/libDrakX); - -use Time::HiRes; -use feature 'state'; - - -sub new { - my ($_class) = @_; - my $w = gtknew('TextView', editable => 0); - state $time; - $w->signal_connect(size_allocate => sub { - my ($w, $requisition) = @_; - return if !ref($w->{anchors}); - return if Time::HiRes::clock_gettime() - $time < 0.200; - $time = Time::HiRes::clock_gettime(); - foreach my $anchor (@{$w->{anchors}}) { - $_->set_size_request($requisition->width-30, -1) foreach $anchor->get_widgets; - } - 1; - }); - $w; -} - -1; diff --git a/AdminPanel/Services/AdminService.pm b/AdminPanel/Services/AdminService.pm deleted file mode 100644 index 8b02227f..00000000 --- a/AdminPanel/Services/AdminService.pm +++ /dev/null @@ -1,559 +0,0 @@ -# vim: set et ts=4 sw=4: -#***************************************************************************** -# -# Copyright (c) 2013 Angelo Naselli -# from drakx services -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2, as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -#***************************************************************************** - -package AdminPanel::Services::AdminService; - -#-###################################################################################### -#- misc imports -#-###################################################################################### - -use strict; - -# TODO same translation atm -use lib qw(/usr/lib/libDrakX); -use common qw(N - N_ - cat_ - formatAlaTeX - translate - find); -use run_program; - -use Moose; - -use yui; -use AdminPanel::Shared; -use AdminPanel::Services::Utility qw( - services - xinetd_services - is_service_running - restart_or_start - stop - set_service - ); - -use File::Basename; - -extends qw( Module ); - -has '+icon' => ( - default => "/usr/share/mcc/themes/default/service-mdk.png", -); - -has '+name' => ( - default => N("AdminService"), -); - -has 'services' => ( - traits => ['Array'], - is => 'rw', - isa => 'ArrayRef[Str]', - default => sub { [] }, - init_arg => undef, - handles => { - all_services => 'elements', - add_service => 'push', - map_service => 'map', - service_count => 'count', - sorted_services => 'sort', - }, -); - -has 'xinetd_services' => ( - traits => ['Array'], - is => 'rw', - isa => 'ArrayRef[Str]', - default => sub { [] }, - init_arg => undef, - handles => { - all_xinetd_services => 'elements', - add_xinetd_service => 'push', - map_xinetd_service => 'map', - xinetd_service_count => 'count', - sorted_xinetd_services => 'sort', - }, -); - -has 'on_services' => ( - traits => ['Array'], - is => 'rw', - isa => 'ArrayRef[Str]', - default => sub { [] }, - init_arg => undef, - handles => { - all_on_services => 'elements', - add_on_service => 'push', - map_on_service => 'map', - on_service_count => 'count', - sorted_on_services => 'sort', - }, -); - - -has 'running_services' => ( - traits => ['Array'], - is => 'rw', - isa => 'ArrayRef[Str]', - default => sub { [] }, - init_arg => undef, - handles => { - all_running_services => 'elements', - add_running_service => 'push', - map_running_service => 'map', - running_service_count => 'count', - sorted_running_services => 'sort', - }, -); -=head1 VERSION - -Version 1.0.0 - -=cut - -our $VERSION = '1.0.0'; - - -sub description { - my %services = ( -acpid => N_("Listen and dispatch ACPI events from the kernel"), -alsa => N_("Launch the ALSA (Advanced Linux Sound Architecture) sound system"), -anacron => N_("Anacron is a periodic command scheduler."), -apmd => N_("apmd is used for monitoring battery status and logging it via syslog. -It can also be used for shutting down the machine when the battery is low."), -atd => N_("Runs commands scheduled by the at command at the time specified when -at was run, and runs batch commands when the load average is low enough."), -'avahi-deamon' => N_("Avahi is a ZeroConf daemon which implements an mDNS stack"), -chronyd => N_("An NTP client/server"), -cpufreq => N_("Set CPU frequency settings"), -crond => N_("cron is a standard UNIX program that runs user-specified programs -at periodic scheduled times. vixie cron adds a number of features to the basic -UNIX cron, including better security and more powerful configuration options."), -cups => N_("Common UNIX Printing System (CUPS) is an advanced printer spooling system"), -dm => N_("Launches the graphical display manager"), -fam => N_("FAM is a file monitoring daemon. It is used to get reports when files change. -It is used by GNOME and KDE"), -g15daemon => N_("G15Daemon allows users access to all extra keys by decoding them and -pushing them back into the kernel via the linux UINPUT driver. This driver must be loaded -before g15daemon can be used for keyboard access. The G15 LCD is also supported. By default, -with no other clients active, g15daemon will display a clock. Client applications and -scripts can access the LCD via a simple API."), -gpm => N_("GPM adds mouse support to text-based Linux applications such the -Midnight Commander. It also allows mouse-based console cut-and-paste operations, -and includes support for pop-up menus on the console."), -haldaemon => N_("HAL is a daemon that collects and maintains information about hardware"), -harddrake => N_("HardDrake runs a hardware probe, and optionally configures -new/changed hardware."), -httpd => N_("Apache is a World Wide Web server. It is used to serve HTML files and CGI."), -inet => N_("The internet superserver daemon (commonly called inetd) starts a -variety of other internet services as needed. It is responsible for starting -many services, including telnet, ftp, rsh, and rlogin. Disabling inetd disables -all of the services it is responsible for."), -ip6tables => N_("Automates a packet filtering firewall with ip6tables"), -iptables => N_("Automates a packet filtering firewall with iptables"), -irqbalance => N_("Evenly distributes IRQ load across multiple CPUs for enhanced performance"), -keytable => N_("This package loads the selected keyboard map as set in -/etc/sysconfig/keyboard. This can be selected using the kbdconfig utility. -You should leave this enabled for most machines."), -kheader => N_("Automatic regeneration of kernel header in /boot for -/usr/include/linux/{autoconf,version}.h"), -kudzu => N_("Automatic detection and configuration of hardware at boot."), -'laptop-mode' => N_("Tweaks system behavior to extend battery life"), -linuxconf => N_("Linuxconf will sometimes arrange to perform various tasks -at boot-time to maintain the system configuration."), -lpd => N_("lpd is the print daemon required for lpr to work properly. It is -basically a server that arbitrates print jobs to printer(s)."), -lvs => N_("Linux Virtual Server, used to build a high-performance and highly -available server."), -mandi => N_("Monitors the network (Interactive Firewall and wireless"), -mdadm => N_("Software RAID monitoring and management"), -messagebus => N_("DBUS is a daemon which broadcasts notifications of system events and other messages"), -msec => N_("Enables MSEC security policy on system startup"), -named => N_("named (BIND) is a Domain Name Server (DNS) that is used to resolve host names to IP addresses."), -netconsole => N_("Initializes network console logging"), -netfs => N_("Mounts and unmounts all Network File System (NFS), SMB (Lan -Manager/Windows), and NCP (NetWare) mount points."), -network => N_("Activates/Deactivates all network interfaces configured to start -at boot time."), -'network-auth' => N_("Requires network to be up if enabled"), -'network-up' => N_("Wait for the hotplugged network to be up"), -nfs => N_("NFS is a popular protocol for file sharing across TCP/IP networks. -This service provides NFS server functionality, which is configured via the -/etc/exports file."), -nfslock => N_("NFS is a popular protocol for file sharing across TCP/IP -networks. This service provides NFS file locking functionality."), -ntpd => N_("Synchronizes system time using the Network Time Protocol (NTP)"), -numlock => N_("Automatically switch on numlock key locker under console -and Xorg at boot."), -oki4daemon => N_("Support the OKI 4w and compatible winprinters."), -partmon => N_("Checks if a partition is close to full up"), -pcmcia => N_("PCMCIA support is usually to support things like ethernet and -modems in laptops. It will not get started unless configured so it is safe to have -it installed on machines that do not need it."), -portmap => N_("The portmapper manages RPC connections, which are used by -protocols such as NFS and NIS. The portmap server must be running on machines -which act as servers for protocols which make use of the RPC mechanism."), -portreserve => N_("Reserves some TCP ports"), -postfix => N_("Postfix is a Mail Transport Agent, which is the program that moves mail from one machine to another."), -random => N_("Saves and restores system entropy pool for higher quality random -number generation."), -rawdevices => N_("Assign raw devices to block devices (such as hard disk drive -partitions), for the use of applications such as Oracle or DVD players"), -resolvconf => N_("Nameserver information manager"), -routed => N_("The routed daemon allows for automatic IP router table updated via -the RIP protocol. While RIP is widely used on small networks, more complex -routing protocols are needed for complex networks."), -rstatd => N_("The rstat protocol allows users on a network to retrieve -performance metrics for any machine on that network."), -rsyslog => N_("Syslog is the facility by which many daemons use to log messages to various system log files. It is a good idea to always run rsyslog."), -rusersd => N_("The rusers protocol allows users on a network to identify who is -logged in on other responding machines."), -rwhod => N_("The rwho protocol lets remote users get a list of all of the users -logged into a machine running the rwho daemon (similar to finger)."), -saned => N_("SANE (Scanner Access Now Easy) enables to access scanners, video cameras, ..."), -shorewall => N_("Packet filtering firewall"), -smb => N_("The SMB/CIFS protocol enables to share access to files & printers and also integrates with a Windows Server domain"), -sound => N_("Launch the sound system on your machine"), -'speech-dispatcherd' => N_("layer for speech analysis"), -sshd => N_("Secure Shell is a network protocol that allows data to be exchanged over a secure channel between two computers"), -syslog => N_("Syslog is the facility by which many daemons use to log messages -to various system log files. It is a good idea to always run syslog."), -'udev-post' => N_("Moves the generated persistent udev rules to /etc/udev/rules.d"), -usb => N_("Load the drivers for your usb devices."), -vnStat => N_("A lightweight network traffic monitor"), -xfs => N_("Starts the X Font Server."), -xinetd => N_("Starts other deamons on demand."), - ); - my ($name) = @_; - my $s = $services{$name}; - if ($s) { - $s = translate($s); - } else { - my $file = "$::prefix/usr/lib/systemd/system/$name.service"; - if (-e $file) { - $s = cat_($file); - $s = $s =~ /^Description=(.*)/mg ? $1 : ''; - } else { - $file = find { -e $_ } map { "$::prefix$_/$name" } '/etc/rc.d/init.d', '/etc/init.d', '/etc/xinetd.d'; - $s = cat_($file); - $s =~ s/\\\s*\n#\s*//mg; - $s = - $s =~ /^#\s+(?:Short-)?[dD]escription:\s+(.*?)^(?:[^#]|# {0,2}\S)/sm ? $1 : - $s =~ /^#\s*(.*?)^[^#]/sm ? $1 : ''; - - $s =~ s/#\s*//mg; - } - } - $s =~ s/\n/ /gm; $s =~ s/\s+$//; - $s; -} - -sub BUILD { - my $self = shift; - - $self->loadServices(); -} - - -#============================================================= - -=head2 start - -=head3 INPUT - - $self: this object - -=head3 DESCRIPTION - - This method extends Module::start and is invoked to - start adminService - -=cut - -#============================================================= -sub start { - my $self = shift; - - $self->servicePanel(); -}; - - -#============================================================= - -=head2 loadServices - -=head3 INPUT - - $self: this object - -=head3 DESCRIPTION - - This methonds load service info into local attributes such - as xinetd_services, on_services and all the available, - services - -=cut - -#============================================================= -sub loadServices { - my $self = shift; - - my ($l, $on_services) = AdminPanel::Services::Utility::services(); - my @xinetd_services = map { $_->[0] } AdminPanel::Services::Utility::xinetd_services(); - - $self->xinetd_services(); - $self->xinetd_services(\@xinetd_services); - $self->services(\@$l); - $self->on_services(\@$on_services); - - $self->refreshRunningServices(); -} - -sub refreshRunningServices { - my $self = shift; - - my @running; - foreach ($self->all_services) { - - my $serviceName = $_; - push @running, $serviceName if is_service_running($serviceName); - } - $self->running_services(\@running); -} - -## serviceInfo sets widgets accordingly to selected service status -## param -## 'service' service name -## 'infoPanel' service information widget -sub serviceInfo { - my ($self, $service, $infoPanel) = @_; - - yui::YUI::ui()->blockEvents(); - ## infoPanel - $infoPanel->setValue(formatAlaTeX(description($service))); - yui::YUI::ui()->unblockEvents(); -} - -sub serviceStatus { - my ($self, $tbl, $item) = @_; - - my $started; - - if (member($item->label(), $self->all_xinetd_services)) { - $started = N("Start when requested"); - } - else { - $started = (member($item->label(), $self->all_running_services)? N("running") : N("stopped")); - } -# TODO add icon green/red led - my $cell = $tbl->toCBYTableItem($item)->cell(1); - if ($cell) { - $cell->setLabel($started); - $tbl->cellChanged($cell); - } -} - -## draw service panel and manage it -sub servicePanel { - my $self = shift; - - my $appTitle = yui::YUI::app()->applicationTitle(); - - ## set new title to get it in dialog - yui::YUI::app()->setApplicationTitle($self->name); - ## set icon if not already set by external launcher - yui::YUI::app()->setApplicationIcon($self->icon); - -# my ($l, $on_services) = services(); -# my @xinetd_services = map { $_->[0] } xinetd_services(); - - my $mageiaPlugin = "mga"; - my $factory = yui::YUI::widgetFactory; - my $mgaFactory = yui::YExternalWidgets::externalWidgetFactory($mageiaPlugin); - $mgaFactory = yui::YMGAWidgetFactory::getYMGAWidgetFactory($mgaFactory); - - my $dialog = $factory->createMainDialog; - my $vbox = $factory->createVBox( $dialog ); - my $frame = $factory->createFrame ($vbox, N("Services")); - - my $frmVbox = $factory->createVBox( $frame ); - my $hbox = $factory->createHBox( $frmVbox ); - - my $yTableHeader = new yui::YTableHeader(); - $yTableHeader->addColumn(N("Service"), $yui::YAlignBegin); - $yTableHeader->addColumn(N("Status"), $yui::YAlignCenter); - $yTableHeader->addColumn(N("On boot"), $yui::YAlignBegin); - - ## service list (serviceBox) - my $serviceTbl = $mgaFactory->createCBTable($hbox, $yTableHeader, $yui::YCBTableCheckBoxOnLastColumn); - my $itemCollection = new yui::YItemCollection; - foreach ($self->all_services) { - - my $serviceName = $_; - - my $item = new yui::YCBTableItem($serviceName); - my $started; - if (member($serviceName, $self->all_xinetd_services)) { - $started = N("Start when requested"); - } - else { - $started = (member($serviceName, $self->all_running_services)? N("running") : N("stopped")); - } - -# TODO add icon green/red led - my $cell = new yui::YTableCell($started); - $item->addCell($cell); - - $item->check(member($serviceName, $self->all_on_services)); - $item->setLabel($serviceName); - $itemCollection->push($item); - $item->DISOWN(); - } - $serviceTbl->addItems($itemCollection); - $serviceTbl->setImmediateMode(1); - $serviceTbl->setWeight(0, 50); - - ## info panel (infoPanel) - $frame = $factory->createFrame ($hbox, N("Information")); - $frame->setWeight(0, 30); - $frmVbox = $factory->createVBox( $frame ); - my $infoPanel = $factory->createRichText($frmVbox, "--------------"); #, 0, 0); - $infoPanel->setAutoScrollDown(); - - ### Service Start button ($startButton) - $hbox = $factory->createHBox( $frmVbox ); - my $startButton = $factory->createPushButton($hbox, N("Start")); - - ### Service Stop button ($stopButton) - my $stopButton = $factory->createPushButton($hbox, N("Stop")); - - # dialog buttons - $factory->createVSpacing($vbox, 1.0); - ## Window push buttons - $hbox = $factory->createHBox( $vbox ); - my $align = $factory->createLeft($hbox); - $hbox = $factory->createHBox($align); - my $aboutButton = $factory->createPushButton($hbox, N("About") ); - $align = $factory->createRight($hbox); - $hbox = $factory->createHBox($align); - my $closeButton = $factory->createPushButton($hbox, N("Close") ); - - #first item status - my $item = $serviceTbl->selectedItem(); - if ($item) { - $self->serviceInfo($item->label(), $infoPanel); - if (member($item->label(), $self->all_xinetd_services)) { - $stopButton->setDisabled(); - $startButton->setDisabled(); - } - else { - $stopButton->setEnabled(1); - $startButton->setEnabled(1); - } - } - - 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 selected - my $widget = $event->widget(); - my $wEvent = yui::toYWidgetEvent($event); - - if ($widget == $closeButton) { - last; - } - elsif ($widget == $aboutButton) { - my $license = translate($AdminPanel::Shared::License); - # TODO fix version value - AboutDialog({ name => N("AdminService"), - version => $self->VERSION, - copyright => N("Copyright (C) %s Mageia community", '2013-2014'), - license => $license, - comments => N("Service Manager is the Mageia service and daemon management tool \n(from the original idea of Mandriva draxservice)."), - website => 'http://www.mageia.org', - website_label => N("Mageia"), - authors => "Angelo Naselli \nMatteo Pasotti ", - translator_credits => - #-PO: put here name(s) and email(s) of translator(s) (eg: "John Smith ") - N("_: Translator(s) name(s) & email(s)\n")} - ); - } - elsif ($widget == $serviceTbl) { - - # service selection changed - $item = $serviceTbl->selectedItem(); - if ($item) { - $self->serviceInfo($item->label(), $infoPanel); - if (member($item->label(), $self->all_xinetd_services)) { - $stopButton->setDisabled(); - $startButton->setDisabled(); - } - else { - $stopButton->setEnabled(1); - $startButton->setEnabled(1); - } - } -# TODO fix libyui-mga-XXX item will always be changed after first one - if ($wEvent->reason() == $yui::YEvent::ValueChanged) { - $item = $serviceTbl->changedItem(); - if ($item) { - - set_service($item->label(), $item->checked()); - # we can push/pop service, but this (slower) should return real situation - $self->refreshRunningServices(); - } - } - } - elsif ($widget == $startButton) { - $item = $serviceTbl->selectedItem(); - if ($item) { - restart_or_start($item->label()); - # we can push/pop service, but this (slower) should return real situation - $self->refreshRunningServices(); - $self->serviceStatus($serviceTbl, $item); - } - } - elsif ($widget == $stopButton) { - $item = $serviceTbl->selectedItem(); - if ($item) { - stop($item->label()); - # we can push/pop service, but this (slower) should return real situation - $self->refreshRunningServices(); - $self->serviceStatus($serviceTbl, $item); - } - } - } - } - $dialog->destroy(); - - #restore old application title - yui::YUI::app()->setApplicationTitle($appTitle) if $appTitle; -} - -no Moose; -__PACKAGE__->meta->make_immutable; - -1; diff --git a/AdminPanel/Services/Utility.pm b/AdminPanel/Services/Utility.pm deleted file mode 100644 index baae3db0..00000000 --- a/AdminPanel/Services/Utility.pm +++ /dev/null @@ -1,446 +0,0 @@ -# vim: set et ts=4 sw=4: -#***************************************************************************** -# -# Copyright (c) 2013 Angelo Naselli -# from drakx services -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2, as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -#***************************************************************************** - -package AdminPanel::Services::Utility; - - - - -#-###################################################################################### -#- misc imports -#-###################################################################################### - -use strict; -use common; -use run_program; - -use File::Basename qw( basename ); -use base qw(Exporter); - -our @EXPORT = qw( - services - xinetd_services - is_service_running - restart_or_start - stop - start - set_service - ); - -sub description { - my %services = ( -acpid => N_("Listen and dispatch ACPI events from the kernel"), -alsa => N_("Launch the ALSA (Advanced Linux Sound Architecture) sound system"), -anacron => N_("Anacron is a periodic command scheduler."), -apmd => N_("apmd is used for monitoring battery status and logging it via syslog. -It can also be used for shutting down the machine when the battery is low."), -atd => N_("Runs commands scheduled by the at command at the time specified when -at was run, and runs batch commands when the load average is low enough."), -'avahi-deamon' => N_("Avahi is a ZeroConf daemon which implements an mDNS stack"), -chronyd => N_("An NTP client/server"), -cpufreq => N_("Set CPU frequency settings"), -crond => N_("cron is a standard UNIX program that runs user-specified programs -at periodic scheduled times. vixie cron adds a number of features to the basic -UNIX cron, including better security and more powerful configuration options."), -cups => N_("Common UNIX Printing System (CUPS) is an advanced printer spooling system"), -dm => N_("Launches the graphical display manager"), -fam => N_("FAM is a file monitoring daemon. It is used to get reports when files change. -It is used by GNOME and KDE"), -g15daemon => N_("G15Daemon allows users access to all extra keys by decoding them and -pushing them back into the kernel via the linux UINPUT driver. This driver must be loaded -before g15daemon can be used for keyboard access. The G15 LCD is also supported. By default, -with no other clients active, g15daemon will display a clock. Client applications and -scripts can access the LCD via a simple API."), -gpm => N_("GPM adds mouse support to text-based Linux applications such the -Midnight Commander. It also allows mouse-based console cut-and-paste operations, -and includes support for pop-up menus on the console."), -haldaemon => N_("HAL is a daemon that collects and maintains information about hardware"), -harddrake => N_("HardDrake runs a hardware probe, and optionally configures -new/changed hardware."), -httpd => N_("Apache is a World Wide Web server. It is used to serve HTML files and CGI."), -inet => N_("The internet superserver daemon (commonly called inetd) starts a -variety of other internet services as needed. It is responsible for starting -many services, including telnet, ftp, rsh, and rlogin. Disabling inetd disables -all of the services it is responsible for."), -ip6tables => N_("Automates a packet filtering firewall with ip6tables"), -iptables => N_("Automates a packet filtering firewall with iptables"), -irqbalance => N_("Evenly distributes IRQ load across multiple CPUs for enhanced performance"), -keytable => N_("This package loads the selected keyboard map as set in -/etc/sysconfig/keyboard. This can be selected using the kbdconfig utility. -You should leave this enabled for most machines."), -kheader => N_("Automatic regeneration of kernel header in /boot for -/usr/include/linux/{autoconf,version}.h"), -kudzu => N_("Automatic detection and configuration of hardware at boot."), -'laptop-mode' => N_("Tweaks system behavior to extend battery life"), -linuxconf => N_("Linuxconf will sometimes arrange to perform various tasks -at boot-time to maintain the system configuration."), -lpd => N_("lpd is the print daemon required for lpr to work properly. It is -basically a server that arbitrates print jobs to printer(s)."), -lvs => N_("Linux Virtual Server, used to build a high-performance and highly -available server."), -mandi => N_("Monitors the network (Interactive Firewall and wireless"), -mdadm => N_("Software RAID monitoring and management"), -messagebus => N_("DBUS is a daemon which broadcasts notifications of system events and other messages"), -msec => N_("Enables MSEC security policy on system startup"), -named => N_("named (BIND) is a Domain Name Server (DNS) that is used to resolve host names to IP addresses."), -netconsole => N_("Initializes network console logging"), -netfs => N_("Mounts and unmounts all Network File System (NFS), SMB (Lan -Manager/Windows), and NCP (NetWare) mount points."), -network => N_("Activates/Deactivates all network interfaces configured to start -at boot time."), -'network-auth' => N_("Requires network to be up if enabled"), -'network-up' => N_("Wait for the hotplugged network to be up"), -nfs => N_("NFS is a popular protocol for file sharing across TCP/IP networks. -This service provides NFS server functionality, which is configured via the -/etc/exports file."), -nfslock => N_("NFS is a popular protocol for file sharing across TCP/IP -networks. This service provides NFS file locking functionality."), -ntpd => N_("Synchronizes system time using the Network Time Protocol (NTP)"), -numlock => N_("Automatically switch on numlock key locker under console -and Xorg at boot."), -oki4daemon => N_("Support the OKI 4w and compatible winprinters."), -partmon => N_("Checks if a partition is close to full up"), -pcmcia => N_("PCMCIA support is usually to support things like ethernet and -modems in laptops. It will not get started unless configured so it is safe to have -it installed on machines that do not need it."), -portmap => N_("The portmapper manages RPC connections, which are used by -protocols such as NFS and NIS. The portmap server must be running on machines -which act as servers for protocols which make use of the RPC mechanism."), -portreserve => N_("Reserves some TCP ports"), -postfix => N_("Postfix is a Mail Transport Agent, which is the program that moves mail from one machine to another."), -random => N_("Saves and restores system entropy pool for higher quality random -number generation."), -rawdevices => N_("Assign raw devices to block devices (such as hard disk drive -partitions), for the use of applications such as Oracle or DVD players"), -resolvconf => N_("Nameserver information manager"), -routed => N_("The routed daemon allows for automatic IP router table updated via -the RIP protocol. While RIP is widely used on small networks, more complex -routing protocols are needed for complex networks."), -rstatd => N_("The rstat protocol allows users on a network to retrieve -performance metrics for any machine on that network."), -rsyslog => N_("Syslog is the facility by which many daemons use to log messages to various system log files. It is a good idea to always run rsyslog."), -rusersd => N_("The rusers protocol allows users on a network to identify who is -logged in on other responding machines."), -rwhod => N_("The rwho protocol lets remote users get a list of all of the users -logged into a machine running the rwho daemon (similar to finger)."), -saned => N_("SANE (Scanner Access Now Easy) enables to access scanners, video cameras, ..."), -shorewall => N_("Packet filtering firewall"), -smb => N_("The SMB/CIFS protocol enables to share access to files & printers and also integrates with a Windows Server domain"), -sound => N_("Launch the sound system on your machine"), -'speech-dispatcherd' => N_("layer for speech analysis"), -sshd => N_("Secure Shell is a network protocol that allows data to be exchanged over a secure channel between two computers"), -syslog => N_("Syslog is the facility by which many daemons use to log messages -to various system log files. It is a good idea to always run syslog."), -'udev-post' => N_("Moves the generated persistent udev rules to /etc/udev/rules.d"), -usb => N_("Load the drivers for your usb devices."), -vnStat => N_("A lightweight network traffic monitor"), -xfs => N_("Starts the X Font Server."), -xinetd => N_("Starts other deamons on demand."), - ); - my ($name) = @_; - my $s = $services{$name}; - if ($s) { - $s = translate($s); - } else { - my $file = "$::prefix/usr/lib/systemd/system/$name.service"; - if (-e $file) { - $s = cat_($file); - $s = $s =~ /^Description=(.*)/mg ? $1 : ''; - } else { - $file = find { -e $_ } map { "$::prefix$_/$name" } '/etc/rc.d/init.d', '/etc/init.d', '/etc/xinetd.d'; - $s = cat_($file); - $s =~ s/\\\s*\n#\s*//mg; - $s = - $s =~ /^#\s+(?:Short-)?[dD]escription:\s+(.*?)^(?:[^#]|# {0,2}\S)/sm ? $1 : - $s =~ /^#\s*(.*?)^[^#]/sm ? $1 : ''; - - $s =~ s/#\s*//mg; - } - } - $s =~ s/\n/ /gm; $s =~ s/\s+$//; - $s; -} - - -sub set_service { - my ($service, $enable) = @_; - - my @xinetd_services = map { $_->[0] } xinetd_services(); - - if (member($service, @xinetd_services)) { - run_program::rooted($::prefix, "chkconfig", $enable ? "--add" : "--del", $service); - } elsif (running_systemd() || has_systemd()) { - # systemctl rejects any symlinked units. You have to enabled the real file - if (-l "/lib/systemd/system/$service.service") { - my $name = readlink("/lib/systemd/system/$service.service"); - $service = File::Basename::basename($name); - } else { - $service = $service . ".service"; - } - run_program::rooted($::prefix, "/bin/systemctl", $enable ? "enable" : "disable", $service); - } else { - my $script = "/etc/rc.d/init.d/$service"; - run_program::rooted($::prefix, "chkconfig", $enable ? "--add" : "--del", $service); - #- FIXME: handle services with no chkconfig line and with no Default-Start levels in LSB header - if ($enable && cat_("$::prefix$script") =~ /^#\s+chkconfig:\s+-/m) { - run_program::rooted($::prefix, "chkconfig", "--level", "35", $service, "on"); - } - } -} - -sub _run_action { - my ($service, $action) = @_; - if (running_systemd()) { - run_program::rooted($::prefix, '/bin/systemctl', '--no-block', $action, "$service.service"); - } else { - run_program::rooted($::prefix, "/etc/rc.d/init.d/$service", $action); - } -} - -sub running_systemd() { - run_program::rooted($::prefix, '/bin/mountpoint', '-q', '/sys/fs/cgroup/systemd'); -} - -sub has_systemd() { - run_program::rooted($::prefix, '/bin/rpm', '-q', 'systemd'); -} - -sub xinetd_services() { - local $ENV{LANGUAGE} = 'C'; - my @xinetd_services; - foreach (run_program::rooted_get_stdout($::prefix, '/sbin/chkconfig', '--list', '--type', 'xinetd')) { - if (my ($xinetd_name, $on_off) = m!^\t(\S+):\s*(on|off)!) { - push @xinetd_services, [ $xinetd_name, $on_off eq 'on' ]; - } - } - @xinetd_services; -} - -sub _systemd_services() { - local $ENV{LANGUAGE} = 'C'; - my @services; - my %loaded; - # Running system using systemd - log::explanations("Detected systemd running. Using systemctl introspection."); - foreach (run_program::rooted_get_stdout($::prefix, '/bin/systemctl', '--full', '--all', 'list-units')) { - if (my ($name) = m!^(\S+)\.service\s+loaded!) { - # We only look at non-template, non-linked service files in /lib - # We also check for any non-masked sysvinit files as these are - # also handled by systemd - if ($name !~ /.*\@$/g && (-e "$::prefix/lib/systemd/system/$name.service" or -e "$::prefix/etc/rc.d/init.d/$name") && ! -l "$::prefix/lib/systemd/system/$name.service") { - push @services, [ $name, !!run_program::rooted($::prefix, '/bin/systemctl', '--quiet', 'is-enabled', "$name.service") ]; - $loaded{$name} = 1; - } - } - } - # list-units will not list disabled units that can be enabled - foreach (run_program::rooted_get_stdout($::prefix, '/bin/systemctl', '--full', 'list-unit-files')) { - if (my ($name) = m!^(\S+)\.service\s+disabled!) { - # We only look at non-template, non-linked service files in /lib - # We also check for any non-masked sysvinit files as these are - # also handled by systemd - if (!exists $loaded{$name} && $name !~ /.*\@$/g && (-e "$::prefix/lib/systemd/system/$name.service" or -e "$::prefix/etc/rc.d/init.d/$name") && ! -l "$::prefix/lib/systemd/system/$name.service") { - # Limit ourselves to "standard" targets which can be enabled - my $wantedby = cat_("$::prefix/lib/systemd/system/$name.service") =~ /^WantedBy=(graphical|multi-user).target$/sm ? $1 : ''; - if ($wantedby) { - push @services, [ $name, 0 ]; - } - } - } - } - - @services; -} - -sub _legacy_services() { - local $ENV{LANGUAGE} = 'C'; - my @services; - my $has_systemd = has_systemd(); - if ($has_systemd) { - # The system not using systemd but will be at next boot. This is - # is typically the case in the installer. In this mode we must read - # as much as is practicable from the native systemd unit files and - # combine that with information from chkconfig regarding legacy sysvinit - # scripts (which systemd will parse and include when running) - log::explanations("Detected systemd installed. Using fake service+chkconfig introspection."); - foreach (glob_("$::prefix/lib/systemd/system/*.service")) { - my ($name) = m!([^/]*).service$!; - - # We only look at non-template, non-symlinked service files - if (!(/.*\@\.service$/g) && ! -l $_) { - # Limit ourselves to "standard" targets - my $wantedby = cat_($_) =~ /^WantedBy=(graphical|multi-user).target$/sm ? $1 : ''; - if ($wantedby) { - # Exclude if enabled statically - # Note DO NOT use -e when testing for files that could - # be symbolic links as this will fail under a chroot - # setup where -e will fail if the symlink target does - # exist which is typically the case when viewed outside - # of the chroot. - if (!-l "$::prefix/lib/systemd/system/$wantedby.target.wants/$name.service") { - push @services, [ $name, !!-l "$::prefix/etc/systemd/system/$wantedby.target.wants/$name.service" ]; - } - } - } - } - } else { - log::explanations("Could not detect systemd. Using chkconfig service introspection."); - } - - # Regardless of whether we expect to use systemd on next boot, we still - # need to instrospect information about non-systemd native services. - my $runlevel; - my $on_off; - if (!$::isInstall) { - $runlevel = (split " ", `/sbin/runlevel`)[1]; - } - foreach (run_program::rooted_get_stdout($::prefix, '/sbin/chkconfig', '--list', '--type', 'sysv')) { - if (my ($name, $l) = m!^(\S+)\s+(0:(on|off).*)!) { - # If we expect to use systemd (i.e. installer) only show those - # sysvinit scripts which are not masked by a native systemd unit. - my $has_systemd_unit = systemd_unit_exists($name); - if (!$has_systemd || !$has_systemd_unit) { - if ($::isInstall) { - $on_off = $l =~ /\d+:on/g; - } else { - $on_off = $l =~ /$runlevel:on/g; - } - push @services, [ $name, $on_off ]; - } - } - } - @services; -} - -#- returns: -#--- the listref of installed services -#--- the listref of "on" services -sub services() { - my @services; - if (running_systemd()) { - @services = _systemd_services(); - } else { - @services = _legacy_services(); - } - - my @l = xinetd_services(); - push @l, @services; - @l = sort { $a->[0] cmp $b->[0] } @l; - [ map { $_->[0] } @l ], [ map { $_->[0] } grep { $_->[1] } @l ]; -} - - - -sub systemd_unit_exists { - my ($name) = @_; - # we test with -l as symlinks are not valid when the system is chrooted: - -e "$::prefix/lib/systemd/system/$name.service" or -l "$::prefix/lib/systemd/system/$name.service"; -} - -sub service_exists { - my ($service) = @_; - -x "$::prefix/etc/rc.d/init.d/$service" or systemd_unit_exists($service); -} - -sub restart ($) { - my ($service) = @_; - # Exit silently if the service is not installed - service_exists($service) or return 1; - _run_action($service, "restart"); -} - -sub restart_or_start ($) { - my ($service) = @_; - # Exit silently if the service is not installed - service_exists($service) or return 1; - _run_action($service, is_service_running($service) ? "restart" : "start"); -} - -sub start ($) { - my ($service) = @_; - # Exit silently if the service is not installed - service_exists($service) or return 1; - _run_action($service, "start"); -} - -sub start_not_running_service ($) { - my ($service) = @_; - # Exit silently if the service is not installed - service_exists($service) or return 1; - is_service_running($service) || _run_action($service, "start"); -} - -sub stop ($) { - my ($service) = @_; - # Exit silently if the service is not installed - service_exists($service) or return 1; - _run_action($service, "stop"); -} - -sub is_service_running ($) { - my ($service) = @_; - # Exit silently if the service is not installed - service_exists($service) or return 1; - if (running_systemd()) { - run_program::rooted($::prefix, '/bin/systemctl', '--quiet', 'is-active', "$service.service"); - } else { - run_program::rooted($::prefix, '/sbin/service', $service, 'status'); - } -} - -sub starts_on_boot { - my ($service) = @_; - my (undef, $on_services) = services(); - member($service, @$on_services); -} - -sub start_service_on_boot ($) { - my ($service) = @_; - set_service($service, 1); -} - -sub do_not_start_service_on_boot ($) { - my ($service) = @_; - set_service($service, 0); -} - -sub enable { - my ($service, $o_dont_apply) = @_; - start_service_on_boot($service); - restart_or_start($service) unless $o_dont_apply; -} - -sub disable { - my ($service, $o_dont_apply) = @_; - do_not_start_service_on_boot($service); - stop($service) unless $o_dont_apply; -} - -sub set_status { - my ($service, $enable, $o_dont_apply) = @_; - if ($enable) { - enable($service, $o_dont_apply); - } else { - disable($service, $o_dont_apply); - } -} - -1; diff --git a/AdminPanel/Services/adminService.conf b/AdminPanel/Services/adminService.conf deleted file mode 100644 index 6c40b101..00000000 --- a/AdminPanel/Services/adminService.conf +++ /dev/null @@ -1,10 +0,0 @@ - - - - System - /usr/share/icons/system_section.png - - AdminPanel::Services::AdminService - - - diff --git a/AdminPanel/Shared.pm b/AdminPanel/Shared.pm deleted file mode 100644 index 583b214c..00000000 --- a/AdminPanel/Shared.pm +++ /dev/null @@ -1,712 +0,0 @@ -#!/usr/bin/perl -# vim: set et ts=4 sw=4: -# Copyright 2012-2013 Angelo Naselli -# -# This file is part of AdminPanel -# -# AdminPanel is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# AdminPanel is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with AdminPanel. If not, see . - -package AdminPanel::Shared; - -=head1 NAME - -AdminPanel::Shared - AdminPanel::Shared contains all the shared routines - needed by AdminPanel and modules - -=head1 SYNOPSIS - - - -=head1 DESCRIPTION - -This module collects all the routines shared between AdminPanel and its modules. - -=head1 EXPORT - - warningMsgBox - msgBox - infoMsgBox - ask_YesOrNo - ask_OkCancel - AboutDialog - trim - - -=head1 SUPPORT - -You can find documentation for this module with the perldoc command: - - perldoc AdminPanel::Shared - -=head1 AUTHOR - -Angelo Naselli - -=head1 COPYRIGHT and LICENSE - -Copyright (C) 2013, Angelo Naselli. - -This file is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. - -This file is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this file. If not, see . - -=head1 FUNCTIONS - -=cut - -use strict; -use warnings; -use diagnostics; - -use lib qw(/usr/lib/libDrakX); -use common qw(N - N_); -use yui; -use base qw(Exporter); - -# TODO move GUI dialogs to Shared::GUI -our @EXPORT = qw( - warningMsgBox - msgBox - infoMsgBox - ask_YesOrNo - ask_OkCancel - ask_fromList - AboutDialog - trim - member -); - - -=head1 VERSION - -Version 0.01 - -=cut - -our $VERSION = '0.01'; - -our $License = N_("This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -"); - - -#============================================================= - -=head2 warningMsgBox - -=head3 INPUT - - $st: string to be swhon into the dialog - -=head3 DESCRIPTION - -This function creates an Warning dialog and show the message -passed as input. - -=cut - -#============================================================= - -sub warningMsgBox { - my ($st) = @_; - my $factory = yui::YUI::widgetFactory; - my $msg_box = $factory->createPopupDialog($yui::YDialogWarnColor); - my $layout = $factory->createVBox($msg_box); - my $align = $factory->createAlignment($layout, 3, 0); - $factory->createLabel( $align, $st, 1, 0); - $align = $factory->createAlignment($layout, 3, 0); - $factory->createPushButton($align, N("Ok")); - $msg_box->waitForEvent(); - - destroy $msg_box; -} - -#============================================================= - -=head2 infoMsgBox - -=head3 INPUT - - $st: string to be swhon into the dialog - -=head3 DESCRIPTION - -This function creates an Info dialog and show the message -passed as input. - -=cut - -#============================================================= - -sub infoMsgBox { - my ($st) = @_; - my $factory = yui::YUI::widgetFactory; - my $msg_box = $factory->createPopupDialog($yui::YDialogInfoColor); - my $layout = $factory->createVBox($msg_box); - my $align = $factory->createAlignment($layout, 3, 0); - $factory->createLabel( $align, $st, 1, 0); - $align = $factory->createAlignment($layout, 3, 0); - $factory->createPushButton($align, N("Ok")); - $msg_box->waitForEvent(); - - destroy $msg_box; -} - -#============================================================= - -=head2 msgBox - -=head3 INPUT - - $st: string to be swhon into the dialog - -=head3 DESCRIPTION - -This function creates a dialog and show the message passed as input. - -=cut - -#============================================================= - -sub msgBox { - my ($st) = @_; - my $factory = yui::YUI::widgetFactory; - my $msg_box = $factory->createPopupDialog($yui::YDialogNormalColor); - my $layout = $factory->createVBox($msg_box); - my $align = $factory->createAlignment($layout, 3, 0); - $factory->createLabel( $align, $st, 1, 0); - $align = $factory->createAlignment($layout, 3, 0); - $factory->createPushButton($align, N("Ok")); - $msg_box->waitForEvent(); - - destroy $msg_box; -} - -#============================================================= - -=head2 ask_OkCancel - -=head3 INPUT - - $title: Title shown as heading - $text: text to be shown into the dialog - -=head3 OUTPUT - - 0: Cancel button has been pressed - 1: Ok button has been pressed - -=head3 DESCRIPTION - -This function create an OK-Cancel dialog with a 'title' and a -'text' passed as parameters. - -=cut - -#============================================================= - -sub ask_OkCancel { - my ($title, $text) = @_; - my $retVal = 0; - my $factory = yui::YUI::widgetFactory; - - my $msg_box = $factory->createPopupDialog($yui::YDialogNormalColor); - my $layout = $factory->createVBox($msg_box); - - my $align = $factory->createAlignment($layout, 3, 0); - ## title with headings true - $factory->createLabel( $align, $title, 1, 0); - $align = $factory->createLeft($layout); - $factory->createLabel( $align, $text, 0, 0); - - $align = $factory->createRight($layout); - my $hbox = $factory->createHBox($align); - my $okButton = $factory->createPushButton($hbox, N("Ok")); - my $cancelButton = $factory->createPushButton($hbox, N("Cancel")); - - my $event = $msg_box->waitForEvent(); - - my $eventType = $event->eventType(); - - if ($eventType == $yui::YEvent::WidgetEvent) { - # widget selected - my $widget = $event->widget(); - $retVal = ($widget == $okButton) ? 1 : 0; - } - - destroy $msg_box; - - return $retVal; -} - -#============================================================= - -=head2 ask_YesOrNo - -=head3 INPUT - - $title: Title shown as heading - $text: question text to be shown into the dialog - -=head3 OUTPUT - - 0: "No" button has been pressed - 1: "Yes" button has been pressed - -=head3 DESCRIPTION - -This function create a Yes-No dialog with a 'title' and a -question 'text' passed as parameters. - -=cut - -#============================================================= - -sub ask_YesOrNo { - my ($title, $text) = @_; - my $retVal = 0; - my $factory = yui::YUI::widgetFactory; - - my $msg_box = $factory->createPopupDialog($yui::YDialogNormalColor); - my $layout = $factory->createVBox($msg_box); - - my $align = $factory->createAlignment($layout, 3, 0); - ## title with headings true - $factory->createLabel( $align, $title, 1, 0); - $align = $factory->createLeft($layout); - $factory->createLabel( $align, $text, 0, 0); - - $align = $factory->createRight($layout); - my $hbox = $factory->createHBox($align); - my $yesButton = $factory->createPushButton($hbox, N("Yes")); - my $noButton = $factory->createPushButton($hbox, N("No")); - - my $event = $msg_box->waitForEvent(); - - my $eventType = $event->eventType(); - - if ($eventType == $yui::YEvent::WidgetEvent) { - # widget selected - my $widget = $event->widget(); - $retVal = ($widget == $yesButton) ? 1 : 0; - } - - destroy $msg_box; - - return $retVal; -} - - -#============================================================= - -=head2 ask_fromList - -=head3 INPUT - - $title: dialog title - $text: combobox heading - $list: item list - -=head3 OUTPUT - - undef: if Cancel button has been pressed - selected item: if Ok button has been pressed - -=head3 DESCRIPTION - -This function create a dialog with a combobox in which to -choose an item from a given list. - -=cut - -#============================================================= - -sub ask_fromList { - my ($title, $text, $list) = @_; - - die "Title is mandatory" if (! $title); - die "Heading is mandatory" if (! $text); - die "List is mandatory" if (! $list ); - die "At least one element is mandatory into list" if (scalar(@$list) < 1); - - my $choice = undef; - my $factory = yui::YUI::widgetFactory; - - ## push application title - my $appTitle = yui::YUI::app()->applicationTitle(); - ## set new title to get it in dialog - yui::YUI::app()->setApplicationTitle($title); - - my $dlg = $factory->createPopupDialog($yui::YDialogNormalColor); - my $layout = $factory->createVBox($dlg); - - my $combo = $factory->createComboBox($layout, $text, 0); - my $itemColl = new yui::YItemCollection; - foreach (@$list) { - my $item = new yui::YItem ($_, 0); - $itemColl->push($item); - $item->DISOWN(); - } - $combo->addItems($itemColl); - - my $align = $factory->createRight($layout); - my $hbox = $factory->createHBox($align); - my $okButton = $factory->createPushButton($hbox, N("Ok")); - my $cancelButton = $factory->createPushButton($hbox, N("Cancel")); - - while (1) { - my $event = $dlg->waitForEvent(); - - my $eventType = $event->eventType(); - #event type checking - if ($eventType == $yui::YEvent::CancelEvent) { - last; - } - elsif ($eventType == $yui::YEvent::WidgetEvent) { - # widget selected - my $widget = $event->widget(); - - if ($widget == $cancelButton) { - last; - } - elsif ($widget == $okButton) { - my $item = $combo->selectedItem(); - $choice = $item->label() if ($item); - last; - } - } - } - - destroy $dlg; - - #restore old application title - yui::YUI::app()->setApplicationTitle($appTitle); - - return $choice; -} - - -#============================================================= - -=head2 AboutDialog - -=head3 INPUT - - $opts: optional options needed to get info for dialog. - name => Application Name, - version => Application Version, - copyright => Copyright ususally like "Copyright (C) copyright-holder Year", - license => License text, - comments => A comment related to application to be shown, - website => Web site URL, - website_label => Label to hide previous link, - authors => Application authors, - translator_credits => Application translators - documenters => Application documenters - artists => Graphic applicaton designers - logo => picture path to be shown as application logo - -=head3 OUTPUT - - Output_Parameter: out_par_description - -=head3 DESCRIPTION - -About dialog implementation, this dialog can be used by -modules, to show authors, license, credits, etc. - -=cut - -#============================================================= - -sub AboutDialog { - my ($opts) = @_; - - # Credits dialog - sub Credits { - my ($opts) = @_; - - my $factory = yui::YUI::widgetFactory; - my $optional = yui::YUI::optionalWidgetFactory; - - my $creditsdlg = $factory->createPopupDialog(); - my $layout = $factory->createVBox($creditsdlg); - - # header - $factory->createHBox($layout); - my $hbox = $factory->createHBox($layout); - my $align = $factory->createHVCenter($hbox); - $hbox = $factory->createHBox($align); - $factory->createHeading($hbox, N("Credits")); - - # Credits tab widget - if ($optional->hasDumbTab()) { - $hbox = $factory->createHBox($layout); - $align = $factory->createAlignment($hbox, 3, 0); - my $dumptab = $optional->createDumbTab($align); - my $item = new yui::YItem(N("Written by")); - $item->setSelected(); - $dumptab->addItem( $item ); - $item->DISOWN(); - if (exists $opts->{documenters}) { - $item = new yui::YItem(N("Documented by")); - $dumptab->addItem( $item ); - $item->DISOWN(); - } - if (exists $opts->{translator_credits}) { - $item = new yui::YItem(N("Translated by")); - $dumptab->addItem( $item ); - $item->DISOWN(); - } - if (exists $opts->{artists}) { - $item = new yui::YItem(N("Artwork by")); - $dumptab->addItem( $item ); - $item->DISOWN(); - } - my $vbox = $factory->createVBox($dumptab); - $align = $factory->createLeft($vbox); - $factory->createVSpacing($vbox, 1.0); - my $label = $factory->createLabel( $align, "***", 0); - $factory->createVSpacing($vbox, 1.0); - - # start value for first Item - $label->setValue($opts->{authors}) if exists $opts->{authors}; - - # Close button - $align = $factory->createRight($layout); - my $closeButton = $factory->createPushButton($align, N("Close")); - - # manage Credits dialog events - while(1) { - my $event = $creditsdlg->waitForEvent(); - my $eventType = $event->eventType(); - - #event type checking - if ($eventType == $yui::YEvent::CancelEvent) { - last; - } - elsif ($eventType == $yui::YEvent::WidgetEvent) { - # widget selected - my $widget = $event->widget(); - - if ($widget == $closeButton) { - last; - } - } - elsif ($event->item() ) { - # $eventType MenuEvent!!! - my $itemLabel = $event->item()->label(); - $itemLabel =~ s/&//; #remove shortcut from label - if ($itemLabel eq N("Written by")) { - $label->setValue($opts->{authors}) if exists $opts->{authors}; - } - elsif ($itemLabel eq N("Documented by")) { - $label->setValue($opts->{documenters}) if exists $opts->{documenters}; - } - elsif ($itemLabel eq N("Translated by")) { - $label->setValue($opts->{translator_credits}) if exists $opts->{translator_credits}; - } - elsif ($itemLabel eq N("Artwork by")) { - $label->setValue($opts->{artists}) if exists $opts->{artists}; - } - } - } - } - else { - print "No tab widgets available!\n"; - } - destroy $creditsdlg; - } - - # License dialog - sub License { - my ($license) = @_; - - my $factory = yui::YUI::widgetFactory; - my $licensedlg = $factory->createPopupDialog(); - my $layout = $factory->createVBox($licensedlg); - - # header - $factory->createHBox($layout); - my $hbox = $factory->createHBox($layout); - my $align = $factory->createHVCenter($hbox); - $hbox = $factory->createHBox($align); - $factory->createHeading($hbox, N("License")); - - # license - $hbox = $factory->createHBox($layout); - $align = $factory->createAlignment($hbox, 3, 0); - $factory->createLabel( $align, $license); - - $align = $factory->createRight($layout); - my $closeButton = $factory->createPushButton($align, N("Close")); - - $licensedlg->waitForEvent(); - - destroy $licensedlg; - } - - my $website = "http://www.mageia.org"; - my $website_label = "Mageia"; - my $factory = yui::YUI::widgetFactory; - my $aboutdlg = $factory->createPopupDialog(); - my $layout = $factory->createVBox($aboutdlg); - - # header - $factory->createHBox($layout); - my $hbox_iconbar = $factory->createHBox($layout); - my $align = $factory->createHVCenter($hbox_iconbar); - $hbox_iconbar = $factory->createHBox($align); - $factory->createImage($hbox_iconbar, $opts->{logo}) if exists $opts->{logo}; - my $header = $opts->{name} . " " . $opts->{version}; - $factory->createHeading($hbox_iconbar, $header); - - # comments - my $hbox = $factory->createHBox($layout); - $align = $factory->createAlignment($hbox, 3, 0); - $factory->createLabel( $align, $opts->{comments}, 0, 0) if exists $opts->{comments}; - - # copyright - $hbox = $factory->createHBox($layout); - $align = $factory->createHVCenter($hbox); - $factory->createLabel( $align, $opts->{copyright}, 0, 0) if exists $opts->{copyright}; - - # website / website_label - $hbox = $factory->createHBox($layout); - $align = $factory->createHVCenter($hbox); - $website = $opts->{website} if exists $opts->{website}; - $website_label = $opts->{website_label} if exists $opts->{website_label}; - my $webref = "". $website_label .""; - $factory->createRichText( $align, $webref); - - # Credits, License and Close buttons - $hbox = $factory->createHBox($layout); - $align = $factory->createLeft($hbox); - my $hbox1 = $factory->createHBox($align); - my $creditsButton = $factory->createPushButton($hbox1, N("Credits")); - my $licenseButton = $factory->createPushButton($hbox1, N("License")); - $factory->createHSpacing($hbox, 2.0); - $align = $factory->createRight($hbox); - my $closeButton = $factory->createPushButton($align, N("Close")); - - # AboutDialog Events - while(1) { - my $event = $aboutdlg->waitForEvent(); - my $eventType = $event->eventType(); - - #event type checking - if ($eventType == $yui::YEvent::CancelEvent) { - last; - } - elsif ($eventType == $yui::YEvent::WidgetEvent) { - # widget selected - my $widget = $event->widget(); - - if($widget == $licenseButton) { - License($opts->{license}) if exists $opts->{license}; - } - elsif ($widget == $creditsButton) { - Credits($opts); - } - elsif ($widget == $closeButton) { - last; - } - } - elsif ($eventType == $yui::YEvent::MenuEvent) { - my $menuEvent = yui::YMGAWidgetFactory::getYMenuEvent($event); - #TODO check why is not working - run_program::raw({ detach => 1 }, 'www-browser', $menuEvent->id()); - } - } - - destroy $aboutdlg; -} - -#============================================================= - -=head2 trim - -=head3 INPUT - - $st: String to be trimmed - -=head3 OUTPUT - - $st: trimmed string - -=head3 DESCRIPTION - -This function trim the given string. - -=cut - -#============================================================= - -sub trim { - my ($st) = shift; - $st =~s /^\s+//g; - $st =~s /\s+$//g; - return $st; -} - -#============================================================= - -=head2 member - -=head3 INPUT - - $e: Array element to be found into array - @_: any array - -=head3 OUTPUT - - 1 or 0: if $e is a member of the given array - -=head3 DESCRIPTION - -This function look for an element into an array - -=cut - -#============================================================= -sub member { - my $e = shift; - foreach (@_) { - $e eq $_ and return 1; - } - 0; -} - -1; # End of AdminPanel::Shared diff --git a/AdminPanel/Users/GUsers.pm b/AdminPanel/Users/GUsers.pm deleted file mode 100644 index fe95a0b2..00000000 --- a/AdminPanel/Users/GUsers.pm +++ /dev/null @@ -1,2570 +0,0 @@ -# vim: set et ts=4 sw=4: -#***************************************************************************** -# -# Copyright (c) 2013 Angelo Naselli -# from adduserdrake and userdrake -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2, as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -#***************************************************************************** - -package AdminPanel::Users::GUsers; - -############################################### -## -## graphic related routines for managing user -## -############################################### - - -use strict; -# TODO evaluate if Moose is too heavy and use Moo -# instead -use POSIX qw(ceil); -# use Time::localtime; - -# TODO same translation atm -use lib qw(/usr/lib/libDrakX); -# i18n: IMPORTANT: to get correct namespace (userdrake instead of libDrakX) -BEGIN { unshift @::textdomains, 'userdrake', 'libuser', 'drakconf' } - -use common qw(N - translate); -use security::level; -use run_program; -## USER is from userdrake -use USER; -use utf8; -use log; - -use Glib; -use yui; -use AdminPanel::Shared; -use AdminPanel::Users::users; -use Moose; -extends qw( Module ); - -has '+icon' => ( - default => "/usr/share/icons/userdrake.png", -); - -has '+name' => ( - default => N("AdminUser"), -); - - -=head1 VERSION - -Version 1.0.0 - -=cut - -our $VERSION = '1.0.0'; - -# main dialog -has 'dialog' => ( - is => 'rw', - init_arg => undef, -); - -has 'widgets' => ( - traits => ['Hash'], - default => sub { {} }, - is => 'rw', - isa => 'HashRef', - handles => { - set_widget => 'set', - get_widget => 'get', - widget_pairs => 'kv', - }, - init_arg => undef, -); - -has 'action_menu' => ( - traits => ['Hash'], - default => sub { {} }, - is => 'rw', - isa => 'HashRef', - handles => { - set_action_menu => 'set', - get_action_menu => 'get', - action_menu_pairs => 'kv', - }, - init_arg => undef, -); - -## Used by USER (for getting values? TODO need explanations, where?) -has 'USER_GetValue' => ( - default => -65533, - is => 'ro', - isa => 'Int', - init_arg => undef, -); - -## Used by USER (for getting values? TODO need explanations, where?) -has 'ctx' => ( - default => sub {USER::ADMIN->new}, - is => 'ro', - init_arg => undef, -); - - -has 'edit_tab_widgets' => ( - traits => ['Hash'], - default => sub { {} }, - is => 'rw', - isa => 'HashRef', - handles => { - set_edit_tab_widget => 'set', - get_edit_tab_widget => 'get', - edit_tab_pairs => 'kv', - }, - init_arg => undef, -); - -sub start { - my $self = shift; - - $self->manageUsersDialog(); -}; - -# TODO move to Shared? -sub labeledFrameBox { - my ($parent, $label) = @_; - - my $factory = yui::YUI::widgetFactory; - - my $frame = $factory->createFrame($parent, $label); - $frame->setWeight( $yui::YD_HORIZ, 1); - $frame->setWeight( $yui::YD_VERT, 2); - $frame = $factory->createHVCenter( $frame ); - $frame = $factory->createVBox( $frame ); - return $frame; -} - -# usefull local variable to avoid duplicating -# translation point for user edit labels -my %userEditLabel = ( - user_data => N("User Data"), - account_info => N("Account Info"), - password_info => N("Password Info"), - groups => N("Groups"), -); -# usefull local variable to avoid duplicating -# translation point for group edit labels -my %groupEditLabel = ( - group_data => N("Group Data"), - group_users => N("Group Users"), -); -#============================================================= - -=head2 ChooseGroup - -=head3 INPUT - - $self: this object - -=head3 OUTPUT - - $choice: 0 or 1 (choice) - -1 cancel or exit - -=head3 DESCRIPTION - -creates a popup dialog to ask if adding user to an existing -group or to the 'users' group - -=cut - -#============================================================= -sub ChooseGroup { - my $self = shift; - - my $choice = -1; - - ## push application title - my $appTitle = yui::YUI::app()->applicationTitle(); - ## set new title to get it in dialog - yui::YUI::app()->setApplicationTitle(N("Choose group")); - - my $factory = yui::YUI::widgetFactory; - - my $dlg = $factory->createPopupDialog(); - my $layout = $factory->createVBox($dlg); - - - my $frame = labeledFrameBox($layout, N("A group with this name already exists. What would you like to do?")); - - my $rbg = $factory->createRadioButtonGroup( $frame ); - $frame = $factory->createVBox( $rbg ); - my $align = $factory->createLeft($frame); - - my $rb1 = $factory->createRadioButton( $align, N("Add to the existing group"), 1); - $rb1->setNotify(1); - $rbg->addRadioButton( $rb1 ); - $align = $factory->createLeft($frame); - my $rb2 = $factory->createRadioButton( $align, N("Add to the 'users' group"), 0); - $rb2->setNotify(1); - $rbg->addRadioButton( $rb2 ); - - my $hbox = $factory->createHBox($layout); - $align = $factory->createRight($hbox); - my $cancelButton = $factory->createPushButton($align, N("Cancel")); - my $okButton = $factory->createPushButton($hbox, N("Ok")); - while(1) { - my $event = $dlg->waitForEvent(); - my $eventType = $event->eventType(); - - #event type checking - if ($eventType == $yui::YEvent::CancelEvent) { - last; - } - elsif ($eventType == $yui::YEvent::WidgetEvent) { - # widget selected - my $widget = $event->widget(); - if ($widget == $cancelButton) { - last; - } - if ($widget == $okButton) { - $choice = $rb1->value() ? 0 : 1 ; - last; - } - } - } - - destroy $dlg; - - #restore old application title - yui::YUI::app()->setApplicationTitle($appTitle); - - return $choice; -} - -#============================================================= - -=head2 _updateOrDelUsersInGroup - -=head3 INPUT - - $name: username - -=head3 DESCRIPTION - - Fixes user deletion into groups. - -=cut - -#============================================================= -sub _updateOrDelUserInGroup { - my ($self, $name) = @_; - my $groups = $self->ctx->GroupsEnumerateFull; - foreach my $g (@$groups) { - my $members = $g->MemberName(1, 0); - if ($self->_inArray($name, $members)) { - eval { $g->MemberName($name, 2) }; - eval { $self->ctx->GroupModify($g) }; - } - } -} - -#============================================================= - -=head2 _deleteGroupDialog - -=head3 INPUT - - $self: this object - -=head3 DESCRIPTION - - This method open a dialog to delete the selected group. - -=cut - -#============================================================= -sub _deleteGroupDialog { - my $self = shift; - - my $item = $self->get_widget('table')->selectedItem(); - if (! $item) { - return; - } - - my $groupname = $item->label(); - ## push application title - my $appTitle = yui::YUI::app()->applicationTitle(); - ## set new title to get it in dialog - yui::YUI::app()->setApplicationTitle(N("Warning")); - - my $factory = yui::YUI::widgetFactory; - my $dlg = $factory->createPopupDialog(); - my $layout = $factory->createVBox($dlg); - - my $align = $factory->createLeft($layout); - - $factory->createLabel($align, N("Do you really want to delete the group %s?", - $groupname)); - - $align = $factory->createRight($layout); - my $hbox = $factory->createHBox($align); - my $cancelButton = $factory->createPushButton($hbox, N("Cancel")); - my $deleteButton = $factory->createPushButton($hbox, N("Delete")); - - while(1) { - my $event = $dlg->waitForEvent(); - my $eventType = $event->eventType(); - - #event type checking - if ($eventType == $yui::YEvent::CancelEvent) { - last; - } - elsif ($eventType == $yui::YEvent::WidgetEvent) { - # widget selected - my $widget = $event->widget(); - if ($widget == $cancelButton) { - last; - } - elsif ($widget == $deleteButton) { - my $groupEnt = $self->ctx->LookupGroupByName($groupname); - my $members = $self->ctx->EnumerateUsersByGroup($groupname); - my $continue = 1; - GLOOP: foreach my $username (@$members) { - my $userEnt = $self->ctx->LookupUserByName($username); - if ($userEnt && $userEnt->Gid($self->USER_GetValue) == $groupEnt->Gid($self->USER_GetValue)) { - AdminPanel::Shared::msgBox(N("%s is a primary group for user %s\n Remove the user first", - $groupname, $username)); - $continue = 0; - last GLOOP; - } - } - if ($continue) { - log::explanations(N("Removing group: %s", $groupname)); - eval { $self->ctx->GroupDel($groupEnt) }; - $self->_refresh(); - } - last; - } - } - } - - destroy $dlg; - - #restore old application title - yui::YUI::app()->setApplicationTitle($appTitle); -} - -#============================================================= - -=head2 _deleteUserDialog - -=head3 INPUT - - $self: this object - -=head3 DESCRIPTION - - This method open a dialog to delete the selected user. - It also asks for additional information to be removed. - -=cut - -#============================================================= -sub _deleteUserDialog { - my $self = shift; - - my $item = $self->get_widget('table')->selectedItem(); - if (! $item) { - return; - } - my $username = $item->label(); - - my $userEnt = $self->ctx->LookupUserByName($username); - my $homedir = $userEnt->HomeDir($self->USER_GetValue); - - ## push application title - my $appTitle = yui::YUI::app()->applicationTitle(); - ## set new title to get it in dialog - yui::YUI::app()->setApplicationTitle(N("Delete files or not?")); - - my $factory = yui::YUI::widgetFactory; - my $dlg = $factory->createPopupDialog(); - my $layout = $factory->createVBox($dlg); - - my $align = $factory->createLeft($layout); - $factory->createLabel($align, N("Deleting user %s\nAlso perform the following actions\n", - $username)); - $align = $factory->createLeft($layout); - my $checkhome = $factory->createCheckBox($align, N("Delete Home Directory: %s", $homedir, 0)); - $align = $factory->createLeft($layout); - my $checkspool = $factory->createCheckBox($align, N("Delete Mailbox: /var/spool/mail/%s", - $username), 0); - $align = $factory->createRight($layout); - my $hbox = $factory->createHBox($align); - my $cancelButton = $factory->createPushButton($hbox, N("Cancel")); - my $deleteButton = $factory->createPushButton($hbox, N("Delete")); - - if ($homedir !~ m!(?:/home|/var/spool)!) { - $checkhome->setDisabled(); - $checkspool->setDisabled(); - } - - - while(1) { - my $event = $dlg->waitForEvent(); - my $eventType = $event->eventType(); - - #event type checking - if ($eventType == $yui::YEvent::CancelEvent) { - last; - } - elsif ($eventType == $yui::YEvent::WidgetEvent) { - # widget selected - my $widget = $event->widget(); - if ($widget == $cancelButton) { - last; - } - elsif ($widget == $deleteButton) { - log::explanations(N("Removing user: %s", $username)); - $self->ctx->UserDel($userEnt); - $self->_updateOrDelUserInGroup($username); - #Let's check out the user's primary group - my $usergid = $userEnt->Gid($self->USER_GetValue); - my $groupEnt = $self->ctx->LookupGroupById($usergid); - if ($groupEnt) { - my $member = $groupEnt->MemberName(1, 0); - if (scalar(@$member) == 0 && $groupEnt->Gid($self->USER_GetValue) > 499) { - $self->ctx->GroupDel($groupEnt); - } - } - if ($checkhome->isChecked()) { - eval { $self->ctx->CleanHome($userEnt) }; - $@ and AdminPanel::Shared::msgBox($@) and last; - } - if ($checkspool->isChecked()) { - eval { $self->ctx->CleanSpool($userEnt) }; - $@ and AdminPanel::Shared::msgBox($@) and last; - } - $self->_refresh(); - last; - } - } - } - - destroy $dlg; - - #restore old application title - yui::YUI::app()->setApplicationTitle($appTitle); - -} - - -sub _addGroupDialog { - my $self = shift; - - my $is_system = 0; - - ## push application title - my $appTitle = yui::YUI::app()->applicationTitle(); - ## set new title to get it in dialog - yui::YUI::app()->setApplicationTitle(N("Create New Group")); - my $factory = yui::YUI::widgetFactory; - my $optional = yui::YUI::optionalWidgetFactory; - - my $dlg = $factory->createPopupDialog(); - my $layout = $factory->createVBox($dlg); - - ## 'group name' - my $align = $factory->createRight($layout); - my $hbox = $factory->createHBox($align); - my $label = $factory->createLabel($hbox, N("Group Name:") ); - my $groupName = $factory->createInputField($hbox, "", 0); - $label->setWeight($yui::YD_HORIZ, 1); - $groupName->setWeight($yui::YD_HORIZ, 2); - - $factory->createVSpacing($layout, 1); - - # Specify group id manually - $align = $factory->createLeft($layout); - $hbox = $factory->createHBox($align); - my $gidManually = $factory->createCheckBox($hbox, N("Specify group ID manually"), 0); - $factory->createHSpacing($hbox, 2); - my $GID = $factory->createIntField($hbox, N("GID"), 1, 65000, 500); - $GID->setEnabled($gidManually->value()); - $gidManually->setNotify(1); - - $hbox = $factory->createHBox($layout); - $align = $factory->createRight($hbox); - my $cancelButton = $factory->createPushButton($align, N("Cancel")); - my $okButton = $factory->createPushButton($hbox, N("Ok")); - while(1) { - my $event = $dlg->waitForEvent(); - my $eventType = $event->eventType(); - - #event type checking - if ($eventType == $yui::YEvent::CancelEvent) { - last; - } - elsif ($eventType == $yui::YEvent::WidgetEvent) { - # widget selected - my $widget = $event->widget(); - if ($widget == $cancelButton) { - last; - } - elsif ($widget == $gidManually) { - # GID inserction enabled? - $GID->setEnabled($gidManually->value()); - } - elsif ($widget == $okButton) { - ## check data - my $groupname = $groupName->value(); - my ($continue, $errorString) = valid_groupname($groupname); - my $nm = $continue && $self->ctx->LookupGroupByName($groupname); - if ($nm) { - $groupName->setValue(""); - $errorString = N("Group already exists, please choose another Group Name"); - $continue = 0; - } - my $groupEnt = $self->ctx->InitGroup($groupname, $is_system); - - my $gid = 0; - if ($continue && $gidManually->value()) { - if (($gid = $GID->value()) < 500) { - $errorString = ""; - my $gidchoice = AdminPanel::Shared::ask_YesOrNo(N(" Group Gid is < 500"), - N("Creating a group with a GID less than 500 is not recommended.\n Are you sure you want to do this?\n\n")); - $continue = $gidchoice and $groupEnt->Gid($gid); - } else { - my $g = $self->ctx->LookupGroupById($gid); - if ($g) { - $errorString = ""; - my $gidchoice = AdminPanel::Shared::ask_YesOrNo(N(" Group ID is already used "), - N("Creating a group with a non unique GID?\n\n")); - $continue = $gidchoice and $groupEnt->Gid($gid); - } - else { - $groupEnt and $groupEnt->Gid($gid); - } - } - } - - - if (!$continue) { - #--- raise error - AdminPanel::Shared::msgBox($errorString) if ($errorString); - } - else { - log::explanations(N("Adding group: %s ", $groupname)); - $self->ctx->GroupAdd($groupEnt); - $self->_refresh(); - last; - } - } - } - } - destroy $dlg; - - #restore old application title - yui::YUI::app()->setApplicationTitle($appTitle); -} - - -#============================================================= - -=head2 _buildUserData - -=head3 INPUT - - $self: this object - $layout : layout in wich drawing graphic user data - -=head3 OUTPUT - - %userData: hash containing reference to graphical object - such as: - full_name, login_name, password, password1, - login_shell - -=head3 DESCRIPTION - - This method is used by addUserDialog and _editUserDialog - to create User Data dialog -=cut - -#============================================================= -sub _buildUserData { - my ($self, $layout, $selected_shell) = @_; - - - my @shells = @{$self->ctx->GetUserShells}; - - my $factory = yui::YUI::widgetFactory; - - ## user 'full name' - my $align = $factory->createRight($layout); - my $hbox = $factory->createHBox($align); - my $label = $factory->createLabel($hbox, N("Full Name:") ); - my $fullName = $factory->createInputField($hbox, "", 0); - $label->setWeight($yui::YD_HORIZ, 1); - $fullName->setWeight($yui::YD_HORIZ, 2); - - ## user 'login name' - $align = $factory->createRight($layout); - $hbox = $factory->createHBox($align); - $label = $factory->createLabel($hbox, N("Login:") ); - my $loginName = $factory->createInputField($hbox, "", 0); - $label->setWeight($yui::YD_HORIZ, 1); - $loginName->setWeight($yui::YD_HORIZ, 2); - $loginName->setNotify(1); - - ## user 'Password' - $align = $factory->createRight($layout); - $hbox = $factory->createHBox($align); - $label = $factory->createLabel($hbox, N("Password:") ); - my $password = $factory->createInputField($hbox, "", 1); - $label->setWeight($yui::YD_HORIZ, 1); - $password->setWeight($yui::YD_HORIZ, 2); - - ## user 'confirm Password' - $align = $factory->createRight($layout); - $hbox = $factory->createHBox($align); - $label = $factory->createLabel($hbox, N("Confirm Password:") ); - my $password1 = $factory->createInputField($hbox, "", 1); - $label->setWeight($yui::YD_HORIZ, 1); - $password1->setWeight($yui::YD_HORIZ, 2); - - ## user 'Login Shell' - $align = $factory->createRight($layout); - $hbox = $factory->createHBox($align); - $label = $factory->createLabel($hbox, N("Login Shell:") ); - my $loginShell = $factory->createComboBox($hbox, "", 0); - my $itemColl = new yui::YItemCollection; - foreach my $shell (@shells) { - my $item = new yui::YItem ($shell, 0); - $item->setSelected(1) if ($selected_shell && $selected_shell eq $shell); - $itemColl->push($item); - $item->DISOWN(); - } - $loginShell->addItems($itemColl); - $label->setWeight($yui::YD_HORIZ, 1); - $loginShell->setWeight($yui::YD_HORIZ, 2); - - my %userData = ( - full_name => $fullName, - login_name => $loginName, - password => $password, - password1 => $password1, - login_shell => $loginShell, - ); - - return ( %userData ); -} - -#============================================================= - -=head2 addUserDialog - -=head3 INPUT - - $self: this object - $standalone: if set the application title is set - from the name set in costructor - -=head3 DESCRIPTION - - This method creates and manages the dialog to add a new - user. - -=cut - -#============================================================= -sub addUserDialog { - my $self = shift; - my $standalone = shift; - - my $dontcreatehomedir = 0; - my $is_system = 0; - - ## push application title - my $appTitle = yui::YUI::app()->applicationTitle(); - ## set new title to get it in dialog - if ($standalone) { - yui::YUI::app()->setApplicationTitle($self->name); - } - else { - yui::YUI::app()->setApplicationTitle(N("Create New User")); - } - - my $factory = yui::YUI::widgetFactory; - my $optional = yui::YUI::optionalWidgetFactory; - - my $dlg = $factory->createPopupDialog(); - my $layout = $factory->createVBox($dlg); - - my %userData = $self->_buildUserData($layout); - - ##### add a separator - ## Create Home directory - my $align = $factory->createLeft($layout); - my $hbox = $factory->createHBox($align); - my $createHome = $factory->createCheckBox($hbox, N("Create Home Directory"), 1); - ## Home directory - $align = $factory->createLeft($layout); - $hbox = $factory->createHBox($align); - my $label = $factory->createLabel($hbox, N("Home Directory:") ); - my $homeDir = $factory->createInputField($hbox, "", 0); - $label->setWeight($yui::YD_HORIZ, 1); - $homeDir->setWeight($yui::YD_HORIZ, 2); - - # Create private group - $align = $factory->createLeft($layout); - $hbox = $factory->createHBox($align); - my $createGroup = $factory->createCheckBox($hbox, N("Create a private group for the user"), 1); - - # Specify user id manually - $align = $factory->createRight($layout); - $hbox = $factory->createHBox($align); - my $uidManually = $factory->createCheckBox($hbox, N("Specify user ID manually"), 0); - my $UID = $factory->createIntField($hbox, N("UID"), 1, 65000, 500); - $UID->setEnabled($uidManually->value()); - $uidManually->setNotify(1); - $uidManually->setWeight($yui::YD_HORIZ, 2); - $UID->setWeight($yui::YD_HORIZ, 1); - - ## user 'icon' - $hbox = $factory->createHBox($layout); - $factory->createLabel($hbox, N("Click on icon to change it") ); - my $iconFace = AdminPanel::Users::users::GetFaceIcon(); - my $icon = $factory->createPushButton($hbox, ""); - $icon->setIcon(AdminPanel::Users::users::face2png($iconFace)); - $icon->setLabel($iconFace); - - $hbox = $factory->createHBox($layout); - $align = $factory->createRight($hbox); - my $cancelButton = $factory->createPushButton($align, N("Cancel")); - my $okButton = $factory->createPushButton($hbox, N("Ok")); - while(1) { - my $event = $dlg->waitForEvent(); - my $eventType = $event->eventType(); - - #event type checking - if ($eventType == $yui::YEvent::CancelEvent) { - last; - } - elsif ($eventType == $yui::YEvent::WidgetEvent) { - # widget selected - my $widget = $event->widget(); - if ($widget == $cancelButton) { - last; - } - elsif ($widget == $icon) { - #remove shortcut from label - my $iconLabel = $self->_skipShortcut($icon->label()); - - my $nextIcon = GetFaceIcon($icon->label(), 1); - $icon->setLabel($nextIcon); - $icon->setIcon(AdminPanel::Users::users::face2png($nextIcon)); - } - elsif ($widget == $uidManually) { - # UID inserction enabled? - $UID->setEnabled($uidManually->value()); - } - elsif ($widget == $userData{ login_name }) { - my $username = $userData{ login_name }->value(); - $homeDir->setValue("/home/$username"); - } - elsif ($widget == $okButton) { - ## check data - my $username = $userData{ login_name }->value(); - my ($continue, $errorString) = valid_username($username); - my $nm = $continue && $self->ctx->LookupUserByName($username); - if ($nm) { - $userData{ login_name }->setValue(""); - $homeDir->setValue(""); - $errorString = N("User already exists, please choose another User Name"); - $continue = 0; - } - my $passwd = $continue && $userData{ password }->value(); - if ($continue && $passwd ne $userData{ password1 }->value()) { - $errorString = N("Password Mismatch"); - $continue = 0; - } - my $sec = security::level::get(); - if ($sec > 3 && length($passwd) < 6) { - $errorString = N("This password is too simple. \n Good passwords should be > 6 characters"); - $continue = 0; - } - my $userEnt = $continue && $self->ctx->InitUser($username, $is_system); - if ($continue && $createHome->value()) { - $dontcreatehomedir = 0; - my $homedir = $homeDir->value(); - $userEnt and $userEnt->HomeDir($homedir); - } else { - $dontcreatehomedir = 1; - } - my $uid = 0; - if ($continue && $uidManually->value()) { - if (($uid = $UID->value()) < 500) { - $errorString = ""; - my $uidchoice = AdminPanel::Shared::ask_YesOrNo(N("User Uid is < 500"), - N("Creating a user with a UID less than 500 is not recommended.\nAre you sure you want to do this?\n\n")); - $continue = $uidchoice and $userEnt->Uid($uid); - } else { - $userEnt and $userEnt->Uid($uid); - } - } - my $gid = 0; - if ($createGroup->value()) { - if ($continue) { - #Check if group exist - my $gr = $self->ctx->LookupGroupByName($username); - if ($gr) { - my $groupchoice = $self->ChooseGroup(); - if ($groupchoice == 0 ) { - #You choose to put it in the existing group - $gid = $gr->Gid($self->USER_GetValue); - } elsif ($groupchoice == 1) { - # Put it in 'users' group - log::explanations(N("Putting %s to 'users' group", - $username)); - $gid = AdminPanel::Users::users::Add2UsersGroup($username, $self->ctx); - } - else { - $errorString = ""; - $continue = 0; - } - } else { - #it's a new group: Add it - my $newgroup = $self->ctx->InitGroup($username,$is_system); - log::explanations(N("Creating new group: %s", $username)); - $gid = $newgroup->Gid($self->USER_GetValue); - $self->ctx->GroupAdd($newgroup); - } - } - } else { - $continue and $gid = AdminPanel::Users::users::Add2UsersGroup($username, $self->ctx); - } - - if (!$continue) { - #---rasie error - AdminPanel::Shared::msgBox($errorString) if ($errorString); - } - else { - ## OK let's create the user - print N("Adding user: ") . $username . " \n"; - log::explanations(N("Adding user: %s"), $username); - my $loginshell = $userData{ login_shell }->value(); - my $fullname = $userData{ full_name }->value(); - $userEnt->Gecos($fullname); $userEnt->LoginShell($loginshell); - $userEnt->Gid($gid); - $userEnt->ShadowMin(-1); $userEnt->ShadowMax(99999); - $userEnt->ShadowWarn(-1); $userEnt->ShadowInact(-1); - $self->ctx->UserAdd($userEnt, $is_system, $dontcreatehomedir); - $self->ctx->UserSetPass($userEnt, $passwd); - defined $icon->label() and - AdminPanel::Users::users::addKdmIcon($username, $icon->label()); -### TODO Migration wizard -# -# Refresh($sysfilter, $stringsearch); -# transfugdrake::get_windows_disk() -# and $in->ask_yesorno(N("Migration wizard"), -# N("Do you want to run the migration wizard in order to import Windows documents and settings in your Mageia distribution?")) -# and run_program::raw({ detach => 1 }, 'transfugdrake'); - - - last; - } - } - } - } - - destroy $dlg; - - #restore old application title - yui::YUI::app()->setApplicationTitle($appTitle) if $appTitle; -} - -#============================================================= - -=head2 _createUserTable - -=head3 INPUT - - $self: this object - -=head3 DESCRIPTION - -This function create the User table to be added to the replace -point of the tab widget. Note this function is meant for internal -use only - -=cut - -#============================================================= -sub _createUserTable { - my $self = shift; - - $self->dialog->startMultipleChanges(); - $self->get_widget('replace_pnt')->deleteChildren(); - my $parent = $self->get_widget('replace_pnt'); - my $factory = yui::YUI::widgetFactory; - my $yTableHeader = new yui::YTableHeader(); - $yTableHeader->addColumn(N("User Name"), $yui::YAlignBegin); - $yTableHeader->addColumn(N("User ID"), $yui::YAlignBegin); - $yTableHeader->addColumn(N("Primary Group"), $yui::YAlignBegin); - $yTableHeader->addColumn(N("Full Name"), $yui::YAlignBegin); - $yTableHeader->addColumn(N("Login Shell"), $yui::YAlignBegin); - $yTableHeader->addColumn(N("Home Directory"), $yui::YAlignBegin); - $yTableHeader->DISOWN(); - - $self->set_widget(table => $factory->createTable($parent, $yTableHeader)); - - $self->get_widget('table')->setImmediateMode(1); - $self->get_widget('table')->DISOWN(); - $self->get_widget('replace_pnt')->showChild(); - $self->dialog->recalcLayout(); - $self->dialog->doneMultipleChanges(); - $self->_refreshUsers(); -} - -#============================================================= - -=head2 _createGroupTable - -=head3 INPUT - - $self: this object - -=head3 DESCRIPTION - -This function create the Group table to be added to the replace -point of the tab widget. Note this function is meant for internal -use only - - -=cut - -#============================================================= -sub _createGroupTable { - my $self = shift; - - - $self->dialog->startMultipleChanges(); - $self->get_widget('replace_pnt')->deleteChildren(); - my $parent = $self->get_widget('replace_pnt'); - my $factory = yui::YUI::widgetFactory; - my $yTableHeader = new yui::YTableHeader(); - $yTableHeader->addColumn(N("Group Name"), $yui::YAlignBegin); - $yTableHeader->addColumn(N("Group ID"), $yui::YAlignBegin); - $yTableHeader->addColumn(N("Group Members"), $yui::YAlignBegin); - $yTableHeader->DISOWN(); - - $self->set_widget(table => $factory->createTable($parent, $yTableHeader)); - - $self->get_widget('table')->setImmediateMode(1); - $self->get_widget('table')->DISOWN(); - $self->get_widget('replace_pnt')->showChild(); - $self->dialog->recalcLayout(); - $self->dialog->doneMultipleChanges(); - $self->_refreshGroups(); -} - - -#============================================================= - -=head2 _computeLockExpire - -=head3 INPUT - - $l: login user info - -=head3 OUTPUT - - $status: Locked, Expired, or empty string - -=head3 DESCRIPTION - - This method returns if the login is Locked, Expired or ok. - Note this function is meant for internal use only - -=cut - -#============================================================= -sub _computeLockExpire { - my ( $self, $l ) = @_; - my $ep = $l->ShadowExpire($self->USER_GetValue); - my $tm = ceil(time()/(24*60*60)); - $ep = -1 if int($tm) <= $ep; - my $status = $self->ctx->IsLocked($l) ? N("Locked") : ($ep != -1 ? N("Expired") : ''); - $status; -} - -#============================================================= - -=head2 _refreshUsers - -=head3 INPUT - - $self: this object - -=head3 DESCRIPTION - - This method refresh user info into User tab widget. - Note this function is meant for internal use only - -=cut - -#============================================================= -sub _refreshUsers { - my $self = shift; - - my $strfilt = $self->get_widget('filter')->value(); - my $filterusers = $self->get_widget('filter_system')->isChecked(); - - my ($users, $group, $groupnm, $expr); - defined $self->ctx and $users = $self->ctx->UsersEnumerateFull; - - $self->dialog->startMultipleChanges(); - #for some reasons QT send an event using table->selectItem() - # WA remove notification immediate - $self->get_widget('table')->setImmediateMode(0); - $self->get_widget('table')->deleteAllItems(); - - my @UserReal; - LOOP: foreach my $l (@$users) { - next LOOP if $filterusers && $l->Uid($self->USER_GetValue) <= 499 || $l->Uid($self->USER_GetValue) == 65534; - push @UserReal, $l if $l->UserName($self->USER_GetValue) =~ /^\Q$strfilt/; - } - my $i; - my $itemColl = new yui::YItemCollection; - foreach my $l (@UserReal) { - $i++; - my $uid = $l->Uid($self->USER_GetValue); - if (!defined $uid) { - warn "bogus user at line $i\n"; - next; - } - my $a = $l->Gid($self->USER_GetValue); - $group = $self->ctx->LookupGroupById($a); - $groupnm = ''; - $expr = $self->_computeLockExpire($l); - $group and $groupnm = $group->GroupName($self->USER_GetValue); - my $s = $l->Gecos($self->USER_GetValue); - c::set_tagged_utf8($s); - my $username = $l->UserName($self->USER_GetValue); - my $Uid = $l->Uid($self->USER_GetValue); - my $shell = $l->LoginShell($self->USER_GetValue); - my $homedir = $l->HomeDir($self->USER_GetValue); - my $item = new yui::YTableItem ("$username", - "$Uid", - "$groupnm", - "$s", - "$shell", - "$homedir", - "$expr"); - # TODO workaround to get first cell at least until we don't - # a cast from YItem - $item->setLabel( $username ); - $itemColl->push($item); - $item->DISOWN(); - } - $self->get_widget('table')->addItems($itemColl); - my $item = $self->get_widget('table')->selectedItem(); - $self->get_widget('table')->selectItem($item, 0) if $item; - $self->dialog->recalcLayout(); - $self->dialog->doneMultipleChanges(); - $self->_refreshActions(); - $self->get_widget('table')->setImmediateMode(1); -} - -#============================================================= - -=head2 _refreshGroups - -=head3 INPUT - - $self: this object - -=head3 DESCRIPTION - - This method refresh group info into Group tab widget. - Note this function is meant for internal use only - -=cut - -#============================================================= -sub _refreshGroups { - my $self = shift; - - my $strfilt = $self->get_widget('filter')->value(); - my $filtergroups = $self->get_widget('filter_system')->isChecked(); - - my $groups; - defined $self->ctx and $groups = $self->ctx->GroupsEnumerateFull; - - $self->dialog->startMultipleChanges(); - #for some reasons QT send an event using table->selectItem() - # WA remove notification immediate - $self->get_widget('table')->setImmediateMode(0); - $self->get_widget('table')->deleteAllItems(); - my @GroupReal; - LOOP: foreach my $g (@$groups) { - next LOOP if $filtergroups && $g->Gid($self->USER_GetValue) <= 499 || $g->Gid($self->USER_GetValue) == 65534; - push @GroupReal, $g if $g->GroupName($self->USER_GetValue) =~ /^\Q$strfilt/; - } - - my $itemColl = new yui::YItemCollection; - foreach my $g (@GroupReal) { - my $a = $g->GroupName($self->USER_GetValue); - #my $group = $ctx->LookupGroupById($a); - my $u_b_g = $a && $self->ctx->EnumerateUsersByGroup($a); - my $listUbyG = join(',', @$u_b_g); - my $group_id = $g->Gid($self->USER_GetValue); - my $groupname = $g->GroupName($self->USER_GetValue); - my $item = new yui::YTableItem ("$groupname", - "$group_id", - "$listUbyG"); - $item->setLabel( $groupname ); - $itemColl->push($item); - $item->DISOWN(); - } - - $self->get_widget('table')->addItems($itemColl); - my $item = $self->get_widget('table')->selectedItem(); - $self->get_widget('table')->selectItem($item, 0) if $item; - $self->dialog->recalcLayout(); - $self->dialog->doneMultipleChanges(); - $self->_refreshActions(); - $self->get_widget('table')->setImmediateMode(1); -} - - -#============================================================= - -=head2 _getUserInfo - -=head3 INPUT - - $self: this object - -=head3 OUTPUT - - %userData: selected user info as: - username: username - full_name: full name of user - shell: shell used - homedir: home dir path - UID: User identifier - acc_check_exp: account expiration enabling - acc_expy: account expiration year - acc_expm: account expiration month - acc_expd: account expiration day - lockuser: account locked - pwd_check_exp: password expiration enabling - pwd_exp_min: days before changing password - is allowed - pwd_exp_max: days before changing password - is required - pwd_exp_warn: warning days before changing - pwd_exp_inact: days before account becomes - inact - members: Array containing groups the user - belongs to. - primary_group: primary group ID for the user - -=head3 DESCRIPTION - - Retrieves the selected user info from the system - Note that acc_expy, acc_expm and acc_expd are valid if - acc_check_exp is enabled. - Note that pwd_exp_min, pwd_exp_max, pwd_exp_warn, - pwd_exp_inact are valid if pwd_check_exp is enabled. - -=cut - -#============================================================= - -sub _getUserInfo { - my $self = shift; - - my $label = $self->_skipShortcut($self->get_widget('tabs')->selectedItem()->label()); - if ($label ne N("Users") ) { - return undef; - } - - my $item = $self->get_widget('table')->selectedItem(); - if (! $item) { - return undef; - } - - my %userData; - $userData{username} = $item->label(); - my $userEnt = $self->ctx->LookupUserByName($userData{username}); - - my $s = $userEnt->Gecos($self->USER_GetValue); - c::set_tagged_utf8($s); - $userData{full_name} = $s; - $userData{shell} = $userEnt->LoginShell($self->USER_GetValue); - $userData{homedir} = $userEnt->HomeDir($self->USER_GetValue); - $userData{UID} = $userEnt->Uid($self->USER_GetValue); - - # default expiration time - my ($day, $mo, $ye) = (localtime())[3, 4, 5]; - $userData{acc_expy} = $ye+1900; - $userData{acc_expm} = $mo+1; - $userData{acc_expd} = $day; - $userData{acc_check_exp} = 0; - my $expire = $userEnt->ShadowExpire($self->USER_GetValue); - if ($expire && $expire != -1) { - my $times = TimeOfArray($expire, 1); - $userData{acc_expy} = $times->{year}; - $userData{acc_expm} = $times->{month}; - $userData{acc_expd} = $times->{dayint}; - $userData{acc_check_exp} = 1; - } - - # user password are not retrieved if admin wants - # to change it has to insert a new one - $userData{password} = undef; - $userData{password1} = undef; - # Check if user account is locked - - $userData{lockuser} = $self->ctx->IsLocked($userEnt); - - $userData{icon_face} = AdminPanel::Users::users::GetFaceIcon($userData{username}); - $userData{pwd_check_exp} = 0; - $userData{pwd_exp_min} = $userEnt->ShadowMin($self->USER_GetValue); - $userData{pwd_exp_max} = $userEnt->ShadowMax($self->USER_GetValue); - $userData{pwd_exp_warn} = $userEnt->ShadowWarn($self->USER_GetValue); - $userData{pwd_exp_inact} = $userEnt->ShadowInact($self->USER_GetValue); - - if ($userData{pwd_exp_min} && $userData{pwd_exp_min} != -1 || - $userData{pwd_exp_max} && $userData{pwd_exp_max} != 99999 || - $userData{pwd_exp_warn} && $userData{pwd_exp_warn} != 7 && $userData{pwd_exp_warn} != -1 || - $userData{pwd_exp_inact} && $userData{pwd_exp_inact} != -1) { - $userData{pwd_check_exp} = 1; - } - - $userData{members} = $self->ctx->EnumerateGroupsByUser($userData{username}); - $userData{primary_group} = $userEnt->Gid($self->USER_GetValue); - - return %userData; - -} - -#============================================================= - -=head2 _getUserInfo - -=head3 INPUT - - $self: this object - -=head3 OUTPUT - - %groupData: selected group info as: - $groupname: group name - $members: users that are members of this group - -=head3 DESCRIPTION - - Retrieves the selected group info from the system - -=cut - -#============================================================= - -sub _getGroupInfo { - my $self = shift; - - my $label = $self->_skipShortcut($self->get_widget('tabs')->selectedItem()->label()); - if ($label ne N("Groups") ) { - return undef; - } - - my $item = $self->get_widget('table')->selectedItem(); - if (! $item) { - return undef; - } - - my %groupData; - $groupData{start_groupname} = $item->label(); - $groupData{groupname} = $item->label(); - - my $groupEnt = $self->ctx->LookupGroupByName($groupData{groupname}); - $groupData{members} = $self->ctx->EnumerateUsersByGroup($groupData{groupname}); - - return %groupData; - -} - -sub _storeDataFromGroupEditPreviousTab { - my ($self, %groupData) = @_; - - my $previus_tab = $self->get_edit_tab_widget('edit_tab_label'); - if (!$previus_tab) { - return %groupData; - } - elsif ($previus_tab eq $groupEditLabel{group_data}) { - $groupData{groupname} = $self->get_edit_tab_widget('groupname')->value(); - } - elsif ($previus_tab eq $groupEditLabel{group_users}) { - my $tbl = $self->get_edit_tab_widget('members'); - $groupData{members} = undef; - my @members; - my $i; - for($i=0;$i<$tbl->itemsCount();$i++) { - push (@members, $tbl->item($i)->label()) if $tbl->toCBYTableItem($tbl->item($i))->checked(); - } - $groupData{members} = [ @members ]; - } - - return %groupData; -} - - -sub _storeDataFromUserEditPreviousTab { - my ($self, %userData) = @_; - - my $previus_tab = $self->get_edit_tab_widget('edit_tab_label'); - if (!$previus_tab) { - return %userData; - } - elsif ($previus_tab eq $userEditLabel{user_data}) { - $userData{full_name} = $self->get_edit_tab_widget('full_name')->value(); - $userData{username} = $self->get_edit_tab_widget('login_name')->value() ; - $userData{shell} = $self->get_edit_tab_widget('login_shell')->value(); - $userData{homedir} = $self->get_edit_tab_widget('homedir')->value(); - my $passwd = $self->get_edit_tab_widget('password')->value(); - $userData{password} = $passwd; - $passwd = $self->get_edit_tab_widget('password1')->value(); - $userData{password1} = $passwd; - } - elsif ($previus_tab eq $userEditLabel{account_info}) { - $userData{acc_check_exp} = $self->get_edit_tab_widget('acc_check_exp')->value(); - $userData{acc_expy} = $self->get_edit_tab_widget('acc_expy')->value(); - $userData{acc_expm} = $self->get_edit_tab_widget('acc_expm')->value(); - $userData{acc_expd} = $self->get_edit_tab_widget('acc_expd')->value(); - $userData{lockuser} = $self->get_edit_tab_widget('lockuser')->value(); - $userData{icon_face} = $self->get_edit_tab_widget('icon_face')->label(); - } - elsif ($previus_tab eq $userEditLabel{password_info}) { - $userData{pwd_check_exp} = $self->get_edit_tab_widget('pwd_check_exp')->value(); - $userData{pwd_exp_min} = $self->get_edit_tab_widget('pwd_exp_min')->value(); - $userData{pwd_exp_max} = $self->get_edit_tab_widget('pwd_exp_max')->value(); - $userData{pwd_exp_warn} = $self->get_edit_tab_widget('pwd_exp_warn')->value(); - $userData{pwd_exp_inact} = $self->get_edit_tab_widget('pwd_exp_inact')->value(); - } - elsif ($previus_tab eq $userEditLabel{groups}) { - my $tbl = $self->get_edit_tab_widget('members'); - $userData{members} = undef; - my @members; - my $i; - for($i=0;$i<$tbl->itemsCount();$i++) { - push (@members, $tbl->item($i)->label()) if $tbl->toCBYTableItem($tbl->item($i))->checked(); - } - $userData{members} = [ @members ]; - - if ($self->get_edit_tab_widget('primary_group')->selectedItem()) { - my $Gent = $self->ctx->LookupGroupByName($self->get_edit_tab_widget('primary_group')->selectedItem()->label()); - my $primgroup = $Gent->Gid($self->USER_GetValue); - - $userData{primary_group} = $primgroup; - } - else { - $userData{primary_group} = -1; - } - } - - return %userData; -} - -#============================================================= - -=head2 _userDataTabWidget - -=head3 INPUT - - $self: this object - $dialog: YUI dialog that owns the YUI replace point - $replace_pnt: YUI replace point, needed to add a new tab - widget - %userData: hash containing user data info, tabs are - removed and added again on selection, so - data must be saved outside of widgets. - $previus_tab: previous tab widget label, needed to store - user data from the old tab before removing - it, if user changed something. - -=head3 OUTPUT - - %userDataWidget: hash containing new YUI widget objects - such as: - retunred onject from _buildUserData and - homedir. - -=head3 DESCRIPTION - - This internal method removes old tab widget saving its - relevant data into userData and creates new selected table - to be shown. - -=cut - -#============================================================= -sub _userDataTabWidget { - my ($self, $dialog, $replace_pnt, %userData) = @_; - - my $factory = yui::YUI::widgetFactory; - - $dialog->startMultipleChanges(); - - $replace_pnt->deleteChildren(); - my $layout = $factory->createVBox($replace_pnt); - my %userDataWidget = $self->_buildUserData($layout, $userData{shell}); - - ## user 'login name' - my $align = $factory->createRight($layout); - my $hbox = $factory->createHBox($align); - my $label = $factory->createLabel($hbox, N("Home:") ); - $userDataWidget{homedir} = $factory->createInputField($hbox, "", 0); - $label->setWeight($yui::YD_HORIZ, 1); - $userDataWidget{homedir}->setWeight($yui::YD_HORIZ, 2); - - # fill data into widgets - ## - # full_name, login_name, password, password1, - # login_shell - $userDataWidget{full_name}->setValue($userData{full_name}); - $userDataWidget{login_name}->setValue($userData{username}); - $userDataWidget{password}->setValue($userData{password}) if $userData{password}; - $userDataWidget{password1}->setValue($userData{password1}) if $userData{password1}; - $userDataWidget{homedir}->setValue($userData{homedir}); - - $replace_pnt->showChild(); - $dialog->recalcLayout(); - $dialog->doneMultipleChanges(); - - return %userDataWidget; -} - - -#============================================================= - -=head2 _groupDataTabWidget - -=head3 INPUT - - $self: this object - $dialog: YUI dialog that owns the YUI replace point - $replace_pnt: YUI replace point, needed to add a new tab - widget - %groupData: hash containing group data info, tabs are - removed and added again on selection, so - data must be saved outside of widgets. - $previus_tab: previous tab widget label, needed to store - group data from the old tab before removing - it, if user changed something. - -=head3 OUTPUT - - %groupDataWidget: hash containing new YUI widget objects - such as: - groupname. - -=head3 DESCRIPTION - - This internal method removes old tab widget saving its - relevant data into groupData and creates new selected table - to be shown. - -=cut - -#============================================================= -sub _groupDataTabWidget { - my ($self, $dialog, $replace_pnt, %groupData) = @_; - - my $factory = yui::YUI::widgetFactory; - - $dialog->startMultipleChanges(); - - $replace_pnt->deleteChildren(); - my $layout = $factory->createVBox($replace_pnt); - - my %groupDataWidget; - - ## user 'login name' - my $align = $factory->createRight($layout); - my $hbox = $factory->createHBox($align); - my $label = $factory->createLabel($hbox, N("Group Name:") ); - $groupDataWidget{groupname} = $factory->createInputField($hbox, "", 0); - $label->setWeight($yui::YD_HORIZ, 1); - $groupDataWidget{groupname}->setWeight($yui::YD_HORIZ, 2); - - $groupDataWidget{groupname}->setValue($groupData{groupname}); - - $replace_pnt->showChild(); - $dialog->recalcLayout(); - $dialog->doneMultipleChanges(); - - return %groupDataWidget; -} - - -sub _userAccountInfoTabWidget { - my ($self, $dialog, $replace_pnt, %userData) = @_; - - my $factory = yui::YUI::widgetFactory; - - $dialog->startMultipleChanges(); - - $replace_pnt->deleteChildren(); - my $layout = $factory->createVBox($replace_pnt); - - my %userAccountWidget; - $userAccountWidget{acc_check_exp} = $factory->createCheckBoxFrame($layout, N("Enable account expiration"), 1); - my $align = $factory->createRight($userAccountWidget{acc_check_exp}); - my $hbox = $factory->createHBox($align); - my $label = $factory->createLabel($hbox, N("Account expires (YYYY-MM-DD):")); - $userAccountWidget{acc_expy} = $factory->createIntField($hbox, "", 1970, 9999, $userData{acc_expy}); - $userAccountWidget{acc_expm} = $factory->createIntField($hbox, "", 1, 12, $userData{acc_expm}); - $userAccountWidget{acc_expd} = $factory->createIntField($hbox, "", 1, 31, $userData{acc_expd}); - $userAccountWidget{acc_check_exp}->setValue($userData{acc_check_exp}); - $label->setWeight($yui::YD_HORIZ, 2); - $align = $factory->createLeft($layout); - $userAccountWidget{lockuser} = $factory->createCheckBox($align, N("Lock User Account"), $userData{lockuser}); - - $align = $factory->createLeft($layout); - $hbox = $factory->createHBox($align); - $label = $factory->createLabel($hbox, N("Click on the icon to change it")); - $userAccountWidget{icon_face} = $factory->createPushButton($hbox, ""); - $userAccountWidget{icon_face}->setIcon(AdminPanel::Users::users::face2png($userData{icon_face})); - $userAccountWidget{icon_face}->setLabel($userData{icon_face}); - - $replace_pnt->showChild(); - $dialog->recalcLayout(); - $dialog->doneMultipleChanges(); - - return %userAccountWidget; -} - - -sub _userPasswordInfoTabWidget { - my ($self, $dialog, $replace_pnt, %userData) = @_; - - my $factory = yui::YUI::widgetFactory; - - $dialog->startMultipleChanges(); - - $replace_pnt->deleteChildren(); - my $layout = $factory->createVBox($replace_pnt); - - my %userPasswordWidget; - my $userEnt = $self->ctx->LookupUserByName($userData{username}); - my $lastchg = $userEnt->ShadowLastChange($self->USER_GetValue); - - my $align = $factory->createLeft($layout); - my $hbox = $factory->createHBox($align); - my $label = $factory->createLabel($hbox, N("User last changed password on: ")); - my $dayStr = $factory->createLabel($hbox, ""); - my $month = $factory->createLabel($hbox, ""); - my $dayInt = $factory->createLabel($hbox, ""); - my $year = $factory->createLabel($hbox, ""); - if ($lastchg) { - my $times = TimeOfArray($lastchg, 0); - $dayStr->setValue($times->{daystr}); - $month->setValue($times->{month}); - $dayInt->setValue($times->{dayint}); - $year->setValue($times->{year}); - } - - $userPasswordWidget{pwd_check_exp} = $factory->createCheckBoxFrame($layout, N("Enable Password Expiration"), 1); - $layout = $factory->createVBox($userPasswordWidget{pwd_check_exp}); - $align = $factory->createLeft($layout); - $hbox = $factory->createHBox($align); - $label = $factory->createLabel($hbox, N("Days before change allowed:")); - $userPasswordWidget{pwd_exp_min} = $factory->createInputField($hbox, "", 0); - $userPasswordWidget{pwd_exp_min}->setValue("$userData{pwd_exp_min}"); - $label->setWeight($yui::YD_HORIZ, 1); - $userPasswordWidget{pwd_exp_min}->setWeight($yui::YD_HORIZ, 2); - - $align = $factory->createLeft($layout); - $hbox = $factory->createHBox($align); - $label = $factory->createLabel($hbox, N("Days before change required:")); - $userPasswordWidget{pwd_exp_max} = $factory->createInputField($hbox, "", 0); - $userPasswordWidget{pwd_exp_max}->setValue("$userData{pwd_exp_max}"); - $label->setWeight($yui::YD_HORIZ, 1); - $userPasswordWidget{pwd_exp_max}->setWeight($yui::YD_HORIZ, 2); - - $align = $factory->createLeft($layout); - $hbox = $factory->createHBox($align); - $label = $factory->createLabel($hbox, N("Days warning before change:")); - $userPasswordWidget{pwd_exp_warn} = $factory->createInputField($hbox, "", 0); - $userPasswordWidget{pwd_exp_warn}->setValue("$userData{pwd_exp_warn}"); - $label->setWeight($yui::YD_HORIZ, 1); - $userPasswordWidget{pwd_exp_warn}->setWeight($yui::YD_HORIZ, 2); - - $align = $factory->createLeft($layout); - $hbox = $factory->createHBox($align); - $label = $factory->createLabel($hbox, N("Days before account inactive:")); - $userPasswordWidget{pwd_exp_inact} = $factory->createInputField($hbox, "", 0); - $userPasswordWidget{pwd_exp_inact}->setValue("$userData{pwd_exp_inact}"); - $label->setWeight($yui::YD_HORIZ, 1); - $userPasswordWidget{pwd_exp_inact}->setWeight($yui::YD_HORIZ, 2); - - $userPasswordWidget{pwd_check_exp}->setValue($userData{pwd_check_exp}); - - $replace_pnt->showChild(); - $dialog->recalcLayout(); - $dialog->doneMultipleChanges(); - - return %userPasswordWidget; -} - -sub _groupUsersTabWidget { - my ($self, $dialog, $replace_pnt, %groupData) = @_; - - my $factory = yui::YUI::widgetFactory; - my $mageiaPlugin = "mga"; - my $mgaFactory = yui::YExternalWidgets::externalWidgetFactory($mageiaPlugin); - $mgaFactory = yui::YMGAWidgetFactory::getYMGAWidgetFactory($mgaFactory); - - $dialog->startMultipleChanges(); - - $replace_pnt->deleteChildren(); - - my %groupUsersWidget; - - my $layout = labeledFrameBox($replace_pnt, N("Select the users to join this group:")); - - my $yTableHeader = new yui::YTableHeader(); - $yTableHeader->addColumn("", $yui::YAlignBegin); - $yTableHeader->addColumn(N("User"), $yui::YAlignBegin); - - $groupUsersWidget{members} = $mgaFactory->createCBTable($layout, $yTableHeader, $yui::YCBTableCheckBoxOnFirstColumn); - - my $groupEnt = $self->ctx->LookupGroupByName($groupData{groupname}); - my $users = $self->ctx->UsersEnumerate; - my @susers = sort(@$users); - - my $itemCollection = new yui::YItemCollection; - my $members = $groupData{members}; - foreach my $user (@susers) { - my $item = new yui::YCBTableItem($user); - $item->check(member($user, @$members)); - $item->setLabel($user); - $itemCollection->push($item); - $item->DISOWN(); - } - $groupUsersWidget{members}->addItems($itemCollection); - - $replace_pnt->showChild(); - $dialog->recalcLayout(); - $dialog->doneMultipleChanges(); - - return %groupUsersWidget; -} - -sub _userGroupsTabWidget { - my ($self, $dialog, $replace_pnt, %userData) = @_; - - my $factory = yui::YUI::widgetFactory; - my $mageiaPlugin = "mga"; - my $mgaFactory = yui::YExternalWidgets::externalWidgetFactory($mageiaPlugin); - $mgaFactory = yui::YMGAWidgetFactory::getYMGAWidgetFactory($mgaFactory); - - $dialog->startMultipleChanges(); - - $replace_pnt->deleteChildren(); - - my %userGroupsWidget; - my $userEnt = $self->ctx->LookupUserByName($userData{username}); - my $lastchg = $userEnt->ShadowLastChange($self->USER_GetValue); - - my $layout = labeledFrameBox($replace_pnt, N("Select groups that the user will be member of:")); - - my $yTableHeader = new yui::YTableHeader(); - $yTableHeader->addColumn("", $yui::YAlignBegin); - $yTableHeader->addColumn(N("Group"), $yui::YAlignBegin); - - $userGroupsWidget{members} = $mgaFactory->createCBTable($layout, $yTableHeader, $yui::YCBTableCheckBoxOnFirstColumn); - - my $grps = $self->ctx->GroupsEnumerate; - my @sgroups = sort @$grps; - - my $itemCollection = new yui::YItemCollection; - my $members = $userData{members}; - foreach my $group (@sgroups) { - my $item = new yui::YCBTableItem($group); - $item->check(member($group, @$members)); - $item->setLabel($group); - $itemCollection->push($item); - $item->DISOWN(); - } - $userGroupsWidget{members}->addItems($itemCollection); - $userGroupsWidget{members}->setNotify(1); - my $primgroup = ''; - if ($userData{primary_group} != -1) { - my $Gent = $self->ctx->LookupGroupById($userData{primary_group}); - $primgroup = $Gent->GroupName($self->USER_GetValue); - } - - my $align = $factory->createLeft($layout); - my $hbox = $factory->createHBox($align); - my $label = $factory->createLabel($hbox, N("Primary Group")); - $userGroupsWidget{primary_group} = $factory->createComboBox($hbox, "", 0); - my $itemColl = new yui::YItemCollection; - foreach my $member (@$members) { - my $item = new yui::YItem ($member, 0); - $item->setSelected(1) if ($item->label() eq $primgroup); - $itemColl->push($item); - $item->DISOWN(); - } - $userGroupsWidget{primary_group}->addItems($itemColl); - $label->setWeight($yui::YD_HORIZ, 1); - $userGroupsWidget{primary_group}->setWeight($yui::YD_HORIZ, 2); - - $replace_pnt->showChild(); - $dialog->recalcLayout(); - $dialog->doneMultipleChanges(); - - return %userGroupsWidget; -} - -sub _groupEdit_Ok { - my ($self, %groupData) = @_; - - # update last changes if any - %groupData = $self->_storeDataFromGroupEditPreviousTab(%groupData); - - my ($continue, $errorString) = valid_groupname($groupData{groupname}); - if (!$continue) { - AdminPanel::Shared::msgBox($errorString) if ($errorString); - return $continue; - } - my $groupEnt = $self->ctx->LookupGroupByName($groupData{start_groupname}); - if ($groupData{start_groupname} ne $groupData{groupname}) { - $groupEnt->GroupName($groupData{groupname}); - } - - my $members = $groupData{members}; - my $gid = $groupEnt->Gid($self->USER_GetValue); - my $users = $self->ctx->UsersEnumerate; - my @susers = sort(@$users); - - foreach my $user (@susers) { - my $uEnt = $self->ctx->LookupGroupByName($user); - if ($uEnt) { - my $ugid = $uEnt->Gid($self->USER_GetValue); - my $m = $self->ctx->EnumerateUsersByGroup($groupData{start_groupname}); - if (member($user, @$members)) { - if (!$self->_inArray($user, $m)) { - if ($ugid != $gid) { - eval { $groupEnt->MemberName($user,1) }; - } - } - } - else { - if ($self->_inArray($user, $m)) { - if ($ugid == $gid) { - AdminPanel::Shared::msgBox(N("You cannot remove user '%s' from their primary group", $user)); - return 0; - } - else { - eval { $groupEnt->MemberName($user,2) }; - } - } - } - } - } - - $self->ctx->GroupModify($groupEnt); - $self->_refresh(); - - return 1; -} - -sub _userEdit_Ok { - my ($self, %userData) = @_; - - # update last changes if any - %userData = $self->_storeDataFromUserEditPreviousTab(%userData); - - my ($continue, $errorString) = valid_username($userData{username}); - if (!$continue) { - AdminPanel::Shared::msgBox($errorString) if ($errorString); - return $continue; - } - - if ( $userData{password} ne $userData{password1}) { - AdminPanel::Shared::msgBox(N("Password Mismatch")); - return 0; - } - my $userEnt = $self->ctx->LookupUserByName($userData{username}); - if ($userData{password} ne '') { - my $sec = security::level::get(); - if ($sec > 3 && length($userData{password}) < 6) { - AdminPanel::Shared::msgBox(N("This password is too simple. \n Good passwords should be > 6 characters")); - return 0; - } - $self->ctx->UserSetPass($userEnt, $userData{password}); - } - - $userEnt->UserName($userData{username}); - $userEnt->Gecos($userData{full_name}); - $userEnt->HomeDir($userData{homedir}); - $userEnt->LoginShell($userData{shell}); - my $username = $userEnt->UserName($self->USER_GetValue); - my $grps = $self->ctx->GroupsEnumerate; - my @sgroups = sort @$grps; - - my $members = $userData{members}; - foreach my $group (@sgroups) { - - my $gEnt = $self->ctx->LookupGroupByName($group); - my $ugid = $gEnt->Gid($self->USER_GetValue); - my $m = $gEnt->MemberName(1,0); - if (member($group, @$members)) { - if (!$self->_inArray($username, $m) && $userData{primary_group} != $ugid) { - eval { $gEnt->MemberName($username, 1) }; - $self->ctx->GroupModify($gEnt); - } - } - else { - if ($self->_inArray($username, $m)) { - eval { $gEnt->MemberName($username, 2) }; - $self->ctx->GroupModify($gEnt); - } - } - } - if ($userData{primary_group} == -1) { - AdminPanel::Shared::msgBox(N("Please select at least one group for the user")); - return 0; - } - $userEnt->Gid($userData{primary_group}); - - if ($userData{acc_check_exp}) { - my $yr = $userData{acc_expy}; - my $mo = $userData{acc_expm}; - my $dy = $userData{acc_expd}; - if (!ValidInt($yr, $dy, $mo)) { - AdminPanel::Shared::msgBox(N("Please specify Year, Month and Day \n for Account Expiration ")); - return 0; - } - my $Exp = ConvTime($dy, $mo, $yr); - $userEnt->ShadowExpire($Exp); - } - else { - $userEnt->ShadowExpire(ceil(-1)) - } - - if ($userData{pwd_check_exp}) { - my $allowed = int($userData{pwd_exp_min}); - my $required = int($userData{pwd_exp_max}); - my $warning = int($userData{pwd_exp_warn}); - my $inactive = int($userData{pwd_exp_inact}); - if ($allowed && $required && $warning && $inactive) { - $userEnt->ShadowMin($allowed); - $userEnt->ShadowMax($required); - $userEnt->ShadowWarn($warning); - $userEnt->ShadowInact($inactive); - } - else { - AdminPanel::Shared::msgBox(N("Please fill up all fields in password aging\n")); - return 0; - } - } - else { - $userEnt->ShadowMin(-1); - $userEnt->ShadowMax(99999); - $userEnt->ShadowWarn(-1); - $userEnt->ShadowInact(-1); - } - - $self->ctx->UserModify($userEnt); - - if ($userData{lockuser}) { - !$self->ctx->IsLocked($userEnt) and $self->ctx->Lock($userEnt); - } - else { - $self->ctx->IsLocked($userEnt) and $self->ctx->UnLock($userEnt); - } - - defined $userData{icon_face} and AdminPanel::Users::users::addKdmIcon($userData{username}, $userData{icon_face}); - $self->_refresh(); - - return 1; -} - - - -sub _editUserDialog { - my $self = shift; - - my $dontcreatehomedir = 0; - my $is_system = 0; - - ## push application title - my $appTitle = yui::YUI::app()->applicationTitle(); - ## set new title to get it in dialog - yui::YUI::app()->setApplicationTitle(N("Edit User")); - - my $factory = yui::YUI::widgetFactory; - my $optional = yui::YUI::optionalWidgetFactory; - - my $dlg = $factory->createPopupDialog(); - my $layout = $factory->createVBox($dlg); - - my %tabs; - if ($optional->hasDumbTab()) { - my $hbox = $factory->createHBox($layout); - my $align = $factory->createHCenter($hbox); - $tabs{widget} = $optional->createDumbTab($align); - - $tabs{user_data} = new yui::YItem($userEditLabel{user_data}); - $tabs{user_data}->setSelected(); - $tabs{used} = $tabs{user_data}->label(); - $tabs{widget}->addItem( $tabs{user_data} ); - $tabs{user_data}->DISOWN(); - - $tabs{account_info} = new yui::YItem($userEditLabel{account_info}); - $tabs{widget}->addItem( $tabs{account_info} ); - $tabs{account_info}->DISOWN(); - - $tabs{password_info} = new yui::YItem($userEditLabel{password_info}); - $tabs{widget}->addItem( $tabs{password_info} ); - $tabs{password_info}->DISOWN(); - - $tabs{groups} = new yui::YItem($userEditLabel{groups}); - $tabs{widget}->addItem( $tabs{groups} ); - $tabs{groups}->DISOWN(); - - my $vbox = $factory->createVBox($tabs{widget}); - $align = $factory->createLeft($vbox); - $tabs{replace_pnt} = $factory->createReplacePoint($align); - - $hbox = $factory->createHBox($vbox); - $align = $factory->createRight($hbox); - my $cancelButton = $factory->createPushButton($align, N("Cancel")); - my $okButton = $factory->createPushButton($hbox, N("Ok")); - - my %userData = $self->_getUserInfo(); - # userData here should be tested because it could be undef - - # Useful entry point for the current edit user/group tab widget - $self->set_edit_tab_widget( $self->_userDataTabWidget($dlg, $tabs{replace_pnt}, %userData) ); - $self->set_edit_tab_widget( edit_tab_label => $userEditLabel{user_data}); - - while(1) { - my $event = $dlg->waitForEvent(); - my $eventType = $event->eventType(); - - #event type checking - if ($eventType == $yui::YEvent::CancelEvent) { - last; - } - elsif ($eventType == $yui::YEvent::MenuEvent) { - ### MENU ### - my $item = $event->item(); - if ($item->label() eq $tabs{user_data}->label()) { - %userData = $self->_storeDataFromUserEditPreviousTab(%userData); - my %edit_tab = $self->_userDataTabWidget($dlg, $tabs{replace_pnt}, %userData ); - $self->edit_tab_widgets( {} ); - $self->set_edit_tab_widget(%edit_tab); - $self->set_edit_tab_widget( edit_tab_label => $userEditLabel{user_data}); - } - elsif ($item->label() eq $tabs{account_info}->label()) { - %userData = $self->_storeDataFromUserEditPreviousTab(%userData); - my %edit_tab = $self->_userAccountInfoTabWidget($dlg, $tabs{replace_pnt}, %userData ); - $self->edit_tab_widgets( {} ); - $self->set_edit_tab_widget(%edit_tab); - $self->set_edit_tab_widget( edit_tab_label => $userEditLabel{account_info}); - } - elsif ($item->label() eq $tabs{password_info}->label()) { - %userData = $self->_storeDataFromUserEditPreviousTab(%userData); - my %edit_tab = $self->_userPasswordInfoTabWidget($dlg, $tabs{replace_pnt}, %userData ); - $self->edit_tab_widgets( {} ); - $self->set_edit_tab_widget(%edit_tab); - $self->set_edit_tab_widget( edit_tab_label => $userEditLabel{password_info}); - } - elsif ($item->label() eq $tabs{groups}->label()) { - %userData = $self->_storeDataFromUserEditPreviousTab(%userData); - my %edit_tab = $self->_userGroupsTabWidget($dlg, $tabs{replace_pnt}, %userData ); - $self->edit_tab_widgets( {} ); - $self->set_edit_tab_widget(%edit_tab); - $self->set_edit_tab_widget( edit_tab_label => $userEditLabel{groups}); - } - } - elsif ($eventType == $yui::YEvent::WidgetEvent) { - ### widget - my $widget = $event->widget(); - if ($widget == $cancelButton) { - last; - } - elsif ($widget == $okButton) { - ## save changes - if ($self->_userEdit_Ok(%userData)) { - last; - } - } -# last: managing tab widget events - else { - my $current_tab = $self->get_edit_tab_widget('edit_tab_label'); - if ($current_tab && $current_tab eq $userEditLabel{account_info}) { - if ($widget == $self->get_edit_tab_widget('icon_face')) { - my $iconLabel = $self->_skipShortcut($self->get_edit_tab_widget('icon_face')->label()); - my $nextIcon = GetFaceIcon($iconLabel, 1); - $self->get_edit_tab_widget('icon_face')->setLabel($nextIcon); - $self->get_edit_tab_widget('icon_face')->setIcon(AdminPanel::Users::users::face2png($nextIcon)); - } - } - elsif ($current_tab && $current_tab eq $userEditLabel{groups}) { - if ($widget == $self->get_edit_tab_widget('members')) { - my $item = $self->get_edit_tab_widget('members')->changedItem(); - if ($item) { - if ($item->checked()) { - # add it to possible primary groups - my $pgItem = new yui::YItem ($item->label(), 0); - $self->get_edit_tab_widget('primary_group')->addItem($pgItem); - } - else { - # remove it to possible primary groups - $dlg->startMultipleChanges(); - my $itemColl = new yui::YItemCollection; - my $tbl = $self->get_edit_tab_widget('members'); - for(my $i=0;$i < $tbl->itemsCount();$i++) { - if ($tbl->toCBYTableItem($tbl->item($i))->checked()) { - my $pgItem = new yui::YItem ($tbl->item($i)->label(), 0); - my $Gent = $self->ctx->LookupGroupById($userData{primary_group}); - my $primgroup = $Gent->GroupName($self->USER_GetValue); - $pgItem->setSelected(1) if ($pgItem->label() eq $primgroup); - - $itemColl->push($pgItem); - $pgItem->DISOWN(); - } - } - $self->get_edit_tab_widget('primary_group')->deleteAllItems(); - $self->get_edit_tab_widget('primary_group')->addItems($itemColl); - $dlg->recalcLayout(); - $dlg->doneMultipleChanges(); - } - } - } - } - } - } - } - - } - else { - AdminPanel::Shared::warningMsgBox(N("Cannot create tab widgets")); - } - - destroy $dlg; - - #restore old application title - yui::YUI::app()->setApplicationTitle($appTitle); - -} - -sub _editGroupDialog { - my $self = shift; - - ## push application title - my $appTitle = yui::YUI::app()->applicationTitle(); - ## set new title to get it in dialog - yui::YUI::app()->setApplicationTitle(N("Edit Group")); - - my $factory = yui::YUI::widgetFactory; - my $optional = yui::YUI::optionalWidgetFactory; - - my $dlg = $factory->createPopupDialog(); - my $layout = $factory->createVBox($dlg); - - my %tabs; - if ($optional->hasDumbTab()) { - my $hbox = $factory->createHBox($layout); - my $align = $factory->createHCenter($hbox); - $tabs{widget} = $optional->createDumbTab($align); - - $tabs{group_data} = new yui::YItem($groupEditLabel{group_data}); - $tabs{group_data}->setSelected(); - $tabs{widget}->addItem( $tabs{group_data} ); - $tabs{group_data}->DISOWN(); - - $tabs{group_users} = new yui::YItem($groupEditLabel{group_users}); - $tabs{widget}->addItem( $tabs{group_users} ); - $tabs{group_users}->DISOWN(); - - my $vbox = $factory->createVBox($tabs{widget}); - $align = $factory->createLeft($vbox); - $tabs{replace_pnt} = $factory->createReplacePoint($align); - - $hbox = $factory->createHBox($vbox); - $align = $factory->createRight($hbox); - my $cancelButton = $factory->createPushButton($align, N("Cancel")); - my $okButton = $factory->createPushButton($hbox, N("Ok")); - - my %groupData = $self->_getGroupInfo(); - # groupData here should be tested because it could be undef - -# %groupData: selected group info as: -# $groupname: group name -# $members: users that are members of this group - - - # Useful entry point for the current edit user/group tab widget - $self->set_edit_tab_widget( $self->_groupDataTabWidget($dlg, $tabs{replace_pnt}, %groupData) ); - $self->set_edit_tab_widget( edit_tab_label => $groupEditLabel{group_data}); - - while(1) { - my $event = $dlg->waitForEvent(); - my $eventType = $event->eventType(); - - #event type checking - if ($eventType == $yui::YEvent::CancelEvent) { - last; - } - elsif ($eventType == $yui::YEvent::MenuEvent) { - ### MENU ### - my $item = $event->item(); - if ($item->label() eq $tabs{group_data}->label()) { - %groupData = $self->_storeDataFromGroupEditPreviousTab(%groupData); - my %edit_tab = $self->_groupDataTabWidget($dlg, $tabs{replace_pnt}, %groupData ); - $self->edit_tab_widgets( {} ); - $self->set_edit_tab_widget(%edit_tab); - $self->set_edit_tab_widget( edit_tab_label => $groupEditLabel{group_data}); - } - elsif ($item->label() eq $tabs{group_users}->label()) { - %groupData = $self->_storeDataFromGroupEditPreviousTab(%groupData); - my %edit_tab = $self->_groupUsersTabWidget($dlg, $tabs{replace_pnt}, %groupData ); - $self->edit_tab_widgets( {} ); - $self->set_edit_tab_widget(%edit_tab); - $self->set_edit_tab_widget( edit_tab_label => $groupEditLabel{group_users}); - } - } - elsif ($eventType == $yui::YEvent::WidgetEvent) { - ### widget - my $widget = $event->widget(); - if ($widget == $cancelButton) { - last; - } - elsif ($widget == $okButton) { - ## save changes - if ($self->_groupEdit_Ok(%groupData)) { - last; - } - } - } - } - - } - else { - AdminPanel::Shared::warningMsgBox(N("Cannot create tab widgets")); - } - - destroy $dlg; - - #restore old application title - yui::YUI::app()->setApplicationTitle($appTitle); - -} - -sub _editUserOrGroup { - my $self = shift; - - # TODO item management avoid label if possible - my $label = $self->_skipShortcut($self->get_widget('tabs')->selectedItem()->label()); - if ($label eq N("Users") ) { - $self->_editUserDialog(); - } - else { - $self->_editGroupDialog(); - } - $self->_refresh(); -} - - -sub _deleteUserOrGroup { - my $self = shift; - - # TODO item management avoid label if possible - my $label = $self->_skipShortcut($self->get_widget('tabs')->selectedItem()->label()); - if ($label eq N("Users") ) { - $self->_deleteUserDialog(); - $self->_refresh(); - } - else { - $self->_deleteGroupDialog(); - $self->_refresh(); - } -} - - -sub _refresh { - my $self = shift; - - # TODO item management avoid label if possible - my $label = $self->_skipShortcut($self->get_widget('tabs')->selectedItem()->label()); - if ($label eq N("Users") ) { - $self->_refreshUsers(); - } - else { - $self->_refreshGroups(); - } -# TODO xguest -# RefreshXguest(1); -} - -# TODO context menu creation is missed in libyui -sub _contextMenuActions { - my $self = shift; - - my $item = $self->get_widget('table')->selectedItem(); - if ($item) { - } -} - -sub _refreshActions { - my $self = shift; - - my $item = $self->get_widget('table')->selectedItem(); - $self->dialog->startMultipleChanges(); - $self->get_widget('action_menu')->deleteAllItems(); - - # do we need to undef them first? - $self->set_action_menu( - add_user => undef, - add_group => undef, - edit => undef, - del => undef, - inst => undef, - ); - $self->set_action_menu( - add_user => new yui::YMenuItem(N("Add User")), - add_group => new yui::YMenuItem(N("Add Group")), - edit => new yui::YMenuItem(N("&Edit")), - del => new yui::YMenuItem(N("&Delete")), - inst => new yui::YMenuItem(N("Install guest account")), - ); - - my $itemColl = new yui::YItemCollection; - for my $pair ( $self->action_menu_pairs ) { - my $menuItem = $pair->[1]; - if ($pair->[0] eq 'edit' || $pair->[0] eq 'del') { - if ($item) { - $itemColl->push($menuItem); - } - } - else { - $itemColl->push($menuItem); - } - $menuItem->DISOWN(); - } - $self->get_widget('action_menu')->addItems($itemColl); - $self->get_widget('action_menu')->rebuildMenuTree(); - if ($item) { - $self->get_widget('edit')->setEnabled(); - $self->get_widget('del')->setEnabled(); - } - else { - $self->get_widget('edit')->setDisabled(); - $self->get_widget('del')->setDisabled(); - } - - $self->dialog->doneMultipleChanges(); -} - - -sub manageUsersDialog { - my $self = shift; - - ## TODO fix for adminpanel - my $pixdir = '/usr/share/userdrake/pixmaps/'; - ## push application title - my $appTitle = yui::YUI::app()->applicationTitle(); - - ## set new title to get it in dialog - yui::YUI::app()->setApplicationTitle($self->name); - ## set icon if not already set by external launcher - yui::YUI::app()->setApplicationIcon($self->icon); - - - my $factory = yui::YUI::widgetFactory; - my $optional = yui::YUI::optionalWidgetFactory; - - - $self->dialog($factory->createMainDialog()); - my $layout = $factory->createVBox($self->dialog); - - my $hbox_headbar = $factory->createHBox($layout); - 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,N("File")), - refresh => new yui::YMenuItem(N("Refresh")), - quit => new yui::YMenuItem(N("&Quit")), - ); - - $fileMenu{ widget }->addItem($fileMenu{ refresh }); - $fileMenu{ widget }->addItem($fileMenu{ quit }); - $fileMenu{ widget }->rebuildMenuTree(); - - my $actionMenu = $factory->createMenuButton($headbar, N("Actions")); - $actionMenu->DISOWN(); - - my %helpMenu = ( - widget => $factory->createMenuButton($headRight, N("&Help")), - help => new yui::YMenuItem(N("Help")), - report_bug => new yui::YMenuItem(N("Report Bug")), - about => new yui::YMenuItem(N("&About")), - ); - - while ( my ($key, $value) = each(%helpMenu) ) { - if ($key ne 'widget' ) { - $helpMenu{ widget }->addItem($value); - } - } - $helpMenu{ widget }->rebuildMenuTree(); - - my $hbox = $factory->createHBox($layout); - $hbox = $factory->createHBox($factory->createLeft($hbox)); - $self->set_widget( - add_user => $factory->createIconButton($hbox, $pixdir . 'user_add.png', N("Add User")), - add_group => $factory->createIconButton($hbox, $pixdir . 'group_add.png', N("Add Group")), - edit => $factory->createIconButton($hbox, $pixdir . 'user_conf.png', N("Edit")), - del => $factory->createIconButton($hbox, $pixdir . 'user_del.png', N("Delete")), - refresh => $factory->createIconButton($hbox, $pixdir . 'refresh.png', N("Refresh")), - action_menu => $actionMenu, - ); - - - $hbox = $factory->createHBox($layout); - $head_align_left = $factory->createLeft($hbox); - $self->set_widget(filter_system => $factory->createCheckBox($head_align_left, N("Filter system users"), 1)); - $factory->createHSpacing($hbox, 3); - $head_align_right = $factory->createRight($hbox); - $headRight = $factory->createHBox($head_align_right); - $factory->createLabel($headRight, N("Search:")); - $self->set_widget(filter => $factory->createInputField($headRight, "", 0)); - $self->set_widget(apply_filter => $factory->createPushButton($headRight, N("Apply filter"))); - $self->get_widget('filter')->setWeight($yui::YD_HORIZ, 2); - $self->get_widget('apply_filter')->setWeight($yui::YD_HORIZ, 1); - $self->get_widget('filter_system')->setNotify(1); - - my %tabs; - if ($optional->hasDumbTab()) { - $hbox = $factory->createHBox($layout); - my $align = $factory->createHCenter($hbox); - $self->set_widget(tabs => $optional->createDumbTab($align)); - $tabs{users} = new yui::YItem(N("Users")); - $tabs{users}->setSelected(); - $self->get_widget('tabs')->addItem( $tabs{users} ); - $tabs{users}->DISOWN(); - $tabs{groups} = new yui::YItem(N("Groups")); - $self->get_widget('tabs')->addItem( $tabs{groups} ); - $tabs{groups}->DISOWN(); - my $vbox = $factory->createVBox($self->get_widget('tabs')); - $align = $factory->createLeft($vbox); - $self->set_widget(replace_pnt => $factory->createReplacePoint($align)); - $self->_createUserTable(); - $self->get_widget('table')->setImmediateMode(1); - $self->get_widget('table')->DISOWN(); - } - - $self->_refreshActions(); - - # main loop - while(1) { - my $event = $self->dialog->waitForEvent(); - my $eventType = $event->eventType(); - - #event type checking - if ($eventType == $yui::YEvent::CancelEvent) { - last; - } - elsif ($eventType == $yui::YEvent::MenuEvent) { -### MENU ### - my $item = $event->item(); - my $menuLabel = $item->label(); - if ($menuLabel eq $fileMenu{ quit }->label()) { - last; - } - elsif ($menuLabel eq $helpMenu{about}->label()) { - my $license = translate($AdminPanel::Shared::License); - AboutDialog({ name => N("AdminUser"), - version => $self->VERSION, - copyright => N("Copyright (C) %s Mageia community", '2013-2014'), - license => $license, - comments => N("AdminUser is a Mageia user management tool \n(from the original idea of Mandriva userdrake)."), - website => 'http://www.mageia.org', - website_label => N("Mageia"), - authors => "Angelo Naselli \nMatteo Pasotti ", - translator_credits => - #-PO: put here name(s) and email(s) of translator(s) (eg: "John Smith ") - N("_: Translator(s) name(s) & email(s)\n")} - ); - } - elsif ($menuLabel eq $self->get_action_menu('add_user')->label()) { - $self->addUserDialog(); - $self->_refresh(); - } - elsif ($menuLabel eq $self->get_action_menu('add_group')->label()) { - $self->_addGroupDialog(); - $self->_refresh(); - } - elsif ($menuLabel eq $self->get_action_menu('del')->label()) { - $self->_deleteUserOrGroup(); - } - elsif ($menuLabel eq $self->get_action_menu('edit')->label()) { - $self->_editUserOrGroup(); - } - elsif ($self->get_widget('tabs') && $menuLabel eq $tabs{groups}->label()) { - $self->_createGroupTable(); - } - elsif ($self->get_widget('tabs') && $menuLabel eq $tabs{users}->label()) { - $self->_createUserTable(); - } - elsif ($menuLabel eq $fileMenu{refresh}->label()) { - $self->_refresh(); - } - } - elsif ($eventType == $yui::YEvent::WidgetEvent) { -### Buttons and widgets ### - my $widget = $event->widget(); - if ($widget == $self->get_widget('add_user')) { - $self->addUserDialog(); - $self->_refresh(); - } - elsif ($widget == $self->get_widget('del')) { - $self->_deleteUserOrGroup(); - } - elsif ($widget == $self->get_widget('table')) { - $self->_refreshActions(); - my $wEvent = yui::YMGAWidgetFactory::getYWidgetEvent($event); - if ($wEvent && $wEvent->reason() == $yui::YEvent::Activated) { - $self->_editUserOrGroup(); - } - } - elsif ($widget == $self->get_widget('add_group')) { - $self->_addGroupDialog(); - $self->_refresh(); - } - elsif ($widget == $self->get_widget('edit')) { - $self->_editUserOrGroup(); - } - elsif ( $widget == $self->get_widget('filter_system') || - $widget == $self->get_widget('refresh') || - $widget == $self->get_widget('apply_filter') ) { - $self->_refresh(); - } - } - } - - $self->dialog->destroy() ; - - #restore old application title - yui::YUI::app()->setApplicationTitle($appTitle) if $appTitle; -} - -#============================================================= - -=head2 _skipShortcut - -=head3 INPUT - - $self: this object - $label: an item label to be cleaned by keyboard shortcut "&" - -=head3 OUTPUT - - $label: cleaned label - -=head3 DESCRIPTION - - This internal method is a workaround to label that are - changed by "&" due to keyborad shortcut. - -=cut - -#============================================================= -sub _skipShortcut { - my ($self, $label) = @_; - - $label =~ s/&// if ($label); - - return ($label); -} - -#============================================================= - -=head2 _inArray - -=head3 INPUT - - $self: this object - $item: item to search - $arr: array container - -=head3 OUTPUT - - true: if the array contains the item - -=head3 DESCRIPTION - -This method returns if an item is into the array container - -=cut - -#============================================================= -sub _inArray { - my ($self, $item, $arr) = @_; - - return grep( /^$item$/, @$arr ); -} - - -sub ValidInt { - foreach my $i (@_) { $i =~ /\d+/ or return 0 } - return 1; -} - -sub ConvTime { - my ($day, $month, $year) = @_; - my ($tm, $days, $mon, $yr); - $mon = $month - 1; $yr = $year - 1900; - $tm = POSIX::mktime(0, 0, 0, $day, $mon, $yr); - $days = ceil($tm / (24 * 60 * 60)); - return $days; -} - -sub TimeOfArray { - my ($reltime, $cm) = @_; - my $h; my %mth = (Jan => 1, Feb => 2, Mar => 3, Apr => 4, May => 5, Jun => 6, Jul => 7, Aug => 8, Sep => 9, Oct => 10, Nov => 11, Dec => 12); - my $_t = localtime($reltime * 24 * 60 * 60) =~ /(\S+)\s+(\S+)\s+(\d+)\s+(\S+)\s+(\d+)/; - $h->{daystr} = $1; - $h->{month} = $2; - $h->{dayint} = $3; - $h->{year} = $5; - $cm and $h->{month} = $mth{$2}; - $h; -} - - -no Moose; -__PACKAGE__->meta->make_immutable; - -1; diff --git a/AdminPanel/Users/adminUser.conf b/AdminPanel/Users/adminUser.conf deleted file mode 100644 index cf8bd636..00000000 --- a/AdminPanel/Users/adminUser.conf +++ /dev/null @@ -1,10 +0,0 @@ - - - - System - /usr/share/icons/system_section.png - - AdminPanel::Users::GUsers - - - diff --git a/AdminPanel/Users/users.pm b/AdminPanel/Users/users.pm deleted file mode 100644 index 2f90b7ce..00000000 --- a/AdminPanel/Users/users.pm +++ /dev/null @@ -1,126 +0,0 @@ -package AdminPanel::Users::users; - -use diagnostics; -use strict; - -#-###################################################################################### -#- misc imports -#-###################################################################################### -use common; - -use run_program; - -use base qw(Exporter); - -our @EXPORT = qw( - facesdir - face2png - facenames - addKdmIcon - valid_username - valid_groupname - GetFaceIcon - Add2UsersGroup - ); - -sub facesdir() { - "$::prefix/usr/share/mga/faces/"; -} -sub face2png { - my ($face) = @_; - facesdir() . $face . ".png"; -} -sub facenames() { - my $dir = facesdir(); - my @l = grep { /^[A-Z]/ } all($dir); - map { if_(/(.*)\.png/, $1) } (@l ? @l : all($dir)); -} - -sub addKdmIcon { - my ($user, $icon) = @_; - my $dest = "$::prefix/usr/share/faces/$user.png"; - eval { cp_af(facesdir() . $icon . ".png", $dest) } if $icon; -} - - -sub valid { - return (0, N("Name field is empty please provide a name")) if (!$_[0] ); - - $_[0] =~ /^[a-z]+?[a-z0-9_\-\.]*?$/ or do { - return (0, N("The name must contain only lower cased latin letters, numbers, `.', `-' and `_'")); - }; - return (0, N("Name is too long")) if (! (length($_[0]) <= $_[1])); - return (1, N("Ok")); -} - -sub valid_username { - return valid($_[0], 32); -} - -sub valid_groupname { - return valid($_[0], 16); -} - -################################################## -## GetFaceIcon -## params -## -## 'name' icon name for the given name -## 'next' get next icon from the given 'name' -## -## return -## 'user_icon' icon name -## -sub GetFaceIcon { - my ($name, $next) = @_; - my @icons = facenames(); - my $i; - my $current_icon; - # remove shortcut "&" from label - $name =~ s/&// if ($name); - my $user_icon = "$::prefix/usr/share/faces/$name.png" if ($name); - if ($name) { - $user_icon = face2png($name) unless(-e $user_icon); - } - if ($name && -e $user_icon) { - my $current_md5 = common::md5file($user_icon); - eval { $i = find_index { common::md5file(face2png($_)) eq $current_md5 } @icons }; - if (!$@) { #- current icon found in @icons, select it - $current_icon = $icons[$i]; - } else { #- add and select current icon in @icons - push @icons, $user_icon; - $current_icon = $user_icon; - $i = @icons - 1; - } - } else { - #- no icon yet, select a random one - $current_icon = $icons[$i = rand(@icons)]; - } - - if ($next) { - $current_icon = $icons[$i = defined $icons[$i+1] ? $i+1 : 0]; - } - return $current_icon; -} - -################################################## -## Add2UsersGroup -## params -## -## 'name' username -## 'ctx' USER::ADMIN object -## -## return -## gid group id -## -sub Add2UsersGroup { - my ($name, $ctx) = @_; - my $GetValue = -65533; ## Used by USER (for getting values? TODO need explanations, where?) - - my $usersgroup = $ctx->LookupGroupByName('users'); - $usersgroup->MemberName($name, 1); - return $usersgroup->Gid($GetValue); -} - - -1; diff --git a/AdminPanel/rpmdragora.pm b/AdminPanel/rpmdragora.pm deleted file mode 100644 index b96ed53d..00000000 --- a/AdminPanel/rpmdragora.pm +++ /dev/null @@ -1,984 +0,0 @@ -# vim: set et ts=4 sw=4: -#***************************************************************************** -# -# Copyright (c) 2002 Guillaume Cottenceau -# Copyright (c) 2002-2007 Thierry Vignaud -# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA -# Copyright (c) 2005, 2007 Mandriva SA -# Copyright (c) 2013 Matteo Pasotti -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2, as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -#***************************************************************************** -# -# $Id: rpmdragora.pm 267936 2010-04-26 16:40:21Z jvictor $ - -package AdminPanel::rpmdragora; - -use lib qw(/usr/lib/libDrakX); -use urpm::download (); -use urpm::prompt; -use urpm::media; - -use MDK::Common; -use MDK::Common::System; -use urpm; -use urpm::cfg; -use URPM; -use URPM::Resolve; -use strict; -use c; -use POSIX qw(_exit); -use common; -use Locale::gettext; -use feature 'state'; - -use AdminPanel::Shared; - -our @ISA = qw(Exporter); -our $VERSION = '2.27'; -our @EXPORT = qw( - $changelog_first_config - $compute_updates - $filter - $dont_show_selections - $ignore_debug_media - $mandrakeupdate_wanted_categories - $mandrivaupdate_height - $mandrivaupdate_width - $max_info_in_descr - $mode - $NVR_searches - $offered_to_add_sources - $rpmdragora_height - $rpmdragora_width - $tree_flat - $tree_mode - $use_regexp - $typical_width - $clean_cache - $auto_select - add_distrib_update_media - add_medium_and_check - but - but_ - check_update_media_version - choose_mirror - distro_type - fatal_msg - getbanner - get_icon - interactive_list - interactive_list_ - interactive_msg - interactive_packtable - myexit - readconf - remove_wait_msg - run_drakbug - show_urpm_progress - slow_func - slow_func_statusbar - statusbar_msg - statusbar_msg_remove - strip_first_underscore - update_sources - update_sources_check - update_sources_interactive - update_sources_noninteractive - wait_msg - warn_for_network_need - writeconf -); -our $typical_width = 280; - -our $dont_show_selections; - -# i18n: IMPORTANT: to get correct namespace (rpmdragora instead of libDrakX) -BEGIN { unshift @::textdomains, qw(rpmdragora urpmi rpm-summary-main rpm-summary-contrib rpm-summary-devel rpm-summary-non-free) } - -use yui; -use Glib; -#ugtk2::add_icon_path('/usr/share/rpmdragora/icons'); - -Locale::gettext::bind_textdomain_codeset('rpmdragora', 'UTF8'); - -our $mageia_release = cat_( - -e '/etc/mageia-release' ? '/etc/mageia-release' : '/etc/release' -) || ''; -chomp $mageia_release; -our ($distro_version) = $mageia_release =~ /(\d+\.\d+)/; -our ($branded, %distrib); -$branded = -f '/etc/sysconfig/oem' - and %distrib = MDK::Common::System::distrib(); -our $myname_update = $branded ? N_("Software Update") : N_("Mageia Update"); - -@rpmdragora::prompt::ISA = 'urpm::prompt'; - -sub rpmdragora::prompt::prompt { - my ($self) = @_; - my @answers; - my $d = ugtk2->new("", grab => 1, if_($::main_window, transient => $::main_window)); - $d->{rwindow}->set_position('center_on_parent'); - gtkadd( - $d->{window}, - gtkpack( - Gtk2::VBox->new(0, 5), - Gtk2::WrappedLabel->new($self->{title}), - (map { gtkpack( - Gtk2::HBox->new(0, 5), - Gtk2::Label->new($self->{prompts}[$_]), - $answers[$_] = gtkset_visibility(gtkentry(), !$self->{hidden}[$_]), - ) } 0 .. $#{$self->{prompts}}), - gtksignal_connect(Gtk2::Button->new(N("Ok")), clicked => sub { Gtk2->main_quit }), - ), - ); - $d->main; - map { $_->get_text } @answers; -} - -$urpm::download::PROMPT_PROXY = new rpmdragora::prompt( - N_("Please enter your credentials for accessing proxy\n"), - [ N_("User name:"), N_("Password:") ], - undef, - [ 0, 1 ], -); - -sub myexit { - writeconf(); - #ugtk2::exit(undef, @_); -} - -my ($root) = grep { $_->[2] == 0 } list_passwd(); -$ENV{HOME} = $> == 0 ? $root->[7] : $ENV{HOME} || '/root'; -$ENV{HOME} = $::env if $::env = $Rpmdragora::init::rpmdragora_options{env}[0]; - -our $configfile = "$ENV{HOME}/.rpmdragora"; - -# -# Configuration File Options -# - -# clear download cache after successfull installation of packages -our $clean_cache; - -# automatic select dependencies without user intervention -our $auto_select; - -our ($changelog_first_config, $compute_updates, $filter, $max_info_in_descr, $mode, $NVR_searches, $tree_flat, $tree_mode, $use_regexp); -our ($mandrakeupdate_wanted_categories, $ignore_debug_media, $offered_to_add_sources, $no_confirmation); -our ($rpmdragora_height, $rpmdragora_width, $mandrivaupdate_height, $mandrivaupdate_width); - -our %config = ( - clean_cache => { - var => \$clean_cache, - default => [ 0 ] - }, - auto_select => { - var => \$auto_select, - default => [ 0 ] - }, - changelog_first_config => { var => \$changelog_first_config, default => [ 0 ] }, - compute_updates => { var => \$compute_updates, default => [ 1 ] }, - dont_show_selections => { var => \$dont_show_selections, default => [ $> ? 1 : 0 ] }, - filter => { var => \$filter, default => [ 'all' ] }, - ignore_debug_media => { var => \$ignore_debug_media, default => [ 0 ] }, - mandrakeupdate_wanted_categories => { var => \$mandrakeupdate_wanted_categories, default => [ qw(security) ] }, - mandrivaupdate_height => { var => \$mandrivaupdate_height, default => [ 0 ] }, - mandrivaupdate_width => { var => \$mandrivaupdate_width, default => [ 0 ] }, - max_info_in_descr => { var => \$max_info_in_descr, default => [] }, - mode => { var => \$mode, default => [ 'by_group' ] }, - NVR_searches => { var => \$NVR_searches, default => [ 0 ] }, - 'no-confirmation' => { var => \$no_confirmation, default => [ 0 ] }, - offered_to_add_sources => { var => \$offered_to_add_sources, default => [ 0 ] }, - rpmdragora_height => { var => \$rpmdragora_height, default => [ 0 ] }, - rpmdragora_width => { var => \$rpmdragora_width, default => [ 0 ] }, - tree_flat => { var => \$tree_flat, default => [ 0 ] }, - tree_mode => { var => \$tree_mode, default => [ qw(gui_pkgs) ] }, - use_regexp => { var => \$use_regexp, default => [ 0 ] }, -); - -sub readconf() { - ${$config{$_}{var}} = $config{$_}{default} foreach keys %config; - foreach my $l (cat_($configfile)) { - foreach (keys %config) { - ${$config{$_}{var}} = [ split ' ', $1 ] if $l =~ /^\Q$_\E(.*)/; - } - } - # special cases: - $::rpmdragora_options{'no-confirmation'} = $no_confirmation->[0] if !defined $::rpmdragora_options{'no-confirmation'}; - $Rpmdragora::init::default_list_mode = $tree_mode->[0] if ref $tree_mode && !$Rpmdragora::init::overriding_config; -} - -sub writeconf() { - return if $::env; - unlink $configfile; - - # special case: - $no_confirmation->[0] = $::rpmdragora_options{'no-confirmation'}; - - output($configfile, map { "$_ " . (ref ${$config{$_}{var}} ? join(' ', @${$config{$_}{var}}) : undef) . "\n" } keys %config); -} - -sub getbanner() { - $::MODE or return undef; - if (0) { - +{ - remove => N("Software Packages Removal"), - update => N("Software Packages Update"), - install => N("Software Packages Installation"), - }; - } -# Gtk2::Banner->new($ugtk2::wm_icon, $::MODE eq 'update' ? N("Software Packages Update") : N("Software Management")); -} - -# return value: -# - undef if if closed (aka really canceled) -# - 0 if if No/Cancel -# - 1 if if Yes/Ok -sub interactive_msg { - my ($title, $contents, %options) = @_; - return ask_YesOrNo($title, $contents); -=comment - $options{transient} ||= $::main_window if $::main_window; - local $::isEmbedded; - my $factory = yui::YUI::widgetFactory; - my $d = $factory->createPopupDialog(); - - my $d = ugtk2->new($title, grab => 1, if_(exists $options{transient}, transient => $options{transient})); - $d->{rwindow}->set_position($options{transient} ? 'center_on_parent' : 'center_always'); - if ($options{scroll}) { - $contents = ugtk2::markup_to_TextView_format($contents) if !ref $contents; - } else { #- because we'll use a WrappedLabel - $contents = formatAlaTeX($contents) if !ref $contents; - } - - my $button_yes; - my $vbox = $factory->createVBox($d); - my $text_w = $factory->createMultiLineEdit($vbox, ""); - my $hbox = $factory->createHBox($vbox); - - ref($options{yesno}) eq 'ARRAY' ? map {ss - my $label = $_; - my $button_yes = $factory->createIconButton($hbox,"",$label); - } @{$options{yesno}} - : ( - $options{yesno} ? ( - my $button_no = $factory->createIconButton($hbox, "", $options{text}{no} || N("No")); - $button_yes = $factory->createIconButton($hbox,"", $options{text}{yes} || N("Yes")); - ) - : $button_yes = $factory->createIconButton($hbox,"",N("Ok")); - ) - - #$d->{window}->set_focus($button_yes); - #$text_w->set_size_request($typical_width*2, $options{scroll} ? 300 : -1); - #$d->main; - return $d->{retval}; -=cut -} - -sub interactive_packtable { - my ($title, $parent_window, $top_label, $lines, $action_buttons) = @_; - - my $w = ugtk2->new($title, grab => 1, transient => $parent_window); - local $::main_window = $w->{real_window}; - $w->{rwindow}->set_position($parent_window ? 'center_on_parent' : 'center'); - my $packtable = create_packtable({}, @$lines); - - gtkadd($w->{window}, - gtkpack_(Gtk2::VBox->new(0, 5), - if_($top_label, 0, Gtk2::Label->new($top_label)), - 1, create_scrolled_window($packtable), - 0, gtkpack__(create_hbox(), @$action_buttons))); - my $preq = $packtable->size_request; - my ($xpreq, $ypreq) = ($preq->width, $preq->height); - my $wreq = $w->{rwindow}->size_request; - my ($xwreq, $ywreq) = ($wreq->width, $wreq->height); - $w->{rwindow}->set_default_size(max($typical_width, min($typical_width*2.5, $xpreq+$xwreq)), - max(200, min(450, $ypreq+$ywreq))); - $w->main; -} - -sub interactive_list { - my ($title, $contents, $list, $callback, %options) = @_; - - my $factory = yui::YUI::widgetFactory; - my $mainw = $factory->createPopupDialog(); - my $vbox = $factory->createVBox($mainw); - my $lbltitle = $factory->createLabel($vbox, N("Dependencies")); - my $radiobuttongroup = $factory->createRadioButtonGroup($vbox); - my $rbbox = $factory->createVBox($radiobuttongroup); - foreach my $item(@$list){ - my $radiobutton = $factory->createRadioButton($rbbox,$item); - $radiobutton->setNotify(0); - $radiobuttongroup->addRadioButton($radiobutton); - } - my $submitButton = $factory->createIconButton($vbox,"", N("OK")); - my $choice; - - while(1) { - my $event = $mainw->waitForEvent(); - my $eventType = $event->eventType(); - #event type checking - if ($eventType == $yui::YEvent::CancelEvent) { - $mainw->destroy(); - last; - } - elsif ($eventType == $yui::YEvent::WidgetEvent) { - # widget selected - my $widget = $event->widget(); - - if($widget == $submitButton) { - $choice = $radiobuttongroup->currentButton->label(); - $choice =~s/\&//g; - last; - } - } - } - $mainw->destroy(); - return $choice; -} - -sub interactive_list_ { interactive_list(@_, if_($::main_window, transient => $::main_window)) } - -sub fatal_msg { - interactive_msg @_; - myexit -1; -} - -sub wait_msg { - my ($msg, %options) = @_; - #OLD my $mainw = ugtk2->new(N("Please wait"), grab => 1, if_(exists $options{transient}, transient => $options{transient})); - #$mainw->{real_window}->set_position($options{transient} ? 'center_on_parent' : 'center_always'); - #my $label = $factory->createLabel($vbox, $msg); - #OLD my $label = ref($msg) =~ /^Gtk/ ? $msg : Gtk2::WrappedLabel->new($msg); - #gtkadd( - #$mainw->{window}, - #gtkpack__( - # gtkset_border_width(Gtk2::VBox->new(0, 5), 6), - # $label, - # if_(exists $options{widgets}, @{$options{widgets}}), - #) - #); - my $factory = yui::YUI::widgetFactory; - my $mainw = $factory->createPopupDialog(); - my $vbox = $factory->createVBox($mainw); - my $title = $factory->createLabel($vbox, N("Please wait")); - #$mainw->recalcLayout(); - #$mainw->doneMultipleChanges(); - $mainw->pollEvent(); - #$mainw->recalcLayout(); - #$mainw->doneMultipleChanges(); - $mainw; -} - -sub remove_wait_msg { - my $w = shift; - #gtkset_mousecursor_normal($w->{rwindow}->window); - $w->destroy; -} - -sub but { " $_[0] " } -sub but_ { " $_[0] " } - -sub slow_func ($&) { - my ($param, $func) = @_; - if (ref($param) =~ /^Gtk/) { - #gtkset_mousecursor_wait($param); - #ugtk2::flush(); - #$func->(); - #gtkset_mousecursor_normal($param); - } else { - my $w = wait_msg($param); - $func->(); - remove_wait_msg($w); - } -} - -sub statusbar_msg { - unless ($::statusbar) { #- fallback if no status bar - if (defined &::wait_msg_) { goto &::wait_msg_ } else { goto &wait_msg } - } - my ($msg, $o_timeout) = @_; - $::statusbar->setText($msg); - #- always use the same context description for now - #my $cx = $::statusbar->get_context_id("foo"); - #$::w and $::w->{rwindow} and gtkset_mousecursor_wait($::w->{rwindow}->window); - #- returns a msg_id to be passed optionnally to statusbar_msg_remove - #my $id = $::statusbar->push($cx, $msg); - #gtkflush(); - #Glib::Timeout->add(5000, sub { statusbar_msg_remove($id); 0 }) if $o_timeout; - Glib::Timeout->add(5000, sub { statusbar_msg_remove(); 0 }) if $o_timeout; - #$id; -} - -sub statusbar_msg_remove { - #my ($msg_id) = @_; - #if (!$::statusbar || ref $msg_id) { #- fallback if no status bar - #goto &remove_wait_msg; - #} - #my $cx = $::statusbar->get_context_id("foo"); - #if (defined $msg_id) { - #$::statusbar->remove($cx, $msg_id); - #} else { - #$::statusbar->pop($cx); - #} - #$::w and $::w->{rwindow} and gtkset_mousecursor_normal($::w->{rwindow}->window); - $::statusbar->setValue(""); -} - -sub slow_func_statusbar ($$&) { - my ($msg, $w, $func) = @_; - gtkset_mousecursor_wait($w->window); - my $msg_id = statusbar_msg($msg); - gtkflush(); - $func->(); - statusbar_msg_remove($msg_id); - gtkset_mousecursor_normal($w->window); -} - -my %u2l = ( - at => N_("Austria"), - au => N_("Australia"), - be => N_("Belgium"), - br => N_("Brazil"), - ca => N_("Canada"), - ch => N_("Switzerland"), - cr => N_("Costa Rica"), - cz => N_("Czech Republic"), - de => N_("Germany"), - dk => N_("Danmark"), - el => N_("Greece"), - es => N_("Spain"), - fi => N_("Finland"), - fr => N_("France"), - gr => N_("Greece"), - hu => N_("Hungary"), - il => N_("Israel"), - it => N_("Italy"), - jp => N_("Japan"), - ko => N_("Korea"), - nl => N_("Netherlands"), - no => N_("Norway"), - pl => N_("Poland"), - pt => N_("Portugal"), - ru => N_("Russia"), - se => N_("Sweden"), - sg => N_("Singapore"), - sk => N_("Slovakia"), - tw => N_("Taiwan"), - uk => N_("United Kingdom"), - cn => N_("China"), - com => N_("United States"), - org => N_("United States"), - net => N_("United States"), - edu => N_("United States"), - ); -my $us = [ qw(com org net edu) ]; -my %t2l = ( - 'America/\w+' => $us, - 'Asia/Tel_Aviv' => [ qw(il ru it cz at de fr se) ], - 'Asia/Tokyo' => [ qw(jp ko tw), @$us ], - 'Asia/Seoul' => [ qw(ko jp tw), @$us ], - 'Asia/Taipei' => [ qw(tw jp), @$us ], - 'Asia/(Shanghai|Beijing)' => [ qw(cn tw sg), @$us ], - 'Asia/Singapore' => [ qw(cn sg), @$us ], - 'Atlantic/Reykjavik' => [ qw(uk no se fi dk), @$us, qw(nl de fr at cz it) ], - 'Australia/\w+' => [ qw(au jp ko tw), @$us ], - 'Brazil/\w+' => [ 'br', @$us ], - 'Canada/\w+' => [ 'ca', @$us ], - 'Europe/Amsterdam' => [ qw(nl be de at cz fr se dk it) ], - 'Europe/Athens' => [ qw(gr pl cz de it nl at fr) ], - 'Europe/Berlin' => [ qw(de be at nl cz it fr se) ], - 'Europe/Brussels' => [ qw(be de nl fr cz at it se) ], - 'Europe/Budapest' => [ qw(cz it at de fr nl se) ], - 'Europe/Copenhagen' => [ qw(dk nl de be se at cz it) ], - 'Europe/Dublin' => [ qw(uk fr be nl dk se cz it) ], - 'Europe/Helsinki' => [ qw(fi se no nl be de fr at it) ], - 'Europe/Istanbul' => [ qw(il ru it cz it at de fr nl se) ], - 'Europe/Lisbon' => [ qw(pt es fr it cz at de se) ], - 'Europe/London' => [ qw(uk fr be nl de at cz se it) ], - 'Europe/Madrid' => [ qw(es fr pt it cz at de se) ], - 'Europe/Moscow' => [ qw(ru de pl cz at se be fr it) ], - 'Europe/Oslo' => [ qw(no se fi dk de be at cz it) ], - 'Europe/Paris' => [ qw(fr be de at cz nl it se) ], - 'Europe/Prague' => [ qw(cz it at de fr nl se) ], - 'Europe/Rome' => [ qw(it fr cz de at nl se) ], - 'Europe/Stockholm' => [ qw(se no dk fi nl de at cz fr it) ], - 'Europe/Vienna' => [ qw(at de cz it fr nl se) ], - ); - -#- get distrib release number (2006.0, etc) -sub etc_version() { - (my $v) = split / /, cat_('/etc/version'); - return $v; -} - -#- returns the keyword describing the type of the distribution. -#- the parameter indicates whether we want base or update sources -sub distro_type { - my ($want_base_distro) = @_; - return 'cauldron' if $mageia_release =~ /cauldron/i; - #- we can't use updates for community while official is not out (release ends in ".0") - if ($want_base_distro || $mageia_release =~ /community/i && etc_version() =~ /\.0$/) { - return 'official' if $mageia_release =~ /official|limited/i; - return 'community' if $mageia_release =~ /community/i; - #- unknown: fallback to updates - } - return 'updates'; -} - -sub compat_arch_for_updates($) { - # FIXME: We prefer 64-bit packages to update on biarch platforms, - # since the system is populated with 64-bit packages anyway. - my ($arch) = @_; - return $arch =~ /x86_64|amd64/ if arch() eq 'x86_64'; - MDK::Common::System::compat_arch($arch); -} - -sub mirrors { - my ($urpm, $want_base_distro) = @_; - my $cachedir = $urpm->{cachedir} || '/root'; - require mirror; - mirror::register_downloader( - sub { - my ($url) = @_; - my $file = $url; - $file =~ s!.*/!$cachedir/!; - unlink $file; # prevent "partial file" errors - before_leaving(sub { unlink $file }); - - my ($gurpm, $id, $canceled); - # display a message in statusbar (if availlable): - $::statusbar and $id = statusbar_msg( - $branded - ? N("Please wait, downloading mirror addresses.") - : N("Please wait, downloading mirror addresses from the Mageia website."), - 0); - my $_clean_guard = before_leaving { - undef $gurpm; - $id and statusbar_msg_remove($id); - }; - - require Rpmdragora::gurpm; - require Rpmdragora::pkg; - - my $res = urpm::download::sync_url($urpm, $url, - dir => $cachedir, - callback => sub { - $gurpm ||= - Rpmdragora::gurpm->new(N("Please wait"), - transient => $::main_window); - $canceled ||= - !Rpmdragora::pkg::download_callback($gurpm, @_); - gtkflush(); - }, - ); - $res or die N("retrieval of [%s] failed", $file) . "\n"; - return $canceled ? () : cat_($file); - }); - my @mirrors = @{ mirror::list(common::parse_LDAP_namespace_structure(cat_('/etc/product.id')), 'distrib') || [] }; - require timezone; - my $tz = ${timezone::read()}{timezone}; - foreach my $mirror (@mirrors) { - my $goodness; - each_index { $_ = $u2l{$_} || $_; $_ eq $mirror->{country} and $goodness ||= 100-$::i } (map { if_($tz =~ /^$_$/, @{$t2l{$_}}) } keys %t2l), @$us; - $mirror->{goodness} = $goodness + rand(); - $mirror->{country} = translate($mirror->{country}); - } - unless (-x '/usr/bin/rsync') { - @mirrors = grep { $_->{url} !~ /^rsync:/ } @mirrors; - } - return sort { $b->{goodness} <=> $a->{goodness} } @mirrors; -} - -sub warn_for_network_need { - my ($message, %options) = @_; - $message ||= -$branded -? N("I need to access internet to get the mirror list. -Please check that your network is currently running. - -Is it ok to continue?") -: N("I need to contact the Mageia website to get the mirror list. -Please check that your network is currently running. - -Is it ok to continue?"); - interactive_msg(N("Mirror choice"), $message, yesno => 1, %options) or return ''; -} - -sub choose_mirror { - my ($urpm, %options) = @_; - delete $options{message}; - my @transient_options = exists $options{transient} ? (transient => $options{transient}) : (); - warn_for_network_need($options{message}, %options) or return; - my @mirrors = eval { mirrors($urpm, $options{want_base_distro}) }; - my $error = $@; - if ($error) { - $error = "\n$error\n"; - interactive_msg(N("Error during download"), -($branded -? N("There was an error downloading the mirror list: - -%s -The network, or the website, may be unavailable. -Please try again later.", $error) -: N("There was an error downloading the mirror list: - -%s -The network, or the Mageia website, may be unavailable. -Please try again later.", $error)), %options - - ); - return ''; - } - - !@mirrors and interactive_msg(N("No mirror"), -($branded -? N("I can't find any suitable mirror.") -: N("I can't find any suitable mirror. - -There can be many reasons for this problem; the most frequent is -the case when the architecture of your processor is not supported -by Mageia Official Updates.")), %options - ), return ''; - - my $w = ugtk2->new(N("Mirror choice"), grab => 1, @transient_options); - $w->{rwindow}->set_position($options{transient} ? 'center_on_parent' : 'center_always'); - my $tree_model = Gtk2::TreeStore->new("Glib::String"); - my $tree = Gtk2::TreeView->new_with_model($tree_model); - $tree->get_selection->set_mode('browse'); - $tree->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, text => 0)); - $tree->set_headers_visible(0); - - gtkadd( - $w->{window}, - gtkpack_( - Gtk2::VBox->new(0,5), - 0, N("Please choose the desired mirror."), - 1, create_scrolled_window($tree), - 0, gtkpack( - create_hbox('edge'), - map { - my $retv = $_->[1]; - gtksignal_connect( - Gtk2::Button->new(but($_->[0])), - clicked => sub { - if ($retv) { - my ($model, $iter) = $tree->get_selection->get_selected; - $model and $w->{retval} = { sel => $model->get($iter, 0) }; - } - Gtk2->main_quit; - }, - ); - } [ N("Cancel"), 0 ], [ N("Ok"), 1 ] - ), - ) - ); - my %roots; - $tree_model->append_set($roots{$_->{country}} ||= $tree_model->append_set(undef, [ 0 => $_->{country} ]), - [ 0 => $_->{url} ]) foreach @mirrors; - - $w->{window}->set_size_request(500, 400); - $w->{rwindow}->show_all; - - my $path = Gtk2::TreePath->new_first; - $tree->expand_row($path, 0); - $path->down; - $tree->get_selection->select_path($path); - - $w->main && return grep { $w->{retval}{sel} eq $_->{url} } @mirrors; -} - -sub show_urpm_progress { - my ($label, $pb, $mode, $file, $percent, $total, $eta, $speed) = @_; - $file =~ s|([^:]*://[^/:\@]*:)[^/:\@]*(\@.*)|$1xxxx$2|; #- if needed... - state $medium; - if ($mode eq 'copy') { - $pb->set_fraction(0); - $label->set_label(N("Copying file for medium `%s'...", $file)); - } elsif ($mode eq 'parse') { - $pb->set_fraction(0); - $label->set_label(N("Examining file of medium `%s'...", $file)); - } elsif ($mode eq 'retrieve') { - $pb->set_fraction(0); - $label->set_label(N("Examining remote file of medium `%s'...", $file)); - $medium = $file; - } elsif ($mode eq 'done') { - $pb->set_fraction(1.0); - $label->set_label($label->get_label . N(" done.")); - $medium = undef; - } elsif ($mode eq 'failed') { - $pb->set_fraction(1.0); - $label->set_label($label->get_label . N(" failed!")); - $medium = undef; - } else { - # FIXME: we're displaying misplaced quotes such as "downloading `foobar from 'medium Main Updates'ยด" - $file = $medium && length($file) < 40 ? #-PO: We're downloading the said file from the said medium - N("%s from medium %s", basename($file), $medium) - : basename($file); - if ($mode eq 'start') { - $pb->set_fraction(0); - $label->set_label(N("Starting download of `%s'...", $file)); - } elsif ($mode eq 'progress') { - if (defined $total && defined $eta) { - $pb->set_fraction($percent/100); - $label->set_label(N("Download of `%s'\ntime to go:%s, speed:%s", $file, $eta, $speed)); - } else { - $pb->set_fraction($percent/100); - $label->set_label(N("Download of `%s'\nspeed:%s", $file, $speed)); - } - } - } - Gtk2->main_iteration while Gtk2->events_pending; -} - -sub update_sources { - my ($urpm, %options) = @_; - my $cancel = 0; - my $w; my $label; $w = wait_msg( - $label = Gtk2::Label->new(N("Please wait, updating media...")), - no_wait_cursor => 1, - widgets => [ - my $pb = gtkset_size_request(Gtk2::ProgressBar->new, 300, -1), - gtkpack( - create_hbox(), - gtksignal_connect( - Gtk2::Button->new(N("Cancel")), - clicked => sub { - $cancel = 1; - $urpm->{error}->(N("Canceled")); - $w and $w->destroy; - }, - ), - ), - ], - ); - my @media; @media = @{$options{medialist}} if ref $options{medialist}; - my $outerfatal = $urpm->{fatal}; - local $urpm->{fatal} = sub { $w->destroy; $outerfatal->(@_) }; - urpm::media::update_those_media($urpm, [ urpm::media::select_media_by_name($urpm, \@media) ], - %options, allow_failures => 1, - callback => sub { - $cancel and goto cancel_update; - my ($type, $media) = @_; - return if $type !~ /^(?:start|progress|end)$/ && @media && !member($media, @media); - if ($type eq 'failed') { - $urpm->{fatal}->(N("Error retrieving packages"), -N("It's impossible to retrieve the list of new packages from the media -`%s'. Either this update media is misconfigured, and in this case -you should use the Software Media Manager to remove it and re-add it in order -to reconfigure it, either it is currently unreachable and you should retry -later.", - $media)); - } else { - show_urpm_progress($label, $pb, @_); - } - }, - ); - $w->destroy; - cancel_update: -} - -sub update_sources_check { - my ($urpm, $options, $error_msg, @media) = @_; - my @error_msgs; - local $urpm->{fatal} = sub { push @error_msgs, $_[1]; goto fatal_error }; - local $urpm->{error} = sub { push @error_msgs, $_[0] }; - update_sources($urpm, %$options, noclean => 1, medialist => \@media); - fatal_error: - if (@error_msgs) { - interactive_msg(N("Error"), sprintf(translate($error_msg), join("\n", map { formatAlaTeX($_) } @error_msgs)), scroll => 1); - return 0; - } - return 1; -} - -sub update_sources_interactive { - my ($urpm, %options) = @_; - my $w = ugtk2->new(N("Update media"), grab => 1, center => 1, %options); - $w->{rwindow}->set_position($options{transient} ? 'center_on_parent' : 'center_always'); - my @buttons; - my @media = grep { ! $_->{ignore} } @{$urpm->{media}}; - unless (@media) { - interactive_msg(N("Warning"), N("No active medium found. You must enable some media to be able to update them.")); - return 0; - } - gtkadd( - $w->{window}, - gtkpack_( - 0, Gtk2::VBox->new(0,5), - 0, Gtk2::Label->new(N("Select the media you wish to update:")), - 1, gtknew('ScrolledWindow', height => 300, child => - # FIXME: using a listview would be just better: - gtknew('VBox', spacing => 5, children_tight => [ - @buttons = map { - Gtk2::CheckButton->new_with_label($_->{name}); - } @media - ]) - ), - 0, Gtk2::HSeparator->new, - 0, gtkpack( - create_hbox(), - gtksignal_connect( - Gtk2::Button->new(N("Cancel")), - clicked => sub { $w->{retval} = 0; Gtk2->main_quit }, - ), - gtksignal_connect( - Gtk2::Button->new(N("Select all")), - clicked => sub { $_->set_active(1) foreach @buttons }, - ), - gtksignal_connect( - Gtk2::Button->new(N("Update")), - clicked => sub { - $w->{retval} = any { $_->get_active } @buttons; - # list of media listed in the checkbox panel - my @buttonmedia = grep { !$_->{ignore} } @{$urpm->{media}}; - @media = map_index { if_($_->get_active, $buttonmedia[$::i]{name}) } @buttons; - Gtk2->main_quit; - }, - ), - ) - ) - ); - if ($w->main) { - return update_sources_noninteractive($urpm, \@media, %options); - } - return 0; -} - -sub update_sources_noninteractive { - my ($urpm, $media, %options) = @_; - - urpm::media::select_media($urpm, @$media); - update_sources_check( - $urpm, - {}, - N_("Unable to update medium; it will be automatically disabled.\n\nErrors:\n%s"), - @$media, - ); - return 1; -} - -sub add_medium_and_check { - my ($urpm, $options) = splice @_, 0, 2; - my @newnames = ($_[0]); #- names of added media - my $fatal_msg; - my @error_msgs; - local $urpm->{fatal} = sub { printf STDERR "Fatal: %s\n", $_[1]; $fatal_msg = $_[1]; goto fatal_error }; - local $urpm->{error} = sub { printf STDERR "Error: %s\n", $_[0]; push @error_msgs, $_[0] }; - if ($options->{distrib}) { - @newnames = urpm::media::add_distrib_media($urpm, @_); - } else { - urpm::media::add_medium($urpm, @_); - } - if (@error_msgs) { - interactive_msg( - N("Error"), - N("Unable to add medium, errors reported:\n\n%s", - join("\n", map { formatAlaTeX($_) } @error_msgs)) . "\n\n" . N("Medium: ") . "$_[0] ($_[1])", - scroll => 1, - ); - return 0; - } - - foreach my $name (@newnames) { - urpm::download::set_proxy_config($_, $options->{proxy}{$_}, $name) foreach keys %{$options->{proxy} || {}}; - } - - if (update_sources_check($urpm, $options, N_("Unable to add medium, errors reported:\n\n%s"), @newnames)) { - urpm::media::write_config($urpm); - $options->{proxy} and urpm::download::dump_proxy_config(); - } else { - urpm::media::read_config($urpm, 0); - return 0; - } - - my %newnames; @newnames{@newnames} = (); - if (any { exists $newnames{$_->{name}} } @{$urpm->{media}}) { - return 1; - } else { - interactive_msg(N("Error"), N("Unable to create medium.")); - return 0; - } - - fatal_error: - interactive_msg(N("Failure when adding medium"), - N("There was a problem adding medium:\n\n%s", $fatal_msg)); - return 0; -} - -#- Check whether the default update media (added by installation) -#- matches the current mdk version -sub check_update_media_version { - my $urpm = shift; - foreach (@_) { - if ($_->{name} =~ /(\d+\.\d+).*\bftp\du\b/ && $1 ne $distro_version) { - interactive_msg( - N("Warning"), - $branded - ? N("Your medium `%s', used for updates, does not match the version of %s you're running (%s). -It will be disabled.", - $_->{name}, $distrib{system}, $distrib{product}) - : N("Your medium `%s', used for updates, does not match the version of Mageia you're running (%s). -It will be disabled.", - $_->{name}, $distro_version) - ); - $_->{ignore} = 1; - urpm::media::write_config($urpm) if -w $urpm->{config}; - return 0; - } - } - 1; -} - -sub add_distrib_update_media { - my ($urpm, $mirror, %options) = @_; - #- ensure a unique medium name - my $medium_name = $rpmdragora::mageia_release =~ /(\d+\.\d+) \((\w+)\)/ ? $2 . $1 . '-' : 'distrib'; - my $initial_number = 1 + max map { $_->{name} =~ /\(\Q$medium_name\E(\d+)\b/ ? $1 : 0 } @{$urpm->{media}}; - add_medium_and_check( - $urpm, - { nolock => 1, distrib => 1 }, - $medium_name, - ($mirror ? $mirror->{url} : (undef, mirrorlist => '$MIRRORLIST')), - probe_with => 'synthesis', initial_number => $initial_number, %options, - usedistrib => 1, - ); -} - -sub open_help { - my ($mode) = @_; - use run_program; - run_program::raw({ detach => 1, as_user => 1 }, 'drakhelp', '--id', $mode ? "software-management-$mode" : 'software-management'); - my $_s = N("Help launched in background"); - statusbar_msg(N("The help window has been started, it should appear shortly on your desktop."), 1); -} - -sub run_drakbug { - my ($id) = @_; - run_program::raw({ detach => 1, as_user => 1 }, 'drakbug', '--report', $id); -} - -#mygtk2::add_icon_path('/usr/share/mcc/themes/default/'); -sub get_icon { - my ($mcc_icon, $fallback_icon) = @_; - my $icon = eval { mygtk2::_find_imgfile($mcc_icon) }; - $icon ||= eval { mygtk2::_find_imgfile($fallback_icon) }; - $icon; -} - -sub strip_first_underscore { join '', map { s/_//; $_ } @_ } - -1; diff --git a/Category.pm b/Category.pm deleted file mode 100644 index b43a4c1a..00000000 --- a/Category.pm +++ /dev/null @@ -1,201 +0,0 @@ -# vim: set et ts=4 sw=4: -# Copyright 2012 Steven Tucker -# -# This file is part of AdminPanel -# -# AdminPanel is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# AdminPanel is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with AdminPanel. If not, see . - - -#Class Category -package Category; - -use strict; -use warnings; -use diagnostics; -use yui; - -## Can only add the config file data at constructor -## The Gui elements are added in setupGui inside MainDisplay -sub new { - my ($class, $newName, $newIcon) = @_; - my $self = { - my $name = 0, - my $button = 0, - my $icon = 0, - my $modules = 0 - }; - bless $self, 'Category'; - - $self->{name} = $newName; - $self->{icon} = $newIcon; - - return $self; -} - -## Add a new module to the list -#============================================================= - -=head2 loadModule - -=head3 INPUT - - $self: this object - $module: module to add - -=head3 OUTPUT - - 1: if the module has been added - 0: otherwise - -=head3 DESCRIPTION - - This method adds a module to the loaded - modules if it is not already in. - -=cut - -#============================================================= -sub loadModule { - my ($self, $module) = @_; - - if (!$self->moduleLoaded($module->{name})) { - push ( @{$self->{modules}}, $module ); - - return 1; - } - return 0; -} - -#============================================================= - -=head2 moduleLoaded - -=head3 INPUT - - $self: this object - $module_name or -CLASS => name : module/CLASS name to look for - -=head3 OUTPUT - - $present: module present or not - -=head3 DESCRIPTION - - This method looks for the given module and if already in - returns true. -=cut - -#============================================================= -sub moduleLoaded { - my $self = shift; - my (%params) = @_; - my ($module_name) = @_; - - my $present = 0; - - if (!$module_name) { - return $present; - } - - foreach my $mod (@{$self->{modules}}) { - if (exists $params{-CLASS} && ref($mod) eq $params{-CLASS}) { - $present = 1; - last; - } - elsif ($mod->{name} eq $module_name) { - $present = 1; - last; - } - } - - return $present; -} - -## Create and add buttons for each module -sub addButtons { - my($self, $pane, $factory) = @_; - my $count = 0; - my $tmpButton; - my $currLayout = 0; - $factory->createVSpacing($pane, 2); - foreach my $mod (@{$self->{modules}}) { - if(($count % 2) != 1) { - $currLayout = $factory->createHBox($pane); - $factory->createHStretch($currLayout); - } - $count++; - $tmpButton = $factory->createPushButton($currLayout, - $mod->name); - $mod->setButton($tmpButton); - $tmpButton->setLabel($mod->name); - $tmpButton->setIcon($mod->icon); - $factory->createHStretch($currLayout); - if(($count % 2) != 1) { - $factory->createVSpacing($pane, 2); - } - } - $factory->createVStretch($pane); -} - -## Delete the module buttons -sub removeButtons { - my($self) = @_; - - for(@{$self->{modules}}) { - $_->removeButton(); - } -} - -sub setIcon { - my($self) = @_; - - $self->{button}->setIcon($self->{icon}); -} - -1; -__END__ - -=pod - -=head1 NAME - - Category - add new category to window - -=head1 SYNOPSIS - - $category = new Category('Category Name'); - - -=head1 USAGE - - my $display = new MainDisplay(); - - my $category = new Category('Network'); - $display->loadCategory($category); - - $display->start(); - -=head1 FUNCTIONS - -=head2 new (name) - - Constructor: creates a new category named Name - - $category = new Category('Name'); - -=head3 name (String) - - The name of the category - -=cut diff --git a/Changes b/Changes new file mode 100644 index 00000000..a970b737 --- /dev/null +++ b/Changes @@ -0,0 +1,5 @@ +Revision history for AdminPanel-Shared + +0.01 Date/time + First version, released on an unsuspecting world. + diff --git a/ConfigReader.pm b/ConfigReader.pm deleted file mode 100644 index d5ec8b1b..00000000 --- a/ConfigReader.pm +++ /dev/null @@ -1,119 +0,0 @@ -# vim: set et ts=4 sw=4: -# Copyright 2012 Steven Tucker -# -# This file is part of AdminPanel -# -# AdminPanel is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# AdminPanel is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with AdminPanel. If not, see . - - -#Class ConfigReader -package ConfigReader; - -use strict; -use warnings; -use diagnostics; -use XML::Simple; -use Data::Dumper; - -sub new { - my ($class, $fileName) = @_; - - my $self = { - my $data = 0, - my $catLen = 0, - my $currCat = 0, - my $modLen = 0, - my $currMod = 0, - my $placeHolder = 0 - }; - bless $self, 'ConfigReader'; - - my $xml = new XML::Simple (KeyAttr=>[]); - $self->{data} = $xml->XMLin($fileName); - if (ref($self->{data}->{category}) eq "HASH") { - # one element alone - my @categories; - push @categories, $self->{data}->{category}; - $self->{data}->{category} = undef; - push @{$self->{data}->{category}}, @categories; - } - $self->{catLen} = scalar(@{$self->{data}->{category}}); - $self->{currCat} = -1; - - if(ref(@{$self->{data}->{category}}[0]->{module}) eq "ARRAY") { - $self->{modLen} = scalar(@{@{$self->{data}->{category}}[0]->{module}}); - } else { - $self->{modLen} = 1; - } - $self->{currMod} = -1; - - return $self; -} - -sub hasNextCat { - my ($self) = @_; - - if($self->{currCat} + 1 >= $self->{catLen}) { - return 0; - } - return 1; -} - -sub getNextCat { - my ($self) = @_; - - $self->{currCat}++; - if($self->{currCat} >= $self->{catLen}) { - return 0; - } - - # Reset the Module Count and Mod length for new Category - $self->{currMod} = -1; - if(ref(@{$self->{data}->{category}}[$self->{currCat}]->{module}) eq "ARRAY") { - $self->{modLen} = scalar(@{@{$self->{data}->{category}}[$self->{currCat}]->{module}}); - } else { - $self->{modLen} = 1; - } - - my $tmp = @{$self->{data}->{category}}[$self->{currCat}]; - - return $tmp; -} - -sub hasNextMod { - my ($self) = @_; - - if($self->{currMod} + 1 >= $self->{modLen}) { - return 0; - } - return 1; -} - -sub getNextMod { - my ($self) = @_; - - my $ret = 0; - - $self->{currMod}++; - - if($self->{modLen} == 1) { - $ret = @{$self->{data}->{category}}[$self->{currCat}]->{module}; - } else { - $ret = @{@{$self->{data}->{category} }[$self->{currCat}]->{module}}[$self->{currMod}]; - } - - return $ret; -} - -1; diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 00000000..805d7d62 --- /dev/null +++ b/MANIFEST @@ -0,0 +1,114 @@ +categories.conf +Changes +etc/categories.conf +etc/categories.conf.d/adminService.conf +etc/categories.conf.d/adminUser.conf +etc/settings.conf +extras/org.mageia.policykit.pkexec.adminpanel.policy +extras/README +extras/Services/adminService.conf +extras/setup.sh +extras/Users/adminUser.conf +ignore.txt +images/logo_mageia.png +images/mageia.png +images/quit.png +lib/AdminPanel/Category.pm +lib/AdminPanel/ConfigReader.pm +lib/AdminPanel/LogViewer/init.pm +lib/AdminPanel/MainDisplay.pm +lib/AdminPanel/Module.pm +lib/AdminPanel/Module/AdminMouse.pm +lib/AdminPanel/Module/Hosts.pm +lib/AdminPanel/Module/Services.pm +lib/AdminPanel/Module/Users.pm +lib/AdminPanel/Privileges.pm +lib/AdminPanel/rpmdragora.pm +lib/AdminPanel/Rpmdragora/.perl_checker +lib/AdminPanel/Rpmdragora/edit_urpm_sources.pm +lib/AdminPanel/Rpmdragora/formatting.pm +lib/AdminPanel/Rpmdragora/gui.pm +lib/AdminPanel/Rpmdragora/gurpm.pm +lib/AdminPanel/Rpmdragora/icon.pm +lib/AdminPanel/Rpmdragora/init.pm +lib/AdminPanel/Rpmdragora/localization.pm +lib/AdminPanel/Rpmdragora/open_db.pm +lib/AdminPanel/Rpmdragora/pkg.pm +lib/AdminPanel/Rpmdragora/rpmnew.pm +lib/AdminPanel/Rpmdragora/widgets.pm +lib/AdminPanel/SettingsReader.pm +lib/AdminPanel/Shared.pm +lib/AdminPanel/Shared/Hosts.pm +lib/AdminPanel/Shared/Services.pm +lib/AdminPanel/Shared/Users.pm +Makefile.PL +MANIFEST This list of files +modules/logviewer/logviewer.pl +modules/rpmdragora/.perl_checker +modules/rpmdragora/AUTHORS +modules/rpmdragora/ChangeLog +modules/rpmdragora/COPYING +modules/rpmdragora/data/.svnignore +modules/rpmdragora/data/mageiaupdate.desktop.in +modules/rpmdragora/data/rpmdragora-browse-only.desktop.in +modules/rpmdragora/data/rpmdragora-sources.desktop.in +modules/rpmdragora/data/rpmdragora.desktop.in +modules/rpmdragora/edit-urpm-sources.pl +modules/rpmdragora/grpmi/curl_download/curl_download.pm +modules/rpmdragora/grpmi/curl_download/Makefile.PL +modules/rpmdragora/gui.lst +modules/rpmdragora/gurpmi.addmedia +modules/rpmdragora/icons/bugfix-update.png +modules/rpmdragora/icons/create_titles.pl +modules/rpmdragora/icons/general-update.png +modules/rpmdragora/icons/security-update.png +modules/rpmdragora/icons/selected.png +modules/rpmdragora/icons/semiselected.png +modules/rpmdragora/icons/state_backport.png +modules/rpmdragora/icons/state_base.png +modules/rpmdragora/icons/state_installed.png +modules/rpmdragora/icons/state_to_install.png +modules/rpmdragora/icons/state_to_remove.png +modules/rpmdragora/icons/state_to_update.png +modules/rpmdragora/icons/state_uninstalled.png +modules/rpmdragora/icons/title-install.png +modules/rpmdragora/icons/title-media.png +modules/rpmdragora/icons/title-tile.png +modules/rpmdragora/icons/title-update.png +modules/rpmdragora/icons/unselected.png +modules/rpmdragora/MageiaUpdate +modules/rpmdragora/mime/gurpmi.addmedia.desktop.in +modules/rpmdragora/mime/urpmi-media.xml +modules/rpmdragora/mime/x-urpmi-media.desktop.in +modules/rpmdragora/NEWS +modules/rpmdragora/pixmaps/edit-urpm-sources16.png +modules/rpmdragora/pixmaps/edit-urpm-sources32.png +modules/rpmdragora/pixmaps/edit-urpm-sources48.png +modules/rpmdragora/pixmaps/mageiaupdate16.png +modules/rpmdragora/pixmaps/mageiaupdate32.png +modules/rpmdragora/pixmaps/mageiaupdate48.png +modules/rpmdragora/pixmaps/rpmdragora-remove16.png +modules/rpmdragora/pixmaps/rpmdragora-remove32.png +modules/rpmdragora/pixmaps/rpmdragora-remove48.png +modules/rpmdragora/pixmaps/rpmdragora16.png +modules/rpmdragora/pixmaps/rpmdragora32.png +modules/rpmdragora/pixmaps/rpmdragora48.png +modules/rpmdragora/README +modules/rpmdragora/rpmdragora +modules/rpmdragora/rpmdragora.menu +modules/rpmdragora/rpmdragora.mine +modules/rpmdragora/simplify-drakx-modules +modules/test.cpp +README +scripts/adminMouse +scripts/adminService +scripts/adminUser +scripts/apanel.pl +scripts/hostmanager +scripts/mgaAddUser +settings.conf +t/00-load.t +t/boilerplate.t +t/manifest.t +t/pod-coverage.t +t/pod.t diff --git a/MainDisplay.pm b/MainDisplay.pm deleted file mode 100644 index 35633b6e..00000000 --- a/MainDisplay.pm +++ /dev/null @@ -1,451 +0,0 @@ -# vim: set et ts=4 sw=4: -# Copyright 2012 Steven Tucker -# -# This file is part of AdminPanel -# -# AdminPanel is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# AdminPanel is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with AdminPanel. If not, see . - - -#Class MainDisplay -package MainDisplay; - -use strict; -use warnings; -use diagnostics; -use SettingsReader; -use ConfigReader; -use Category; -use Module; -use Data::Dumper; -use yui; - -sub new { - - my $self = { - my $categories = 0, - my $event = 0, - my $factory = 0, - my $mainWin = 0, - my $mainLayout = 0, - my $menuLayout = 0, - my $menus = { - my $file = 0, - my $help = 0 - }, - my $layout = 0, - my $leftPane = 0, - my $rightPane = 0, - my $currCategory = 0, - my $confDir = 0, - my $title = 0, - my $settings = 0, - my $exitButton = 0, -# my $justToGetRidOfERROR = 0, - my $replacePoint = 0 - }; - bless $self, 'MainDisplay'; - -## Default values - $self->{name} = "Administration panel"; - $self->{categories} = []; - $self->{confDir} = "/etc/apanel", - $self->{title} = "apanel", - - my $cmdline = new yui::YCommandLine; - - ## TODO add parameter check - my $pos = $cmdline->find("--name"); - if ($pos > 0) - { - $self->{title} = $cmdline->arg($pos+1); - } - $pos = $cmdline->find("--conf_dir"); - if ($pos > 0) - { - $self->{confDir} = $cmdline->arg($pos+1); - } - else - { - $self->{confDir} = "/etc/$self->{title}"; - } -# print "name = ".$self->{title}."\n"; -# print "conf dir = ".$self->{confDir}."\n"; - - $self->setupGui(); - - return $self; -} - -## Begin the program event loop -sub start { - my ($self) = shift; - my $reqExit = 0; - - ##Default category selection - if (!$self->{currCategory}) { - $self->{currCategory} = @{$self->{categories}}[0]; - } - $self->{currCategory}->addButtons($self->{rightPane}, $self->{factory}); - $self->{rightPaneFrame}->setLabel($self->{currCategory}->{name}); - $self->{factory}->createSpacing($self->{rightPane}, 1, 1, 1.0 ); - my $launch = 0; - while(!$launch) { - - ## Grab Event - $self->{event} = $self->{mainWin}->waitForEvent(); - - ## Check for window close - if ($self->{event}->eventType() == $yui::YEvent::CancelEvent) - { - last; - } - -## why i can't test item() with $self->{menus}->{file}[0]? - ## Check for Exit button push or menu - if($self->{event}->widget() == $self->{exitButton} || - ($self->{event}->item() && ($self->{event}->item()->label() eq $self->{menus}->{file}[0]->label() ))) { - last; - }; - - ## Discover if a menu button was selected. - ## If menu button selected, set right panel to display - ## selected Category Modules - for(@{$self->{categories}}){ - if( $_->{button} == $self->{event}->widget() ){ - ## Menu item selected, set right pane - $self->{mainWin}->startMultipleChanges(); - ## Remove existing modules - $self->{replacePoint}->deleteChildren(); - $self->{rightPane} = $self->{factory}->createVBox($self->{replacePoint}); - - ## Change Current Category to the selected one - $self->{currCategory} = $_; - ## Add new Module Buttons to Right Pane - $self->{currCategory}->addButtons($self->{rightPane}, $self->{factory}); - $self->{rightPaneFrame}->setLabel($self->{currCategory}->{name}); - $self->{factory}->createSpacing($self->{rightPane}, 1, 1, 1.0 ); - $self->{replacePoint}->showChild(); - $self->{mainWin}->recalcLayout(); - $self->{mainWin}->doneMultipleChanges(); - - last; - } - } - - ## Check if event is from current Category View - ## If icon click, launch the Module - for(@{$self->{currCategory}->{modules}}) { - if( $_->{button} == $self->{event}->widget() ){ - $launch = $_; - last; - } - } - } - - return $launch; -} - -sub destroy { - my ($self) = shift; - $self->{mainWin}->destroy(); - for (my $cat=0; $cat < scalar(@{$self->{categories}}); $cat++ ) { - @{$self->{categories}}[$cat]->{button} = 0; - @{$self->{categories}}[$cat]->removeButtons(); - } -} - -sub setupGui { - my ($self) = shift; - - $self->loadSettings(); - yui::YUILog::setLogFileName($self->{settings}->{log}); - $self->{name} = $self->{settings}->{title}; - yui::YUI::app()->setApplicationTitle($self->{name}); - yui::YUI::app()->setApplicationIcon($self->{settings}->{icon}); - - $self->{factory} = yui::YUI::widgetFactory; - $self->{mainWin} = $self->{factory}->createMainDialog; -#print "Title: ".yui::YUI::app()->applicationTitle()."\n"; - - $self->{mainLayout} = $self->{factory}->createVBox($self->{mainWin}); - $self->{menuLayout} = $self->{factory}->createHBox($self->{mainLayout}); - - ## Menu file - ## TODO i8n - my $align = $self->{factory}->createAlignment($self->{menuLayout}, 1, 0); - my $menu = $self->{factory}->createMenuButton($align, "File"); - my $item = new yui::YMenuItem("Exit"); - - push(@{$self->{menus}->{file}}, $item); - $menu->addItem($item); - $menu->rebuildMenuTree(); - - $align = $self->{factory}->createAlignment($self->{menuLayout}, 2, 0); - $menu = $self->{factory}->createMenuButton($align, "Help"); - $item = new yui::YMenuItem("Help"); - $menu->addItem($item); - push(@{$self->{menus}->{help}}, $item); - $item = new yui::YMenuItem("About"); - $menu->addItem($item); - push(@{$self->{menus}->{help}}, $item); - $menu->rebuildMenuTree(); - - $self->{layout} = $self->{factory}->createHBox($self->{mainLayout}); - - #create left Panel Frame no need to add a label for title - $self->{leftPaneFrame} = $self->{factory}->createFrame($self->{layout}, $self->{settings}->{category_title}); - #create right Panel Frame no need to add a label for title (use setLabel when module changes) - $self->{rightPaneFrame} = $self->{factory}->createFrame($self->{layout}, ""); - #create replace point for dynamically created widgets - $self->{replacePoint} = $self->{factory}->createReplacePoint($self->{rightPaneFrame}); - - $self->{rightPane} = $self->{factory}->createVBox($self->{replacePoint}); - $self->{leftPane} = $self->{factory}->createVBox($self->{leftPaneFrame}); - - #logo from settings - my $logo = $self->{factory}->createImage($self->{leftPane}, $self->{settings}->{logo}); - $logo->setAutoScale(1); - -# $self->{leftPaneFrame}->setWeight(0, 1); - $self->{rightPaneFrame}->setWeight(0, 2); - - $self->loadCategories(); - $self->{factory}->createVStretch($self->{leftPane}); - - $self->{exitButton} = $self->{factory}->createPushButton($self->{leftPane}, "Exit"); - $self->{exitButton}->setIcon("$self->{settings}->{images_dir}/quit.png"); - $self->{exitButton}->setStretchable(0, 1); -# $self->{exitButton}->setStretchable(1, 1); -} - -## adpanel settings -sub loadSettings { - my ($self, $force_load) = @_; - # configuration file name - my $fileName = "$self->{confDir}/settings.conf"; - if (!$self->{settings} || $force_load) { - $self->{settings} = new SettingsReader($fileName); - } -} - -#============================================================= - -=head2 categoryLoaded - -=head3 INPUT - - $self: this object - $category: category to look for - -=head3 OUTPUT - - $present: category is present or not - -=head3 DESCRIPTION - - This method looks for the given category and if already in - returns true. -=cut - -#============================================================= -sub categoryLoaded { - my ($self, $category) = @_; - my $present = 0; - - if (!$category) { - return $present; - } - - foreach my $cat (@{$self->{categories}}) { - if ($cat->{name} eq $category->{name}) { - $present = 1; - last; - } - } - - return $present; -} - -#============================================================= - -=head2 getCategory - -=head3 INPUT - - $self: this object - $name: category name - -=head3 OUTPUT - - $category: category object if exists - -=head3 DESCRIPTION - - This method looks for the given category name and returns - the realte object. -=cut - -#============================================================= -sub getCategory { - my ($self, $name) = @_; - my $category = undef; - - foreach $category (@{$self->{categories}}) { - if ($category->{name} eq $name) { - return $category; - } - } - - return $category; -} - -sub loadCategory { - my ($self, $category) = @_; - - if (!$self->categoryLoaded($category)) { - push ( @{$self->{categories}}, $category ); - - @{$self->{categories}}[-1]->{button} = $self->{factory}->createPushButton( - $self->{leftPane}, - $self->{categories}[-1]->{name} - ); - @{$self->{categories}}[-1]->setIcon(); - - @{$self->{categories}}[-1]->{button}->setStretchable(0, 1); - } - else { - for (my $cat=0; $cat < scalar(@{$self->{categories}}); $cat++ ) { - if( @{$self->{categories}}[$cat]->{name} eq $category->{name} && - !@{$self->{categories}}[$cat]->{button}) { - @{$self->{categories}}[$cat]->{button} = $self->{factory}->createPushButton( - $self->{leftPane}, - $self->{categories}[$cat]->{name} - ); - @{$self->{categories}}[$cat]->setIcon(); - @{$self->{categories}}[$cat]->{button}->setStretchable(0, 1); - last; - - } - } - } -} - -sub loadCategories { - my ($self) = @_; - - # category files - my @categoryFiles; - my $fileName = "$self->{confDir}/categories.conf"; - - - # configuration file dir - my $directory = "$self->{confDir}/categories.conf.d"; - - push(@categoryFiles, $fileName); - push(@categoryFiles, ); - my $currCategory; - - foreach $fileName (@categoryFiles) { - my $inFile = new ConfigReader($fileName); - my $tmpCat; - my $tmp; - my $hasNextCat = $inFile->hasNextCat(); - while( $hasNextCat ) { - $tmp = $inFile->getNextCat(); - $tmpCat = $self->getCategory($tmp->{title}); - if (!$tmpCat) { - $tmpCat = new Category($tmp->{title}, $tmp->{icon}); - } - $self->loadCategory($tmpCat); - $hasNextCat = $inFile->hasNextCat(); - $currCategory = $tmpCat; - - my $hasNextMod = $inFile->hasNextMod(); - while( $hasNextMod ) { - $tmp = $inFile->getNextMod(); - my $tmpMod; - my $loaded = 0; - if (exists $tmp->{title}) { - if (not $currCategory->moduleLoaded($tmp->{title})) { - $tmpMod = Module->create(name => $tmp->{title}, - icon => $tmp->{icon}, - launch => $tmp->{launcher} - ); - } - } - elsif (exists $tmp->{class}) { - if (not $currCategory->moduleLoaded(-CLASS => $tmp->{class})) { - $tmpMod = Module->create(-CLASS => $tmp->{class}); - } - } - if ($tmpMod) { - $loaded = $currCategory->loadModule($tmpMod); - undef $tmpMod if !$loaded; - } - $hasNextMod = $inFile->hasNextMod(); - } - } - } -} - -sub menuEventIndex { - my ($self) = shift; - - my $index = -1; - - for(my $i = 0; $i < scalar(@{$self->{categories}} ); ++$i) - { - print "Current Index = ".$index."\n"; - if($self->{event}->widget() == @{$self->{categories}}[$i]->{button}) - { - $index = $i; - print "Index found is : ".$index; - last; - } - } - return $index; -} - -1; - -=pod - -=head1 NAME - - MainDisplay - class for the main window - -=head1 SYNOPSIS - - $mainDisplay = new MainDisplay(); - -=head1 METHODS - -=head2 start - - contains the main loop of the application - where we can check for events - -=head2 setupGui - - creates a popupDialog using a YUI::WidgetFactory - and then populate this dialog with some components - -=head2 loadCategory - - creates a new button representing a category - -=head3 category (String) - -=cut - diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 00000000..171cd08f --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,35 @@ +use 5.006; +use strict; +use warnings FATAL => 'all'; +use ExtUtils::MakeMaker; + +WriteMakefile( + NAME => 'AdminPanel', + AUTHOR => q{Angelo Naselli - Matteo Pasotti }, + VERSION_FROM => 'lib/AdminPanel/MainDisplay.pm', + ABSTRACT => 'AdminPanel contains a generic launcher application that can run perl modules or external programs using Suse YUI abstarction.', + LICENSE => 'GPL_2', + PL_FILES => {}, + MIN_PERL_VERSION => 5.006, + CONFIGURE_REQUIRES => { + 'ExtUtils::MakeMaker' => 0, + }, + BUILD_REQUIRES => { + 'Test::More' => 0, + }, + PREREQ_PM => { + #'ABC' => 1.6, + #'Foo::Bar::Module' => 5.0401, + "Moose" => 0, + "Config::Hosts" => 0, + }, + EXE_FILES => [ qw( scripts/adminMouse + scripts/adminService + scripts/adminUser + scripts/apanel.pl + scripts/hostmanager + scripts/mgaAddUser + ) ], + dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', }, + clean => { FILES => 'AdminPanel-*' }, +); diff --git a/Module.pm b/Module.pm deleted file mode 100644 index 48eb5bdc..00000000 --- a/Module.pm +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/perl - -# vim: set et ts=4 sw=4: -# Copyright 2012 Steven Tucker -# -# This file is part of AdminPanel -# -# AdminPanel is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# AdminPanel is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with AdminPanel. If not, see . - - -#Class Module -package Module; - -use Moose; - -=head1 VERSION - -Version 0.01 - -=cut - -our $VERSION = '1.0.0'; - -use strict; -use warnings; -use diagnostics; -use yui; - -=head1 SUBROUTINES/METHODS - -=head2 create - returns a Module object such as a module - launcher (this object) or an extension of - this class - -=cut - -sub create { - my $class = shift; - $class = ref $class || $class; - my (%params) = @_; - - my $obj; - if ( exists $params{-CLASS} ) { - my $driver = $params{-CLASS}; - - eval { - my $pkg = $driver; - $pkg =~ s/::/\//g; - $pkg .= '.pm'; - require $pkg; - $obj=$driver->new(); - }; - if ( $@ ) { - die "Error getting obj for driver $params{-CLASS}: $@"; - return undef; - } - } - else { - $obj = new Module(@_); - } - return $obj; -} - -has 'icon' => ( - is => 'rw', - isa => 'Str', -); - -has 'name' => ( - is => 'rw', - isa => 'Str', -); - -has 'launch' => ( - is => 'rw', - isa => 'Str', -); - -has 'button' => ( - is => 'rw', - init_arg => undef, -); - - -sub setButton { - my ($self, $button) = @_; - $self->{button} = $button; -} - -sub removeButton { - my($self) = @_; - - undef($self->{button}); -} - -# base class launcher -sub start { - my $self = shift; - - if ($self->{launch}) { - my $err = yui::YUI::app()->runInTerminal( $self->{launch} . " --ncurses"); - if ($err == -1) { - system($self->{launch}); - } - } -} - - -no Moose; -1; diff --git a/README b/README new file mode 100644 index 00000000..f0860fa3 --- /dev/null +++ b/README @@ -0,0 +1,63 @@ +AdminPanel-Shared + +The README is used to introduce the module and provide instructions on +how to install the module, any machine dependencies it may have (for +example C compilers and installed libraries) and any other information +that should be provided before the module is installed. + +A README file is required for CPAN modules since CPAN extracts the README +file from a module distribution so that people browsing the archive +can use it to get an idea of the module's uses. It is usually a good idea +to provide version information here so that people can decide whether +fixes for the module are worth downloading. + + +INSTALLATION + +To install this module, run the following commands: + + perl Makefile.PL + make + make test + make install + +SUPPORT AND DOCUMENTATION + +After installing, you can find documentation for this module with the +perldoc command. + + perldoc AdminPanel + +You can also look for information at: + + RT, CPAN's request tracker (report bugs here) + http://rt.cpan.org/NoAuth/Bugs.html?Dist=AdminPanel-Shared + + AnnoCPAN, Annotated CPAN documentation + http://annocpan.org/dist/AdminPanel-Shared + + CPAN Ratings + http://cpanratings.perl.org/d/AdminPanel-Shared + + Search CPAN + http://search.cpan.org/dist/AdminPanel-Shared/ + + +LICENSE AND COPYRIGHT + +Copyright (C) 2012-2014 Angelo Naselli, Matteo Pasotti, Steven Tucker + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; version 2 dated June, 1991 or at your option +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +A copy of the GNU General Public License is available in the source tree; +if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + diff --git a/SettingsReader.pm b/SettingsReader.pm deleted file mode 100644 index e0790f61..00000000 --- a/SettingsReader.pm +++ /dev/null @@ -1,45 +0,0 @@ -# vim: set et ts=4 sw=4: -# Copyright 2012 Angelo Naselli -# -# This file is part of AdminPanel -# -# AdminPanel is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# AdminPanel is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with AdminPanel. If not, see . - - -#Class SettingsReader -package SettingsReader; - -use strict; -use warnings; -use diagnostics; -use XML::Simple; -use Data::Dumper; - -sub new { - my ($class, $fileName) = @_; - - my $self = { - my $settings = 0, - my $justToGetRidOfERROR = 0 - }; - bless $self, 'SettingsReader'; - - my $xml = new XML::Simple (KeyAttr=>[]); - $self->{settings} = $xml->XMLin($fileName); - - return $self->{settings}; -} - - -1; diff --git a/apanel.pl b/apanel.pl deleted file mode 100755 index f75c2fab..00000000 --- a/apanel.pl +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/perl -# vim: set et ts=4 sw=4: -# Copyright 2012 Steven Tucker -# Copyright 2013 Matteo Pasotti -# Copyright 2014 Angelo Naselli -# -# This file is part of AdminPanel -# -# AdminPanel is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# AdminPanel is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with AdminPanel. If not, see . - -use strict; -use warnings; -use diagnostics; -use AdminPanel::Privileges; -use FindBin; -use lib "$FindBin::RealBin"; -use SettingsReader; -use MainDisplay; -use yui; - -my $cmdline = new yui::YCommandLine; - -usage() if($cmdline->find("--help") > 0 || $cmdline->find("-h") > 0); - -my $settings = getSettings(); - -ask_for_authentication($settings->{priv_method}) if(require_root_capability()); - - my $mainWin = new MainDisplay(); -while (1) { - my $launch = $mainWin->start(); - - if ($launch) { - $mainWin->destroy(); - $launch->start(); - } - else { - $mainWin->destroy(); - last; - } - $mainWin->setupGui(); -} - - -sub usage { - print "\n"; - print "Usage apanel [options...]\n\n"; - print "Options:\n"; - print "\t--help | -h print this help\n"; -## anaselli: --name now is used only to add a path to /etc (e.g. --name mcc2 means /etc/mcc2) - # and it is overriden by --conf_dir, so it should be discussed better to understand - # if it is really needed any more. - # Window title is got from settings.conf (key title) - print "\t--name string specify the window title of the administration panel\n"; - print "\t--conf_dir path specify the settings.conf file directory\n"; - print "\n"; - exit(0); -} - -# adpanel settings -sub getSettings { - my ($self) = @_; - # yui commandline parser - my $pos = $cmdline->find("--conf_dir"); - my $confDir = "/etc/apanel"; - if($pos > 0){ - $confDir = $cmdline->arg($pos + 1); - }else{ - $confDir = "/etc/apanel"; - } - # configuration file name - my $fileName = "$confDir/settings.conf"; - return new SettingsReader($fileName); -} - -=pod - -=head1 main - - main launcher - -=cut - -1; diff --git a/categories.conf b/categories.conf index d687780f..49b37c5a 100644 --- a/categories.conf +++ b/categories.conf @@ -28,21 +28,21 @@ System /usr/share/icons/system_section.png - AdminPanel::Users::GUsers + AdminPanel::Module::Users Network && Internet /usr/share/icons/networking_section.png - AdminPanel::Hosts::GHosts + AdminPanel::Module::Hosts Hardware /usr/share/icons/configuration_section.png - AdminPanel::AdminMouse + AdminPanel::Module::AdminMouse CD/DVD Config diff --git a/extras/Services/adminService.conf b/extras/Services/adminService.conf new file mode 100644 index 00000000..304f75ed --- /dev/null +++ b/extras/Services/adminService.conf @@ -0,0 +1,10 @@ + + + + System + /usr/share/icons/system_section.png + + AdminPanel::Module::Services + + + diff --git a/extras/Users/adminUser.conf b/extras/Users/adminUser.conf new file mode 100644 index 00000000..85dba9f2 --- /dev/null +++ b/extras/Users/adminUser.conf @@ -0,0 +1,10 @@ + + + + System + /usr/share/icons/system_section.png + + AdminPanel::Module::Users + + + diff --git a/ignore.txt b/ignore.txt new file mode 100644 index 00000000..86918c02 --- /dev/null +++ b/ignore.txt @@ -0,0 +1,20 @@ +Makefile +Makefile.old +Build +Build.bat +META.* +MYMETA.* +.build/ +_build/ +cover_db/ +blib/ +inc/ +.lwpcookies +.last_cover_stats +.git +tags +nytprof.out +pod2htm*.tmp +pm_to_blib +AdminPanel-* +AdminPanel-*.tar.gz diff --git a/lib/AdminPanel/Category.pm b/lib/AdminPanel/Category.pm new file mode 100644 index 00000000..7c89fbb7 --- /dev/null +++ b/lib/AdminPanel/Category.pm @@ -0,0 +1,201 @@ +# vim: set et ts=4 sw=4: +# Copyright 2012 Steven Tucker +# +# This file is part of AdminPanel +# +# AdminPanel is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# AdminPanel is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with AdminPanel. If not, see . + + +#Class Category +package AdminPanel::Category; + +use strict; +use warnings; +use diagnostics; +use yui; + +## Can only add the config file data at constructor +## The Gui elements are added in setupGui inside MainDisplay +sub new { + my ($class, $newName, $newIcon) = @_; + my $self = { + my $name = 0, + my $button = 0, + my $icon = 0, + my $modules = 0 + }; + bless $self, 'AdminPanel::Category'; + + $self->{name} = $newName; + $self->{icon} = $newIcon; + + return $self; +} + +## Add a new module to the list +#============================================================= + +=head2 loadModule + +=head3 INPUT + + $self: this object + $module: module to add + +=head3 OUTPUT + + 1: if the module has been added + 0: otherwise + +=head3 DESCRIPTION + + This method adds a module to the loaded + modules if it is not already in. + +=cut + +#============================================================= +sub loadModule { + my ($self, $module) = @_; + + if (!$self->moduleLoaded($module->{name})) { + push ( @{$self->{modules}}, $module ); + + return 1; + } + return 0; +} + +#============================================================= + +=head2 moduleLoaded + +=head3 INPUT + + $self: this object + $module_name or -CLASS => name : module/CLASS name to look for + +=head3 OUTPUT + + $present: module present or not + +=head3 DESCRIPTION + + This method looks for the given module and if already in + returns true. +=cut + +#============================================================= +sub moduleLoaded { + my $self = shift; + my (%params) = @_; + my ($module_name) = @_; + + my $present = 0; + + if (!$module_name) { + return $present; + } + + foreach my $mod (@{$self->{modules}}) { + if (exists $params{-CLASS} && ref($mod) eq $params{-CLASS}) { + $present = 1; + last; + } + elsif ($mod->{name} eq $module_name) { + $present = 1; + last; + } + } + + return $present; +} + +## Create and add buttons for each module +sub addButtons { + my($self, $pane, $factory) = @_; + my $count = 0; + my $tmpButton; + my $currLayout = 0; + $factory->createVSpacing($pane, 2); + foreach my $mod (@{$self->{modules}}) { + if(($count % 2) != 1) { + $currLayout = $factory->createHBox($pane); + $factory->createHStretch($currLayout); + } + $count++; + $tmpButton = $factory->createPushButton($currLayout, + $mod->name); + $mod->setButton($tmpButton); + $tmpButton->setLabel($mod->name); + $tmpButton->setIcon($mod->icon); + $factory->createHStretch($currLayout); + if(($count % 2) != 1) { + $factory->createVSpacing($pane, 2); + } + } + $factory->createVStretch($pane); +} + +## Delete the module buttons +sub removeButtons { + my($self) = @_; + + for(@{$self->{modules}}) { + $_->removeButton(); + } +} + +sub setIcon { + my($self) = @_; + + $self->{button}->setIcon($self->{icon}); +} + +1; +__END__ + +=pod + +=head1 NAME + + Category - add new category to window + +=head1 SYNOPSIS + + $category = new Category('Category Name'); + + +=head1 USAGE + + my $display = new MainDisplay(); + + my $category = new Category('Network'); + $display->loadCategory($category); + + $display->start(); + +=head1 FUNCTIONS + +=head2 new (name) + + Constructor: creates a new category named Name + + $category = new Category('Name'); + +=head3 name (String) + + The name of the category + +=cut diff --git a/lib/AdminPanel/ConfigReader.pm b/lib/AdminPanel/ConfigReader.pm new file mode 100644 index 00000000..718a381d --- /dev/null +++ b/lib/AdminPanel/ConfigReader.pm @@ -0,0 +1,119 @@ +# vim: set et ts=4 sw=4: +# Copyright 2012 Steven Tucker +# +# This file is part of AdminPanel +# +# AdminPanel is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# AdminPanel is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with AdminPanel. If not, see . + + +#Class ConfigReader +package AdminPanel::ConfigReader; + +use strict; +use warnings; +use diagnostics; +use XML::Simple; +use Data::Dumper; + +sub new { + my ($class, $fileName) = @_; + + my $self = { + my $data = 0, + my $catLen = 0, + my $currCat = 0, + my $modLen = 0, + my $currMod = 0, + my $placeHolder = 0 + }; + bless $self, 'AdminPanel::ConfigReader'; + + my $xml = new XML::Simple (KeyAttr=>[]); + $self->{data} = $xml->XMLin($fileName); + if (ref($self->{data}->{category}) eq "HASH") { + # one element alone + my @categories; + push @categories, $self->{data}->{category}; + $self->{data}->{category} = undef; + push @{$self->{data}->{category}}, @categories; + } + $self->{catLen} = scalar(@{$self->{data}->{category}}); + $self->{currCat} = -1; + + if(ref(@{$self->{data}->{category}}[0]->{module}) eq "ARRAY") { + $self->{modLen} = scalar(@{@{$self->{data}->{category}}[0]->{module}}); + } else { + $self->{modLen} = 1; + } + $self->{currMod} = -1; + + return $self; +} + +sub hasNextCat { + my ($self) = @_; + + if($self->{currCat} + 1 >= $self->{catLen}) { + return 0; + } + return 1; +} + +sub getNextCat { + my ($self) = @_; + + $self->{currCat}++; + if($self->{currCat} >= $self->{catLen}) { + return 0; + } + + # Reset the Module Count and Mod length for new Category + $self->{currMod} = -1; + if(ref(@{$self->{data}->{category}}[$self->{currCat}]->{module}) eq "ARRAY") { + $self->{modLen} = scalar(@{@{$self->{data}->{category}}[$self->{currCat}]->{module}}); + } else { + $self->{modLen} = 1; + } + + my $tmp = @{$self->{data}->{category}}[$self->{currCat}]; + + return $tmp; +} + +sub hasNextMod { + my ($self) = @_; + + if($self->{currMod} + 1 >= $self->{modLen}) { + return 0; + } + return 1; +} + +sub getNextMod { + my ($self) = @_; + + my $ret = 0; + + $self->{currMod}++; + + if($self->{modLen} == 1) { + $ret = @{$self->{data}->{category}}[$self->{currCat}]->{module}; + } else { + $ret = @{@{$self->{data}->{category} }[$self->{currCat}]->{module}}[$self->{currMod}]; + } + + return $ret; +} + +1; diff --git a/lib/AdminPanel/LogViewer/init.pm b/lib/AdminPanel/LogViewer/init.pm new file mode 100644 index 00000000..1c961712 --- /dev/null +++ b/lib/AdminPanel/LogViewer/init.pm @@ -0,0 +1,31 @@ +package AdminPanel::LogViewer::init; + +use strict; +use warnings; +use diagnostics; +use English; +use lib qw(/usr/lib/libDrakX); +use common; +use AdminPanel::Shared; +use base qw(Exporter); + +our @EXPORT = qw(warn_about_user_mode + interactive_msg); + +sub interactive_msg { + my ($title, $contents) = @_; + return ask_YesOrNo($title, $contents); +} + +sub warn_about_user_mode() { + my $title = N("Running in user mode"); + my $msg = N("You are launching this program as a normal user.\n". + "You will not be able to read system logs which you do not have rights to,\n". + "but you may still browse all the others."); + if(($EUID != 0) and (!interactive_msg($title, $msg))) { + return 0; + } + return 1; +} + +1; diff --git a/lib/AdminPanel/MainDisplay.pm b/lib/AdminPanel/MainDisplay.pm new file mode 100644 index 00000000..8792bb28 --- /dev/null +++ b/lib/AdminPanel/MainDisplay.pm @@ -0,0 +1,505 @@ +# vim: set et ts=4 sw=4: +# Copyright 2012 Steven Tucker +# +# This file is part of AdminPanel +# +# AdminPanel is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# AdminPanel is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with AdminPanel. If not, see . + + +package AdminPanel::MainDisplay; +#============================================================= -*-perl-*- + +=head1 NAME + +AdminPanel::MainDisplay - class for AdminPaneol main window + +=head1 SYNOPSIS + + $mainDisplay = new AdminPanel::MainDisplay(); + +=head1 METHODS + +=head1 DESCRIPTION + +Long_description + +=head1 EXPORT + +exported + +=head1 SUPPORT + +You can find documentation for this module with the perldoc command: + +perldoc AdminPanel::MainDisplay + +=head1 SEE ALSO + +SEE_ALSO + +=head1 AUTHOR + +Steven Tucker + +=head1 COPYRIGHT and LICENSE + +Copyright (C) 2012, Steven Tucker +Copyright (C) 2014, Angelo Naselli. + +AdminPanel is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +AdminPanel is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with AdminPanel. If not, see . + +=head1 FUNCTIONS + +=cut + + + +=head1 VERSION + +Version 0.01 + +=cut + +our $VERSION = '1.0.0'; + +use strict; +use warnings; +use diagnostics; +use AdminPanel::SettingsReader; +use AdminPanel::ConfigReader; +use AdminPanel::Category; +use AdminPanel::Module; +use Data::Dumper; +use yui; + +sub new { + + my $self = { + my $categories = 0, + my $event = 0, + my $factory = 0, + my $mainWin = 0, + my $mainLayout = 0, + my $menuLayout = 0, + my $menus = { + my $file = 0, + my $help = 0 + }, + my $layout = 0, + my $leftPane = 0, + my $rightPane = 0, + my $currCategory = 0, + my $confDir = 0, + my $title = 0, + my $settings = 0, + my $exitButton = 0, +# my $justToGetRidOfERROR = 0, + my $replacePoint = 0 + }; + bless $self, 'AdminPanel::MainDisplay'; + +## Default values + $self->{name} = "Administration panel"; + $self->{categories} = []; + $self->{confDir} = "/etc/apanel", + $self->{title} = "apanel", + + my $cmdline = new yui::YCommandLine; + + ## TODO add parameter check + my $pos = $cmdline->find("--name"); + if ($pos > 0) + { + $self->{title} = $cmdline->arg($pos+1); + } + $pos = $cmdline->find("--conf_dir"); + if ($pos > 0) + { + $self->{confDir} = $cmdline->arg($pos+1); + } + else + { + $self->{confDir} = "/etc/$self->{title}"; + } +# print "name = ".$self->{title}."\n"; +# print "conf dir = ".$self->{confDir}."\n"; + + $self->setupGui(); + + return $self; +} + +## Begin the program event loop +sub start { + my ($self) = shift; + my $reqExit = 0; + + ##Default category selection + if (!$self->{currCategory}) { + $self->{currCategory} = @{$self->{categories}}[0]; + } + $self->{currCategory}->addButtons($self->{rightPane}, $self->{factory}); + $self->{rightPaneFrame}->setLabel($self->{currCategory}->{name}); + $self->{factory}->createSpacing($self->{rightPane}, 1, 1, 1.0 ); + my $launch = 0; + while(!$launch) { + + ## Grab Event + $self->{event} = $self->{mainWin}->waitForEvent(); + + ## Check for window close + if ($self->{event}->eventType() == $yui::YEvent::CancelEvent) + { + last; + } + +## why i can't test item() with $self->{menus}->{file}[0]? + ## Check for Exit button push or menu + if($self->{event}->widget() == $self->{exitButton} || + ($self->{event}->item() && ($self->{event}->item()->label() eq $self->{menus}->{file}[0]->label() ))) { + last; + }; + + ## Discover if a menu button was selected. + ## If menu button selected, set right panel to display + ## selected Category Modules + for(@{$self->{categories}}){ + if( $_->{button} == $self->{event}->widget() ){ + ## Menu item selected, set right pane + $self->{mainWin}->startMultipleChanges(); + ## Remove existing modules + $self->{replacePoint}->deleteChildren(); + $self->{rightPane} = $self->{factory}->createVBox($self->{replacePoint}); + + ## Change Current Category to the selected one + $self->{currCategory} = $_; + ## Add new Module Buttons to Right Pane + $self->{currCategory}->addButtons($self->{rightPane}, $self->{factory}); + $self->{rightPaneFrame}->setLabel($self->{currCategory}->{name}); + $self->{factory}->createSpacing($self->{rightPane}, 1, 1, 1.0 ); + $self->{replacePoint}->showChild(); + $self->{mainWin}->recalcLayout(); + $self->{mainWin}->doneMultipleChanges(); + + last; + } + } + + ## Check if event is from current Category View + ## If icon click, launch the Module + for(@{$self->{currCategory}->{modules}}) { + if( $_->{button} == $self->{event}->widget() ){ + $launch = $_; + last; + } + } + } + + return $launch; +} + +sub destroy { + my ($self) = shift; + $self->{mainWin}->destroy(); + for (my $cat=0; $cat < scalar(@{$self->{categories}}); $cat++ ) { + @{$self->{categories}}[$cat]->{button} = 0; + @{$self->{categories}}[$cat]->removeButtons(); + } +} + +sub setupGui { + my ($self) = shift; + + $self->loadSettings(); + yui::YUILog::setLogFileName($self->{settings}->{log}); + $self->{name} = $self->{settings}->{title}; + yui::YUI::app()->setApplicationTitle($self->{name}); + yui::YUI::app()->setApplicationIcon($self->{settings}->{icon}); + + $self->{factory} = yui::YUI::widgetFactory; + $self->{mainWin} = $self->{factory}->createMainDialog; +#print "Title: ".yui::YUI::app()->applicationTitle()."\n"; + + $self->{mainLayout} = $self->{factory}->createVBox($self->{mainWin}); + $self->{menuLayout} = $self->{factory}->createHBox($self->{mainLayout}); + + ## Menu file + ## TODO i8n + my $align = $self->{factory}->createAlignment($self->{menuLayout}, 1, 0); + my $menu = $self->{factory}->createMenuButton($align, "File"); + my $item = new yui::YMenuItem("Exit"); + + push(@{$self->{menus}->{file}}, $item); + $menu->addItem($item); + $menu->rebuildMenuTree(); + + $align = $self->{factory}->createAlignment($self->{menuLayout}, 2, 0); + $menu = $self->{factory}->createMenuButton($align, "Help"); + $item = new yui::YMenuItem("Help"); + $menu->addItem($item); + push(@{$self->{menus}->{help}}, $item); + $item = new yui::YMenuItem("About"); + $menu->addItem($item); + push(@{$self->{menus}->{help}}, $item); + $menu->rebuildMenuTree(); + + $self->{layout} = $self->{factory}->createHBox($self->{mainLayout}); + + #create left Panel Frame no need to add a label for title + $self->{leftPaneFrame} = $self->{factory}->createFrame($self->{layout}, $self->{settings}->{category_title}); + #create right Panel Frame no need to add a label for title (use setLabel when module changes) + $self->{rightPaneFrame} = $self->{factory}->createFrame($self->{layout}, ""); + #create replace point for dynamically created widgets + $self->{replacePoint} = $self->{factory}->createReplacePoint($self->{rightPaneFrame}); + + $self->{rightPane} = $self->{factory}->createVBox($self->{replacePoint}); + $self->{leftPane} = $self->{factory}->createVBox($self->{leftPaneFrame}); + + #logo from settings + my $logo = $self->{factory}->createImage($self->{leftPane}, $self->{settings}->{logo}); + $logo->setAutoScale(1); + +# $self->{leftPaneFrame}->setWeight(0, 1); + $self->{rightPaneFrame}->setWeight(0, 2); + + $self->loadCategories(); + $self->{factory}->createVStretch($self->{leftPane}); + + $self->{exitButton} = $self->{factory}->createPushButton($self->{leftPane}, "Exit"); + $self->{exitButton}->setIcon("$self->{settings}->{images_dir}/quit.png"); + $self->{exitButton}->setStretchable(0, 1); +# $self->{exitButton}->setStretchable(1, 1); +} + +## adpanel settings +sub loadSettings { + my ($self, $force_load) = @_; + # configuration file name + my $fileName = "$self->{confDir}/settings.conf"; + if (!$self->{settings} || $force_load) { + $self->{settings} = new AdminPanel::SettingsReader($fileName); + } +} + +#============================================================= + +=head2 categoryLoaded + +=head3 INPUT + + $self: this object + $category: category to look for + +=head3 OUTPUT + + $present: category is present or not + +=head3 DESCRIPTION + + This method looks for the given category and if already in + returns true. +=cut + +#============================================================= +sub categoryLoaded { + my ($self, $category) = @_; + my $present = 0; + + if (!$category) { + return $present; + } + + foreach my $cat (@{$self->{categories}}) { + if ($cat->{name} eq $category->{name}) { + $present = 1; + last; + } + } + + return $present; +} + +#============================================================= + +=head2 getCategory + +=head3 INPUT + + $self: this object + $name: category name + +=head3 OUTPUT + + $category: category object if exists + +=head3 DESCRIPTION + + This method looks for the given category name and returns + the realte object. +=cut + +#============================================================= +sub getCategory { + my ($self, $name) = @_; + my $category = undef; + + foreach $category (@{$self->{categories}}) { + if ($category->{name} eq $name) { + return $category; + } + } + + return $category; +} + +sub loadCategory { + my ($self, $category) = @_; + + if (!$self->categoryLoaded($category)) { + push ( @{$self->{categories}}, $category ); + + @{$self->{categories}}[-1]->{button} = $self->{factory}->createPushButton( + $self->{leftPane}, + $self->{categories}[-1]->{name} + ); + @{$self->{categories}}[-1]->setIcon(); + + @{$self->{categories}}[-1]->{button}->setStretchable(0, 1); + } + else { + for (my $cat=0; $cat < scalar(@{$self->{categories}}); $cat++ ) { + if( @{$self->{categories}}[$cat]->{name} eq $category->{name} && + !@{$self->{categories}}[$cat]->{button}) { + @{$self->{categories}}[$cat]->{button} = $self->{factory}->createPushButton( + $self->{leftPane}, + $self->{categories}[$cat]->{name} + ); + @{$self->{categories}}[$cat]->setIcon(); + @{$self->{categories}}[$cat]->{button}->setStretchable(0, 1); + last; + + } + } + } +} + +sub loadCategories { + my ($self) = @_; + + # category files + my @categoryFiles; + my $fileName = "$self->{confDir}/categories.conf"; + + + # configuration file dir + my $directory = "$self->{confDir}/categories.conf.d"; + + push(@categoryFiles, $fileName); + push(@categoryFiles, <$directory/*.conf>); + my $currCategory; + + foreach $fileName (@categoryFiles) { + my $inFile = new AdminPanel::ConfigReader($fileName); + my $tmpCat; + my $tmp; + my $hasNextCat = $inFile->hasNextCat(); + while( $hasNextCat ) { + $tmp = $inFile->getNextCat(); + $tmpCat = $self->getCategory($tmp->{title}); + if (!$tmpCat) { + $tmpCat = new AdminPanel::Category($tmp->{title}, $tmp->{icon}); + } + $self->loadCategory($tmpCat); + $hasNextCat = $inFile->hasNextCat(); + $currCategory = $tmpCat; + + my $hasNextMod = $inFile->hasNextMod(); + while( $hasNextMod ) { + $tmp = $inFile->getNextMod(); + my $tmpMod; + my $loaded = 0; + if (exists $tmp->{title}) { + if (not $currCategory->moduleLoaded($tmp->{title})) { + $tmpMod = AdminPanel::Module->create(name => $tmp->{title}, + icon => $tmp->{icon}, + launch => $tmp->{launcher} + ); + } + } + elsif (exists $tmp->{class}) { + if (not $currCategory->moduleLoaded(-CLASS => $tmp->{class})) { + $tmpMod = AdminPanel::Module->create(-CLASS => $tmp->{class}); + } + } + if ($tmpMod) { + $loaded = $currCategory->loadModule($tmpMod); + undef $tmpMod if !$loaded; + } + $hasNextMod = $inFile->hasNextMod(); + } + } + } +} + +sub menuEventIndex { + my ($self) = shift; + + my $index = -1; + + for(my $i = 0; $i < scalar(@{$self->{categories}} ); ++$i) + { + print "Current Index = ".$index."\n"; + if($self->{event}->widget() == @{$self->{categories}}[$i]->{button}) + { + $index = $i; + print "Index found is : ".$index; + last; + } + } + return $index; +} + +1; + +=pod + +=head2 start + + contains the main loop of the application + where we can check for events + +=head2 setupGui + + creates a popupDialog using a YUI::WidgetFactory + and then populate this dialog with some components + +=head2 loadCategory + + creates a new button representing a category + +=head3 category (String) + +=cut + diff --git a/lib/AdminPanel/Module.pm b/lib/AdminPanel/Module.pm new file mode 100644 index 00000000..1488e955 --- /dev/null +++ b/lib/AdminPanel/Module.pm @@ -0,0 +1,121 @@ +#!/usr/bin/perl + +# vim: set et ts=4 sw=4: +# Copyright 2012 Steven Tucker +# +# This file is part of AdminPanel +# +# AdminPanel is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# AdminPanel is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with AdminPanel. If not, see . + + +#Class Module +package AdminPanel::Module; + +use Moose; + +=head1 VERSION + +Version 0.01 + +=cut + +our $VERSION = '1.0.0'; + +use strict; +use warnings; +use diagnostics; +use yui; + +=head1 SUBROUTINES/METHODS + +=head2 create - returns a Module object such as a module + launcher (this object) or an extension of + this class + +=cut + +sub create { + my $class = shift; + $class = ref $class || $class; + my (%params) = @_; + + my $obj; + if ( exists $params{-CLASS} ) { + my $driver = $params{-CLASS}; + + eval { + my $pkg = $driver; + $pkg =~ s/::/\//g; + $pkg .= '.pm'; + require $pkg; + $obj=$driver->new(); + }; + if ( $@ ) { + die "Error getting obj for driver $params{-CLASS}: $@"; + return undef; + } + } + else { + $obj = new AdminPanel::Module(@_); + } + return $obj; +} + +has 'icon' => ( + is => 'rw', + isa => 'Str', +); + +has 'name' => ( + is => 'rw', + isa => 'Str', +); + +has 'launch' => ( + is => 'rw', + isa => 'Str', +); + +has 'button' => ( + is => 'rw', + init_arg => undef, +); + + +sub setButton { + my ($self, $button) = @_; + $self->{button} = $button; +} + +sub removeButton { + my($self) = @_; + + undef($self->{button}); +} + +# base class launcher +sub start { + my $self = shift; + + if ($self->{launch}) { + my $err = yui::YUI::app()->runInTerminal( $self->{launch} . " --ncurses"); + if ($err == -1) { + system($self->{launch}); + } + } +} + + +no Moose; +1; diff --git a/lib/AdminPanel/Module/AdminMouse.pm b/lib/AdminPanel/Module/AdminMouse.pm new file mode 100644 index 00000000..9e4e37c0 --- /dev/null +++ b/lib/AdminPanel/Module/AdminMouse.pm @@ -0,0 +1,278 @@ +# vim: set et ts=4 sw=4: +#***************************************************************************** +# +# Copyright (c) 2013 Angelo Naselli +# from drakx services +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** + +package AdminPanel::Module::AdminMouse; + +#leaving them atm +use lib qw(/usr/lib/libDrakX); + +# i18n: IMPORTANT: to get correct namespace (drakx-kbd-mouse-x11 instead of libDrakX) +BEGIN { unshift @::textdomains, 'drakx-kbd-mouse-x11' } + +use common; +use modules; +use mouse; +use c; + +use AdminPanel::Shared; + +use yui; +use Moose; + +extends qw( AdminPanel::Module ); + +has '+icon' => ( + default => "/usr/share/mcc/themes/default/mousedrake-mdk.png", +); + +has '+name' => ( + default => N("AdminMouse"), +); + +sub start { + my $self = shift; + + $self->_adminMouseDialog(); +} + +sub _getUntranslatedName { + my ($self, $name, $list) = @_; + + foreach my $n (@{$list}) { + my @names = split(/\|/, $n); + for (my $lev=0; $lev < scalar(@names); $lev++) { + if (translate($names[$lev]) eq $name) { + return $names[$lev]; + } + } + } + + return undef; +} + + +sub _adminMouseDialog { + my $self = shift; + + my $datavalue = "TEST"; + + my $appTitle = yui::YUI::app()->applicationTitle(); + + ## set new title to get it in dialog + yui::YUI::app()->setApplicationTitle($self->name); + ## set icon if not already set by external launcher + yui::YUI::app()->setApplicationIcon($self->icon); + + my $factory = yui::YUI::widgetFactory; + + my $dialog = $factory->createMainDialog; + my $vbox = $factory->createVBox( $dialog ); + my $frame = $factory->createFrame ($vbox, N("Please choose your type of mouse.")); + my $treeWidget = $factory->createTree($frame, ""); + + my $modules_conf = modules::any_conf->read; + + my $mouse = mouse::read(); + + if (!$::noauto) { + my $probed_mouse = mouse::detect($modules_conf); + $mouse = $probed_mouse if !$mouse->{Protocol} || !$probed_mouse->{unsafe}; + } + + if (!$mouse || !$::auto) { + $mouse ||= mouse::fullname2mouse('Universal|Any PS/2 & USB mice'); + + my $prev = my $fullname = $mouse->{type} . '|' . $mouse->{name}; + my $selected = $mouse->{name}; + + my $fullList = { list => [ mouse::_fullnames() ], items => [], separator => '|', val => \$fullname, + format => sub { join('|', map { translate($_) } split('\|', $_[0])) } } ; + my $i; + + my $itemColl = new yui::YItemCollection; + my @items; + for ($i=0; $i{list}}); $i++) { + my @names = split(/\|/, $fullList->{list}[$i]); + for (my $lev=0; $lev < scalar(@names); $lev++) { + $names[$lev] = N($names[$lev]); + } + if ($i == 0 || $names[0] ne $items[0]->{label}) { + if ($i != 0) { + $itemColl->push($items[0]->{item}); + push @{$fullList->{items}}, $items[-1]->{item};; + } + @items = undef; + my $item = new yui::YTreeItem ($names[0]); + + if ($selected eq $self->_getUntranslatedName($item->label(), $fullList->{list})) { + $item->setSelected(1) ; + $item->setOpen(1); + my $parent = $item; + while($parent = $parent->parent()) { + $parent->setOpen(1); + } + } + $item->DISOWN(); + @items = ({item => $item, label => $names[0], level => 0}); + for (my $lev=1; $lev < scalar(@names); $lev++) { + $item = new yui::YTreeItem ($items[$lev-1]->{item}, $names[$lev]); + + if ($selected eq $self->_getUntranslatedName($item->label(), $fullList->{list})) { + $item->setSelected(1) ; + $item->setOpen(1); + my $parent = $item; + while($parent = $parent->parent()) { + $parent->setOpen(1); + } + } + $item->DISOWN(); + if ($lev < scalar(@names)-1) { + push @items, {item => $item, label => $names[$lev], level => $lev}; + } + } + } + else { + my $prevItem = 0; + for (my $lev=1; $lev < scalar(@names); $lev++) { + my $it; + for ($it=1; $it < scalar(@items); $it++){ + if ($items[$it]->{label} eq $names[$lev] && $items[$it]->{level} == $lev) { + $prevItem = $it; + last; + } + } + if ($it == scalar(@items)) { + my $item = new yui::YTreeItem ($items[$prevItem]->{item}, $names[$lev]); + + if ($selected eq $self->_getUntranslatedName($item->label(), $fullList->{list})) { + $item->setSelected(1) ; + $item->setOpen(1); + my $parent = $item; + while($parent = $parent->parent()) { + $parent->setOpen(1); + } + } + $item->DISOWN(); + push @items, {item => $item, label => $names[$lev], level => $lev}; + } + } + } + } + $itemColl->push($items[0]->{item}); + push @{$fullList->{items}}, $items[-1]->{item}; + + $treeWidget->addItems($itemColl); + my $align = $factory->createLeft($vbox); + my $hbox = $factory->createHBox($align); + my $aboutButton = $factory->createPushButton($hbox, N("About") ); + $align = $factory->createRight($hbox); + $hbox = $factory->createHBox($align); + my $cancelButton = $factory->createPushButton($hbox, N("Cancel") ); + my $okButton = $factory->createPushButton($hbox, N("Ok") ); + + 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 selected + my $widget = $event->widget(); + + if ($widget == $cancelButton) { + last; + } + elsif ($widget == $aboutButton) { + my $license = translate($AdminPanel::Shared::License); + AdminPanel::Shared::AboutDialog( + { name => N("AdminMouse"), + version => $self->VERSION, + copyright => N("Copyright (C) %s Mageia community", '2014'), + license => $license, + comments => N("AdminMouse is the Mageia mouse management tool \n(from the original idea of Mandriva mousedrake)."), + website => 'http://www.mageia.org', + website_label => N("Mageia"), + authors => "Angelo Naselli \nMatteo Pasotti ", + translator_credits => + #-PO: put here name(s) and email(s) of translator(s) (eg: "John Smith ") + N("_: Translator(s) name(s) & email(s)\n")} + ); + } + elsif ($widget == $okButton) { + my $continue = 1; + my $selectedItem = $treeWidget->selectedItem(); + + my $it=$selectedItem; + my $fullname = $self->_getUntranslatedName($it->label(), $fullList->{list}); + while($it = yui::toYTreeItem($it)->parent()) { + $fullname = join("|", $self->_getUntranslatedName($it->label(), $fullList->{list}), $fullname); + } + + if ($fullname ne $prev) { + my $mouse_ = mouse::fullname2mouse($fullname, device => $mouse->{device}); + if ($fullname =~ /evdev/) { + $mouse_->{evdev_mice} = $mouse_->{evdev_mice_all} = $mouse->{evdev_mice_all}; + } + %$mouse = %$mouse_; + } + + if ($mouse->{nbuttons} < 3 ) { + $mouse->{Emulate3Buttons} = AdminPanel::Shared::ask_YesOrNo('', N("Emulate third button?")); + } + if ($mouse->{type} eq 'serial') { + my @list = (); + foreach (detect_devices::serialPorts()) { + push @list, detect_devices::serialPort2text($_); + } + my $choice = AdminPanel::Shared::ask_fromList(N("Mouse Port"), + N("Please choose which serial port your mouse is connected to."), + \@list); + if ( !$choice ) { + $continue = 0; + } + else { + $mouse->{device} = $choice; + } + } + + if ($continue) { + last; + } + } + } + } + + } + + # TODO manage write conf without interactive things + # mouse::write_conf($in->do_pkgs, $modules_conf, $mouse, 1); + system('systemctl', 'try-restart', 'gpm.service') if -e '/usr/lib/systemd/system/gpm.service'; + + $dialog->destroy(); + + #restore old application title + yui::YUI::app()->setApplicationTitle($appTitle); +} + +1; diff --git a/lib/AdminPanel/Module/Hosts.pm b/lib/AdminPanel/Module/Hosts.pm new file mode 100644 index 00000000..fe6e0117 --- /dev/null +++ b/lib/AdminPanel/Module/Hosts.pm @@ -0,0 +1,355 @@ +# vim: set et ts=4 sw=4: +#***************************************************************************** +# +# Copyright (c) 2013-2014 Matteo Pasotti +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** + +package AdminPanel::Module::Hosts; + +use Modern::Perl 2011; +use autodie; +use Moose; +use POSIX qw(ceil); +use utf8; + +use Glib; +use yui; +use AdminPanel::Shared; +use AdminPanel::Shared::Hosts; + +extends qw( AdminPanel::Module ); + + +has '+icon' => ( + default => "/usr/lib/libDrakX/icons/IC-Dhost-48.png" +); + +has '+name' => ( + default => "Hostmanager", +); + +=head1 VERSION + +Version 1.0.0 + +=cut + +our $VERSION = '1.0.0'; + +has 'dialog' => ( + is => 'rw', + init_arg => undef +); + +has 'table' => ( + is => 'rw', + init_arg => undef +); + +has 'cfgHosts' => ( + is => 'rw', + init_arg => undef +); + +sub start { + my $self = shift; + + $self->manageHostsDialog(); +}; + + +#============================================================= + +=head2 _addHostDialog + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + +This subroutine creates the Host dialog to add host definitions + +=cut + +#============================================================= +sub _manipulateHostDialog { + my $self = shift; + + my $headerString = shift(); + my $boolEdit = shift(); + + my $hostIpString = ""; + my $hostNameString = ""; + my $hostAliasesString = ""; + + if($boolEdit == 1){ + $hostIpString = shift(); + $hostNameString = shift(); + $hostAliasesString = shift(); + } + + my $factory = yui::YUI::widgetFactory; + my $dlg = $factory->createPopupDialog(); + my $layout = $factory->createVBox($dlg); + + my $hbox_header = $factory->createHBox($layout); + my $vbox_content = $factory->createVBox($layout); + my $hbox_footer = $factory->createHBox($layout); + + # header + my $labelDescription = $factory->createLabel($hbox_header,$headerString); + + # content + my $firstHbox = $factory->createHBox($vbox_content); + my $secondHbox = $factory->createHBox($vbox_content); + my $thirdHbox = $factory->createHBox($vbox_content); + + my $labelIPAddress = $factory->createLabel($firstHbox,"IP Address"); + my $labelHostName = $factory->createLabel($secondHbox,"Hostname"); + my $labelHostAlias = $factory->createLabel($thirdHbox,"Host aliases"); + $labelIPAddress->setWeight($yui::YD_HORIZ, 10); + $labelHostName->setWeight($yui::YD_HORIZ, 10); + $labelHostAlias->setWeight($yui::YD_HORIZ, 10); + + my $textIPAddress = $factory->createInputField($firstHbox,""); + my $textHostName = $factory->createInputField($secondHbox,""); + my $textHostAlias = $factory->createInputField($thirdHbox,""); + $textIPAddress->setWeight($yui::YD_HORIZ, 30); + $textHostName->setWeight($yui::YD_HORIZ, 30); + $textHostAlias->setWeight($yui::YD_HORIZ, 30); + + if($boolEdit == 1){ + $textIPAddress->setValue($hostIpString); + $textHostName->setValue($hostNameString); + $textHostAlias->setValue($hostAliasesString); + } + + # footer + my $cancelButton = $factory->createPushButton($factory->createLeft($hbox_footer),"Cancel"); + my $okButton = $factory->createPushButton($factory->createRight($hbox_footer),"OK"); + + while(1){ + my $event = $dlg->waitForEvent(); + my $eventType = $event->eventType(); + + #event type checking + if ($eventType == $yui::YEvent::CancelEvent) { + last; + } + elsif ($eventType == $yui::YEvent::WidgetEvent) { + # widget selected + my $widget = $event->widget(); + if ($widget == $cancelButton) { + last; + } + elsif($widget == $okButton) { + my $res = undef; + my @hosts_toadd; + push @hosts_toadd, $textHostName->value(); + if(trim($textHostAlias->value()) ne ""){ + push @hosts_toadd, $textHostAlias->value(); + } + print "@hosts_toadd\n"; + if($boolEdit == 0){ + $res = $self->cfgHosts->_insertHost($textIPAddress->value(),[@hosts_toadd]); + }else{ + $res = $self->cfgHosts->_modifyHost($textIPAddress->value(),[@hosts_toadd]); + } + $res = $self->cfgHosts->_writeHosts(); + print "Write result: $res\n"; + last; + } + } + } + + destroy $dlg; +} + +sub _addHostDialog { + my $self = shift(); + return $self->_manipulateHostDialog("Add the information",0); +} + +sub _edtHostDialog { + my $self = shift(); + my $hostIp = shift(); + my $hostName = shift(); + my $hostAliases = shift(); + return $self->_manipulateHostDialog("Modify the information",1,$hostIp,$hostName,$hostAliases); +} + +#============================================================= + +=head2 setupTable + +=head3 INPUT + + $self: this object + + $data: reference to the array containaing the host data to show into the table + +=head3 DESCRIPTION + +This subroutine populates a previously created YTable with the hosts data +retrieved by the Config::Hosts module + +=cut + +#============================================================= +sub setupTable { + my $self = shift(); + + my @hosts = $self->cfgHosts->_getHosts(); + # clear table + $self->table->deleteAllItems(); + foreach my $host (@hosts){ + my $tblItem; + my $aliases = join(',',@{$host->{'hosts'}}); + if(scalar(@{$host->{'hosts'}}) > 1){ + $aliases =~s/^$host->{'hosts'}[0]\,*//g; + }elsif(scalar(@{$host->{'hosts'}}) == 1){ + $aliases = ""; + } + $tblItem = new yui::YTableItem($host->{'ip'},$host->{'hosts'}[0],$aliases); + $self->table->addItem($tblItem); + } +} + +sub manageHostsDialog { + my $self = shift; + + ## TODO fix for adminpanel + my $appTitle = yui::YUI::app()->applicationTitle(); + my $appIcon = yui::YUI::app()->applicationIcon(); + ## set new title to get it in dialog + my $newTitle = "Manage hosts definitions"; + yui::YUI::app()->setApplicationTitle($newTitle); + + my $factory = yui::YUI::widgetFactory; + my $optional = yui::YUI::optionalWidgetFactory; + + + $self->dialog($factory->createMainDialog()); + my $layout = $factory->createVBox($self->dialog); + + my $hbox_header = $factory->createHBox($layout); + my $headLeft = $factory->createHBox($factory->createLeft($hbox_header)); + my $headRight = $factory->createHBox($factory->createRight($hbox_header)); + + my $logoImage = $factory->createImage($headLeft, $appIcon); + my $labelAppDescription = $factory->createLabel($headRight,$newTitle); + $logoImage->setWeight($yui::YD_HORIZ,0); + $labelAppDescription->setWeight($yui::YD_HORIZ,3); + + my $hbox_content = $factory->createHBox($layout); + + my $tableHeader = new yui::YTableHeader(); + $tableHeader->addColumn("IP Address"); + $tableHeader->addColumn("Hostname"); + $tableHeader->addColumn("Host Aliases"); + my $leftContent = $factory->createLeft($hbox_content); + $leftContent->setWeight($yui::YD_HORIZ,45); + $self->table($factory->createTable($leftContent,$tableHeader)); + + # initialize Config::Hosts + $self->cfgHosts(AdminPanel::Shared::Hosts->new()); + $self->setupTable(); + + my $rightContent = $factory->createRight($hbox_content); + $rightContent->setWeight($yui::YD_HORIZ,10); + my $topContent = $factory->createTop($rightContent); + my $vbox_commands = $factory->createVBox($topContent); + my $addButton = $factory->createPushButton($factory->createHBox($vbox_commands),"Add"); + my $edtButton = $factory->createPushButton($factory->createHBox($vbox_commands),"Edit"); + my $remButton = $factory->createPushButton($factory->createHBox($vbox_commands),"Remove"); + $addButton->setWeight($yui::YD_HORIZ,1); + $edtButton->setWeight($yui::YD_HORIZ,1); + $remButton->setWeight($yui::YD_HORIZ,1); + + my $hbox_foot = $factory->createHBox($layout); + my $vbox_foot_left = $factory->createVBox($factory->createLeft($hbox_foot)); + my $vbox_foot_right = $factory->createVBox($factory->createRight($hbox_foot)); + my $aboutButton = $factory->createPushButton($vbox_foot_left,"About"); + my $cancelButton = $factory->createPushButton($vbox_foot_right,"Cancel"); + my $okButton = $factory->createPushButton($vbox_foot_right,"OK"); + + # main loop + while(1) { + my $event = $self->dialog->waitForEvent(); + my $eventType = $event->eventType(); + + #event type checking + if ($eventType == $yui::YEvent::CancelEvent) { + last; + } + elsif ($eventType == $yui::YEvent::WidgetEvent) { +### Buttons and widgets ### + my $widget = $event->widget(); + if ($widget == $cancelButton) { + last; + } + elsif ($widget == $addButton) { + $self->_addHostDialog(); + $self->setupTable(); + } + elsif ($widget == $edtButton) { + my $tblItem = yui::toYTableItem($self->table->selectedItem()); + if($tblItem->cellCount() >= 3){ + $self->_edtHostDialog($tblItem->cell(0)->label(),$tblItem->cell(1)->label(),$tblItem->cell(2)->label()); + }else{ + $self->_edtHostDialog($tblItem->cell(0)->label(),$tblItem->cell(1)->label(),""); + } + $self->setupTable(); + } + elsif ($widget == $remButton) { + # implement deletion dialog + if(AdminPanel::Shared::ask_YesOrNo("Confirmation","Are you sure to drop this host?") == 1){ + my $tblItem = yui::toYTableItem($self->table->selectedItem()); + # drop the host using the ip + $self->cfgHosts->_dropHost($tblItem->cell(0)->label()); + # write changes + $self->cfgHosts->_writeHosts(); + $self->setupTable(); + } + }elsif ($widget == $aboutButton) { + AdminPanel::Shared::AboutDialog({ + name => $appTitle, + version => $VERSION, + copyright => "Copyright (c) 2013-2014 by Matteo Pasotti", + license => $AdminPanel::Shared::License, + comments => "Graphical manager for hosts definitions", + website => "http://gitweb.mageia.org/software/adminpanel", + website_label => "WebSite", + authors => "Matteo Pasotti " + } + ); + }elsif ($widget == $okButton) { + # write changes + $self->cfgHosts->_writeHosts(); + last; + } + } + } + + $self->dialog->destroy() ; + + #restore old application title + yui::YUI::app()->setApplicationTitle($appTitle); +} + +1; diff --git a/lib/AdminPanel/Module/Services.pm b/lib/AdminPanel/Module/Services.pm new file mode 100644 index 00000000..33326379 --- /dev/null +++ b/lib/AdminPanel/Module/Services.pm @@ -0,0 +1,559 @@ +# vim: set et ts=4 sw=4: +#***************************************************************************** +# +# Copyright (c) 2013 Angelo Naselli +# from drakx services +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** + +package AdminPanel::Module::Services; + +#-###################################################################################### +#- misc imports +#-###################################################################################### + +use strict; + +# TODO same translation atm +use lib qw(/usr/lib/libDrakX); +use common qw(N + N_ + cat_ + formatAlaTeX + translate + find); +use run_program; + +use Moose; + +use yui; +use AdminPanel::Shared; +use AdminPanel::Shared::Services qw( + services + xinetd_services + is_service_running + restart_or_start + stop + set_service + ); + +use File::Basename; + +extends qw( AdminPanel::Module ); + +has '+icon' => ( + default => "/usr/share/mcc/themes/default/service-mdk.png", +); + +has '+name' => ( + default => N("AdminService"), +); + +has 'services' => ( + traits => ['Array'], + is => 'rw', + isa => 'ArrayRef[Str]', + default => sub { [] }, + init_arg => undef, + handles => { + all_services => 'elements', + add_service => 'push', + map_service => 'map', + service_count => 'count', + sorted_services => 'sort', + }, +); + +has 'xinetd_services' => ( + traits => ['Array'], + is => 'rw', + isa => 'ArrayRef[Str]', + default => sub { [] }, + init_arg => undef, + handles => { + all_xinetd_services => 'elements', + add_xinetd_service => 'push', + map_xinetd_service => 'map', + xinetd_service_count => 'count', + sorted_xinetd_services => 'sort', + }, +); + +has 'on_services' => ( + traits => ['Array'], + is => 'rw', + isa => 'ArrayRef[Str]', + default => sub { [] }, + init_arg => undef, + handles => { + all_on_services => 'elements', + add_on_service => 'push', + map_on_service => 'map', + on_service_count => 'count', + sorted_on_services => 'sort', + }, +); + + +has 'running_services' => ( + traits => ['Array'], + is => 'rw', + isa => 'ArrayRef[Str]', + default => sub { [] }, + init_arg => undef, + handles => { + all_running_services => 'elements', + add_running_service => 'push', + map_running_service => 'map', + running_service_count => 'count', + sorted_running_services => 'sort', + }, +); +=head1 VERSION + +Version 1.0.0 + +=cut + +our $VERSION = '1.0.0'; + + +sub description { + my %services = ( +acpid => N_("Listen and dispatch ACPI events from the kernel"), +alsa => N_("Launch the ALSA (Advanced Linux Sound Architecture) sound system"), +anacron => N_("Anacron is a periodic command scheduler."), +apmd => N_("apmd is used for monitoring battery status and logging it via syslog. +It can also be used for shutting down the machine when the battery is low."), +atd => N_("Runs commands scheduled by the at command at the time specified when +at was run, and runs batch commands when the load average is low enough."), +'avahi-deamon' => N_("Avahi is a ZeroConf daemon which implements an mDNS stack"), +chronyd => N_("An NTP client/server"), +cpufreq => N_("Set CPU frequency settings"), +crond => N_("cron is a standard UNIX program that runs user-specified programs +at periodic scheduled times. vixie cron adds a number of features to the basic +UNIX cron, including better security and more powerful configuration options."), +cups => N_("Common UNIX Printing System (CUPS) is an advanced printer spooling system"), +dm => N_("Launches the graphical display manager"), +fam => N_("FAM is a file monitoring daemon. It is used to get reports when files change. +It is used by GNOME and KDE"), +g15daemon => N_("G15Daemon allows users access to all extra keys by decoding them and +pushing them back into the kernel via the linux UINPUT driver. This driver must be loaded +before g15daemon can be used for keyboard access. The G15 LCD is also supported. By default, +with no other clients active, g15daemon will display a clock. Client applications and +scripts can access the LCD via a simple API."), +gpm => N_("GPM adds mouse support to text-based Linux applications such the +Midnight Commander. It also allows mouse-based console cut-and-paste operations, +and includes support for pop-up menus on the console."), +haldaemon => N_("HAL is a daemon that collects and maintains information about hardware"), +harddrake => N_("HardDrake runs a hardware probe, and optionally configures +new/changed hardware."), +httpd => N_("Apache is a World Wide Web server. It is used to serve HTML files and CGI."), +inet => N_("The internet superserver daemon (commonly called inetd) starts a +variety of other internet services as needed. It is responsible for starting +many services, including telnet, ftp, rsh, and rlogin. Disabling inetd disables +all of the services it is responsible for."), +ip6tables => N_("Automates a packet filtering firewall with ip6tables"), +iptables => N_("Automates a packet filtering firewall with iptables"), +irqbalance => N_("Evenly distributes IRQ load across multiple CPUs for enhanced performance"), +keytable => N_("This package loads the selected keyboard map as set in +/etc/sysconfig/keyboard. This can be selected using the kbdconfig utility. +You should leave this enabled for most machines."), +kheader => N_("Automatic regeneration of kernel header in /boot for +/usr/include/linux/{autoconf,version}.h"), +kudzu => N_("Automatic detection and configuration of hardware at boot."), +'laptop-mode' => N_("Tweaks system behavior to extend battery life"), +linuxconf => N_("Linuxconf will sometimes arrange to perform various tasks +at boot-time to maintain the system configuration."), +lpd => N_("lpd is the print daemon required for lpr to work properly. It is +basically a server that arbitrates print jobs to printer(s)."), +lvs => N_("Linux Virtual Server, used to build a high-performance and highly +available server."), +mandi => N_("Monitors the network (Interactive Firewall and wireless"), +mdadm => N_("Software RAID monitoring and management"), +messagebus => N_("DBUS is a daemon which broadcasts notifications of system events and other messages"), +msec => N_("Enables MSEC security policy on system startup"), +named => N_("named (BIND) is a Domain Name Server (DNS) that is used to resolve host names to IP addresses."), +netconsole => N_("Initializes network console logging"), +netfs => N_("Mounts and unmounts all Network File System (NFS), SMB (Lan +Manager/Windows), and NCP (NetWare) mount points."), +network => N_("Activates/Deactivates all network interfaces configured to start +at boot time."), +'network-auth' => N_("Requires network to be up if enabled"), +'network-up' => N_("Wait for the hotplugged network to be up"), +nfs => N_("NFS is a popular protocol for file sharing across TCP/IP networks. +This service provides NFS server functionality, which is configured via the +/etc/exports file."), +nfslock => N_("NFS is a popular protocol for file sharing across TCP/IP +networks. This service provides NFS file locking functionality."), +ntpd => N_("Synchronizes system time using the Network Time Protocol (NTP)"), +numlock => N_("Automatically switch on numlock key locker under console +and Xorg at boot."), +oki4daemon => N_("Support the OKI 4w and compatible winprinters."), +partmon => N_("Checks if a partition is close to full up"), +pcmcia => N_("PCMCIA support is usually to support things like ethernet and +modems in laptops. It will not get started unless configured so it is safe to have +it installed on machines that do not need it."), +portmap => N_("The portmapper manages RPC connections, which are used by +protocols such as NFS and NIS. The portmap server must be running on machines +which act as servers for protocols which make use of the RPC mechanism."), +portreserve => N_("Reserves some TCP ports"), +postfix => N_("Postfix is a Mail Transport Agent, which is the program that moves mail from one machine to another."), +random => N_("Saves and restores system entropy pool for higher quality random +number generation."), +rawdevices => N_("Assign raw devices to block devices (such as hard disk drive +partitions), for the use of applications such as Oracle or DVD players"), +resolvconf => N_("Nameserver information manager"), +routed => N_("The routed daemon allows for automatic IP router table updated via +the RIP protocol. While RIP is widely used on small networks, more complex +routing protocols are needed for complex networks."), +rstatd => N_("The rstat protocol allows users on a network to retrieve +performance metrics for any machine on that network."), +rsyslog => N_("Syslog is the facility by which many daemons use to log messages to various system log files. It is a good idea to always run rsyslog."), +rusersd => N_("The rusers protocol allows users on a network to identify who is +logged in on other responding machines."), +rwhod => N_("The rwho protocol lets remote users get a list of all of the users +logged into a machine running the rwho daemon (similar to finger)."), +saned => N_("SANE (Scanner Access Now Easy) enables to access scanners, video cameras, ..."), +shorewall => N_("Packet filtering firewall"), +smb => N_("The SMB/CIFS protocol enables to share access to files & printers and also integrates with a Windows Server domain"), +sound => N_("Launch the sound system on your machine"), +'speech-dispatcherd' => N_("layer for speech analysis"), +sshd => N_("Secure Shell is a network protocol that allows data to be exchanged over a secure channel between two computers"), +syslog => N_("Syslog is the facility by which many daemons use to log messages +to various system log files. It is a good idea to always run syslog."), +'udev-post' => N_("Moves the generated persistent udev rules to /etc/udev/rules.d"), +usb => N_("Load the drivers for your usb devices."), +vnStat => N_("A lightweight network traffic monitor"), +xfs => N_("Starts the X Font Server."), +xinetd => N_("Starts other deamons on demand."), + ); + my ($name) = @_; + my $s = $services{$name}; + if ($s) { + $s = translate($s); + } else { + my $file = "$::prefix/usr/lib/systemd/system/$name.service"; + if (-e $file) { + $s = cat_($file); + $s = $s =~ /^Description=(.*)/mg ? $1 : ''; + } else { + $file = find { -e $_ } map { "$::prefix$_/$name" } '/etc/rc.d/init.d', '/etc/init.d', '/etc/xinetd.d'; + $s = cat_($file); + $s =~ s/\\\s*\n#\s*//mg; + $s = + $s =~ /^#\s+(?:Short-)?[dD]escription:\s+(.*?)^(?:[^#]|# {0,2}\S)/sm ? $1 : + $s =~ /^#\s*(.*?)^[^#]/sm ? $1 : ''; + + $s =~ s/#\s*//mg; + } + } + $s =~ s/\n/ /gm; $s =~ s/\s+$//; + $s; +} + +sub BUILD { + my $self = shift; + + $self->loadServices(); +} + + +#============================================================= + +=head2 start + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + This method extends Module::start and is invoked to + start adminService + +=cut + +#============================================================= +sub start { + my $self = shift; + + $self->servicePanel(); +}; + + +#============================================================= + +=head2 loadServices + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + This methonds load service info into local attributes such + as xinetd_services, on_services and all the available, + services + +=cut + +#============================================================= +sub loadServices { + my $self = shift; + + my ($l, $on_services) = AdminPanel::Shared::Services::services(); + my @xinetd_services = map { $_->[0] } AdminPanel::Shared::Services::xinetd_services(); + + $self->xinetd_services(); + $self->xinetd_services(\@xinetd_services); + $self->services(\@$l); + $self->on_services(\@$on_services); + + $self->refreshRunningServices(); +} + +sub refreshRunningServices { + my $self = shift; + + my @running; + foreach ($self->all_services) { + + my $serviceName = $_; + push @running, $serviceName if is_service_running($serviceName); + } + $self->running_services(\@running); +} + +## serviceInfo sets widgets accordingly to selected service status +## param +## 'service' service name +## 'infoPanel' service information widget +sub serviceInfo { + my ($self, $service, $infoPanel) = @_; + + yui::YUI::ui()->blockEvents(); + ## infoPanel + $infoPanel->setValue(formatAlaTeX(description($service))); + yui::YUI::ui()->unblockEvents(); +} + +sub serviceStatus { + my ($self, $tbl, $item) = @_; + + my $started; + + if (member($item->label(), $self->all_xinetd_services)) { + $started = N("Start when requested"); + } + else { + $started = (member($item->label(), $self->all_running_services)? N("running") : N("stopped")); + } +# TODO add icon green/red led + my $cell = $tbl->toCBYTableItem($item)->cell(1); + if ($cell) { + $cell->setLabel($started); + $tbl->cellChanged($cell); + } +} + +## draw service panel and manage it +sub servicePanel { + my $self = shift; + + my $appTitle = yui::YUI::app()->applicationTitle(); + + ## set new title to get it in dialog + yui::YUI::app()->setApplicationTitle($self->name); + ## set icon if not already set by external launcher + yui::YUI::app()->setApplicationIcon($self->icon); + +# my ($l, $on_services) = services(); +# my @xinetd_services = map { $_->[0] } xinetd_services(); + + my $mageiaPlugin = "mga"; + my $factory = yui::YUI::widgetFactory; + my $mgaFactory = yui::YExternalWidgets::externalWidgetFactory($mageiaPlugin); + $mgaFactory = yui::YMGAWidgetFactory::getYMGAWidgetFactory($mgaFactory); + + my $dialog = $factory->createMainDialog; + my $vbox = $factory->createVBox( $dialog ); + my $frame = $factory->createFrame ($vbox, N("Services")); + + my $frmVbox = $factory->createVBox( $frame ); + my $hbox = $factory->createHBox( $frmVbox ); + + my $yTableHeader = new yui::YTableHeader(); + $yTableHeader->addColumn(N("Service"), $yui::YAlignBegin); + $yTableHeader->addColumn(N("Status"), $yui::YAlignCenter); + $yTableHeader->addColumn(N("On boot"), $yui::YAlignBegin); + + ## service list (serviceBox) + my $serviceTbl = $mgaFactory->createCBTable($hbox, $yTableHeader, $yui::YCBTableCheckBoxOnLastColumn); + my $itemCollection = new yui::YItemCollection; + foreach ($self->all_services) { + + my $serviceName = $_; + + my $item = new yui::YCBTableItem($serviceName); + my $started; + if (member($serviceName, $self->all_xinetd_services)) { + $started = N("Start when requested"); + } + else { + $started = (member($serviceName, $self->all_running_services)? N("running") : N("stopped")); + } + +# TODO add icon green/red led + my $cell = new yui::YTableCell($started); + $item->addCell($cell); + + $item->check(member($serviceName, $self->all_on_services)); + $item->setLabel($serviceName); + $itemCollection->push($item); + $item->DISOWN(); + } + $serviceTbl->addItems($itemCollection); + $serviceTbl->setImmediateMode(1); + $serviceTbl->setWeight(0, 50); + + ## info panel (infoPanel) + $frame = $factory->createFrame ($hbox, N("Information")); + $frame->setWeight(0, 30); + $frmVbox = $factory->createVBox( $frame ); + my $infoPanel = $factory->createRichText($frmVbox, "--------------"); #, 0, 0); + $infoPanel->setAutoScrollDown(); + + ### Service Start button ($startButton) + $hbox = $factory->createHBox( $frmVbox ); + my $startButton = $factory->createPushButton($hbox, N("Start")); + + ### Service Stop button ($stopButton) + my $stopButton = $factory->createPushButton($hbox, N("Stop")); + + # dialog buttons + $factory->createVSpacing($vbox, 1.0); + ## Window push buttons + $hbox = $factory->createHBox( $vbox ); + my $align = $factory->createLeft($hbox); + $hbox = $factory->createHBox($align); + my $aboutButton = $factory->createPushButton($hbox, N("About") ); + $align = $factory->createRight($hbox); + $hbox = $factory->createHBox($align); + my $closeButton = $factory->createPushButton($hbox, N("Close") ); + + #first item status + my $item = $serviceTbl->selectedItem(); + if ($item) { + $self->serviceInfo($item->label(), $infoPanel); + if (member($item->label(), $self->all_xinetd_services)) { + $stopButton->setDisabled(); + $startButton->setDisabled(); + } + else { + $stopButton->setEnabled(1); + $startButton->setEnabled(1); + } + } + + 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 selected + my $widget = $event->widget(); + my $wEvent = yui::toYWidgetEvent($event); + + if ($widget == $closeButton) { + last; + } + elsif ($widget == $aboutButton) { + my $license = translate($AdminPanel::Shared::License); + # TODO fix version value + AboutDialog({ name => N("AdminService"), + version => $self->VERSION, + copyright => N("Copyright (C) %s Mageia community", '2013-2014'), + license => $license, + comments => N("Service Manager is the Mageia service and daemon management tool \n(from the original idea of Mandriva draxservice)."), + website => 'http://www.mageia.org', + website_label => N("Mageia"), + authors => "Angelo Naselli \nMatteo Pasotti ", + translator_credits => + #-PO: put here name(s) and email(s) of translator(s) (eg: "John Smith ") + N("_: Translator(s) name(s) & email(s)\n")} + ); + } + elsif ($widget == $serviceTbl) { + + # service selection changed + $item = $serviceTbl->selectedItem(); + if ($item) { + $self->serviceInfo($item->label(), $infoPanel); + if (member($item->label(), $self->all_xinetd_services)) { + $stopButton->setDisabled(); + $startButton->setDisabled(); + } + else { + $stopButton->setEnabled(1); + $startButton->setEnabled(1); + } + } +# TODO fix libyui-mga-XXX item will always be changed after first one + if ($wEvent->reason() == $yui::YEvent::ValueChanged) { + $item = $serviceTbl->changedItem(); + if ($item) { + + set_service($item->label(), $item->checked()); + # we can push/pop service, but this (slower) should return real situation + $self->refreshRunningServices(); + } + } + } + elsif ($widget == $startButton) { + $item = $serviceTbl->selectedItem(); + if ($item) { + restart_or_start($item->label()); + # we can push/pop service, but this (slower) should return real situation + $self->refreshRunningServices(); + $self->serviceStatus($serviceTbl, $item); + } + } + elsif ($widget == $stopButton) { + $item = $serviceTbl->selectedItem(); + if ($item) { + stop($item->label()); + # we can push/pop service, but this (slower) should return real situation + $self->refreshRunningServices(); + $self->serviceStatus($serviceTbl, $item); + } + } + } + } + $dialog->destroy(); + + #restore old application title + yui::YUI::app()->setApplicationTitle($appTitle) if $appTitle; +} + +no Moose; +__PACKAGE__->meta->make_immutable; + +1; diff --git a/lib/AdminPanel/Module/Users.pm b/lib/AdminPanel/Module/Users.pm new file mode 100644 index 00000000..16ea058a --- /dev/null +++ b/lib/AdminPanel/Module/Users.pm @@ -0,0 +1,2570 @@ +# vim: set et ts=4 sw=4: +#***************************************************************************** +# +# Copyright (c) 2013 Angelo Naselli +# from adduserdrake and userdrake +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** + +package AdminPanel::Module::Users; + +############################################### +## +## graphic related routines for managing user +## +############################################### + + +use strict; +# TODO evaluate if Moose is too heavy and use Moo +# instead +use POSIX qw(ceil); +# use Time::localtime; + +# TODO same translation atm +use lib qw(/usr/lib/libDrakX); +# i18n: IMPORTANT: to get correct namespace (userdrake instead of libDrakX) +BEGIN { unshift @::textdomains, 'userdrake', 'libuser', 'drakconf' } + +use common qw(N + translate); +use security::level; +use run_program; +## USER is from userdrake +use USER; +use utf8; +use log; + +use Glib; +use yui; +use AdminPanel::Shared; +use AdminPanel::Shared::Users; +use Moose; +extends qw( AdminPanel::Module ); + +has '+icon' => ( + default => "/usr/share/icons/userdrake.png", +); + +has '+name' => ( + default => N("AdminUser"), +); + + +=head1 VERSION + +Version 1.0.0 + +=cut + +our $VERSION = '1.0.0'; + +# main dialog +has 'dialog' => ( + is => 'rw', + init_arg => undef, +); + +has 'widgets' => ( + traits => ['Hash'], + default => sub { {} }, + is => 'rw', + isa => 'HashRef', + handles => { + set_widget => 'set', + get_widget => 'get', + widget_pairs => 'kv', + }, + init_arg => undef, +); + +has 'action_menu' => ( + traits => ['Hash'], + default => sub { {} }, + is => 'rw', + isa => 'HashRef', + handles => { + set_action_menu => 'set', + get_action_menu => 'get', + action_menu_pairs => 'kv', + }, + init_arg => undef, +); + +## Used by USER (for getting values? TODO need explanations, where?) +has 'USER_GetValue' => ( + default => -65533, + is => 'ro', + isa => 'Int', + init_arg => undef, +); + +## Used by USER (for getting values? TODO need explanations, where?) +has 'ctx' => ( + default => sub {USER::ADMIN->new}, + is => 'ro', + init_arg => undef, +); + + +has 'edit_tab_widgets' => ( + traits => ['Hash'], + default => sub { {} }, + is => 'rw', + isa => 'HashRef', + handles => { + set_edit_tab_widget => 'set', + get_edit_tab_widget => 'get', + edit_tab_pairs => 'kv', + }, + init_arg => undef, +); + +sub start { + my $self = shift; + + $self->manageUsersDialog(); +}; + +# TODO move to Shared? +sub labeledFrameBox { + my ($parent, $label) = @_; + + my $factory = yui::YUI::widgetFactory; + + my $frame = $factory->createFrame($parent, $label); + $frame->setWeight( $yui::YD_HORIZ, 1); + $frame->setWeight( $yui::YD_VERT, 2); + $frame = $factory->createHVCenter( $frame ); + $frame = $factory->createVBox( $frame ); + return $frame; +} + +# usefull local variable to avoid duplicating +# translation point for user edit labels +my %userEditLabel = ( + user_data => N("User Data"), + account_info => N("Account Info"), + password_info => N("Password Info"), + groups => N("Groups"), +); +# usefull local variable to avoid duplicating +# translation point for group edit labels +my %groupEditLabel = ( + group_data => N("Group Data"), + group_users => N("Group Users"), +); +#============================================================= + +=head2 ChooseGroup + +=head3 INPUT + + $self: this object + +=head3 OUTPUT + + $choice: 0 or 1 (choice) + -1 cancel or exit + +=head3 DESCRIPTION + +creates a popup dialog to ask if adding user to an existing +group or to the 'users' group + +=cut + +#============================================================= +sub ChooseGroup { + my $self = shift; + + my $choice = -1; + + ## push application title + my $appTitle = yui::YUI::app()->applicationTitle(); + ## set new title to get it in dialog + yui::YUI::app()->setApplicationTitle(N("Choose group")); + + my $factory = yui::YUI::widgetFactory; + + my $dlg = $factory->createPopupDialog(); + my $layout = $factory->createVBox($dlg); + + + my $frame = labeledFrameBox($layout, N("A group with this name already exists. What would you like to do?")); + + my $rbg = $factory->createRadioButtonGroup( $frame ); + $frame = $factory->createVBox( $rbg ); + my $align = $factory->createLeft($frame); + + my $rb1 = $factory->createRadioButton( $align, N("Add to the existing group"), 1); + $rb1->setNotify(1); + $rbg->addRadioButton( $rb1 ); + $align = $factory->createLeft($frame); + my $rb2 = $factory->createRadioButton( $align, N("Add to the 'users' group"), 0); + $rb2->setNotify(1); + $rbg->addRadioButton( $rb2 ); + + my $hbox = $factory->createHBox($layout); + $align = $factory->createRight($hbox); + my $cancelButton = $factory->createPushButton($align, N("Cancel")); + my $okButton = $factory->createPushButton($hbox, N("Ok")); + while(1) { + my $event = $dlg->waitForEvent(); + my $eventType = $event->eventType(); + + #event type checking + if ($eventType == $yui::YEvent::CancelEvent) { + last; + } + elsif ($eventType == $yui::YEvent::WidgetEvent) { + # widget selected + my $widget = $event->widget(); + if ($widget == $cancelButton) { + last; + } + if ($widget == $okButton) { + $choice = $rb1->value() ? 0 : 1 ; + last; + } + } + } + + destroy $dlg; + + #restore old application title + yui::YUI::app()->setApplicationTitle($appTitle); + + return $choice; +} + +#============================================================= + +=head2 _updateOrDelUsersInGroup + +=head3 INPUT + + $name: username + +=head3 DESCRIPTION + + Fixes user deletion into groups. + +=cut + +#============================================================= +sub _updateOrDelUserInGroup { + my ($self, $name) = @_; + my $groups = $self->ctx->GroupsEnumerateFull; + foreach my $g (@$groups) { + my $members = $g->MemberName(1, 0); + if ($self->_inArray($name, $members)) { + eval { $g->MemberName($name, 2) }; + eval { $self->ctx->GroupModify($g) }; + } + } +} + +#============================================================= + +=head2 _deleteGroupDialog + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + This method open a dialog to delete the selected group. + +=cut + +#============================================================= +sub _deleteGroupDialog { + my $self = shift; + + my $item = $self->get_widget('table')->selectedItem(); + if (! $item) { + return; + } + + my $groupname = $item->label(); + ## push application title + my $appTitle = yui::YUI::app()->applicationTitle(); + ## set new title to get it in dialog + yui::YUI::app()->setApplicationTitle(N("Warning")); + + my $factory = yui::YUI::widgetFactory; + my $dlg = $factory->createPopupDialog(); + my $layout = $factory->createVBox($dlg); + + my $align = $factory->createLeft($layout); + + $factory->createLabel($align, N("Do you really want to delete the group %s?", + $groupname)); + + $align = $factory->createRight($layout); + my $hbox = $factory->createHBox($align); + my $cancelButton = $factory->createPushButton($hbox, N("Cancel")); + my $deleteButton = $factory->createPushButton($hbox, N("Delete")); + + while(1) { + my $event = $dlg->waitForEvent(); + my $eventType = $event->eventType(); + + #event type checking + if ($eventType == $yui::YEvent::CancelEvent) { + last; + } + elsif ($eventType == $yui::YEvent::WidgetEvent) { + # widget selected + my $widget = $event->widget(); + if ($widget == $cancelButton) { + last; + } + elsif ($widget == $deleteButton) { + my $groupEnt = $self->ctx->LookupGroupByName($groupname); + my $members = $self->ctx->EnumerateUsersByGroup($groupname); + my $continue = 1; + GLOOP: foreach my $username (@$members) { + my $userEnt = $self->ctx->LookupUserByName($username); + if ($userEnt && $userEnt->Gid($self->USER_GetValue) == $groupEnt->Gid($self->USER_GetValue)) { + AdminPanel::Shared::msgBox(N("%s is a primary group for user %s\n Remove the user first", + $groupname, $username)); + $continue = 0; + last GLOOP; + } + } + if ($continue) { + log::explanations(N("Removing group: %s", $groupname)); + eval { $self->ctx->GroupDel($groupEnt) }; + $self->_refresh(); + } + last; + } + } + } + + destroy $dlg; + + #restore old application title + yui::YUI::app()->setApplicationTitle($appTitle); +} + +#============================================================= + +=head2 _deleteUserDialog + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + This method open a dialog to delete the selected user. + It also asks for additional information to be removed. + +=cut + +#============================================================= +sub _deleteUserDialog { + my $self = shift; + + my $item = $self->get_widget('table')->selectedItem(); + if (! $item) { + return; + } + my $username = $item->label(); + + my $userEnt = $self->ctx->LookupUserByName($username); + my $homedir = $userEnt->HomeDir($self->USER_GetValue); + + ## push application title + my $appTitle = yui::YUI::app()->applicationTitle(); + ## set new title to get it in dialog + yui::YUI::app()->setApplicationTitle(N("Delete files or not?")); + + my $factory = yui::YUI::widgetFactory; + my $dlg = $factory->createPopupDialog(); + my $layout = $factory->createVBox($dlg); + + my $align = $factory->createLeft($layout); + $factory->createLabel($align, N("Deleting user %s\nAlso perform the following actions\n", + $username)); + $align = $factory->createLeft($layout); + my $checkhome = $factory->createCheckBox($align, N("Delete Home Directory: %s", $homedir, 0)); + $align = $factory->createLeft($layout); + my $checkspool = $factory->createCheckBox($align, N("Delete Mailbox: /var/spool/mail/%s", + $username), 0); + $align = $factory->createRight($layout); + my $hbox = $factory->createHBox($align); + my $cancelButton = $factory->createPushButton($hbox, N("Cancel")); + my $deleteButton = $factory->createPushButton($hbox, N("Delete")); + + if ($homedir !~ m!(?:/home|/var/spool)!) { + $checkhome->setDisabled(); + $checkspool->setDisabled(); + } + + + while(1) { + my $event = $dlg->waitForEvent(); + my $eventType = $event->eventType(); + + #event type checking + if ($eventType == $yui::YEvent::CancelEvent) { + last; + } + elsif ($eventType == $yui::YEvent::WidgetEvent) { + # widget selected + my $widget = $event->widget(); + if ($widget == $cancelButton) { + last; + } + elsif ($widget == $deleteButton) { + log::explanations(N("Removing user: %s", $username)); + $self->ctx->UserDel($userEnt); + $self->_updateOrDelUserInGroup($username); + #Let's check out the user's primary group + my $usergid = $userEnt->Gid($self->USER_GetValue); + my $groupEnt = $self->ctx->LookupGroupById($usergid); + if ($groupEnt) { + my $member = $groupEnt->MemberName(1, 0); + if (scalar(@$member) == 0 && $groupEnt->Gid($self->USER_GetValue) > 499) { + $self->ctx->GroupDel($groupEnt); + } + } + if ($checkhome->isChecked()) { + eval { $self->ctx->CleanHome($userEnt) }; + $@ and AdminPanel::Shared::msgBox($@) and last; + } + if ($checkspool->isChecked()) { + eval { $self->ctx->CleanSpool($userEnt) }; + $@ and AdminPanel::Shared::msgBox($@) and last; + } + $self->_refresh(); + last; + } + } + } + + destroy $dlg; + + #restore old application title + yui::YUI::app()->setApplicationTitle($appTitle); + +} + + +sub _addGroupDialog { + my $self = shift; + + my $is_system = 0; + + ## push application title + my $appTitle = yui::YUI::app()->applicationTitle(); + ## set new title to get it in dialog + yui::YUI::app()->setApplicationTitle(N("Create New Group")); + my $factory = yui::YUI::widgetFactory; + my $optional = yui::YUI::optionalWidgetFactory; + + my $dlg = $factory->createPopupDialog(); + my $layout = $factory->createVBox($dlg); + + ## 'group name' + my $align = $factory->createRight($layout); + my $hbox = $factory->createHBox($align); + my $label = $factory->createLabel($hbox, N("Group Name:") ); + my $groupName = $factory->createInputField($hbox, "", 0); + $label->setWeight($yui::YD_HORIZ, 1); + $groupName->setWeight($yui::YD_HORIZ, 2); + + $factory->createVSpacing($layout, 1); + + # Specify group id manually + $align = $factory->createLeft($layout); + $hbox = $factory->createHBox($align); + my $gidManually = $factory->createCheckBox($hbox, N("Specify group ID manually"), 0); + $factory->createHSpacing($hbox, 2); + my $GID = $factory->createIntField($hbox, N("GID"), 1, 65000, 500); + $GID->setEnabled($gidManually->value()); + $gidManually->setNotify(1); + + $hbox = $factory->createHBox($layout); + $align = $factory->createRight($hbox); + my $cancelButton = $factory->createPushButton($align, N("Cancel")); + my $okButton = $factory->createPushButton($hbox, N("Ok")); + while(1) { + my $event = $dlg->waitForEvent(); + my $eventType = $event->eventType(); + + #event type checking + if ($eventType == $yui::YEvent::CancelEvent) { + last; + } + elsif ($eventType == $yui::YEvent::WidgetEvent) { + # widget selected + my $widget = $event->widget(); + if ($widget == $cancelButton) { + last; + } + elsif ($widget == $gidManually) { + # GID inserction enabled? + $GID->setEnabled($gidManually->value()); + } + elsif ($widget == $okButton) { + ## check data + my $groupname = $groupName->value(); + my ($continue, $errorString) = valid_groupname($groupname); + my $nm = $continue && $self->ctx->LookupGroupByName($groupname); + if ($nm) { + $groupName->setValue(""); + $errorString = N("Group already exists, please choose another Group Name"); + $continue = 0; + } + my $groupEnt = $self->ctx->InitGroup($groupname, $is_system); + + my $gid = 0; + if ($continue && $gidManually->value()) { + if (($gid = $GID->value()) < 500) { + $errorString = ""; + my $gidchoice = AdminPanel::Shared::ask_YesOrNo(N(" Group Gid is < 500"), + N("Creating a group with a GID less than 500 is not recommended.\n Are you sure you want to do this?\n\n")); + $continue = $gidchoice and $groupEnt->Gid($gid); + } else { + my $g = $self->ctx->LookupGroupById($gid); + if ($g) { + $errorString = ""; + my $gidchoice = AdminPanel::Shared::ask_YesOrNo(N(" Group ID is already used "), + N("Creating a group with a non unique GID?\n\n")); + $continue = $gidchoice and $groupEnt->Gid($gid); + } + else { + $groupEnt and $groupEnt->Gid($gid); + } + } + } + + + if (!$continue) { + #--- raise error + AdminPanel::Shared::msgBox($errorString) if ($errorString); + } + else { + log::explanations(N("Adding group: %s ", $groupname)); + $self->ctx->GroupAdd($groupEnt); + $self->_refresh(); + last; + } + } + } + } + destroy $dlg; + + #restore old application title + yui::YUI::app()->setApplicationTitle($appTitle); +} + + +#============================================================= + +=head2 _buildUserData + +=head3 INPUT + + $self: this object + $layout : layout in wich drawing graphic user data + +=head3 OUTPUT + + %userData: hash containing reference to graphical object + such as: + full_name, login_name, password, password1, + login_shell + +=head3 DESCRIPTION + + This method is used by addUserDialog and _editUserDialog + to create User Data dialog +=cut + +#============================================================= +sub _buildUserData { + my ($self, $layout, $selected_shell) = @_; + + + my @shells = @{$self->ctx->GetUserShells}; + + my $factory = yui::YUI::widgetFactory; + + ## user 'full name' + my $align = $factory->createRight($layout); + my $hbox = $factory->createHBox($align); + my $label = $factory->createLabel($hbox, N("Full Name:") ); + my $fullName = $factory->createInputField($hbox, "", 0); + $label->setWeight($yui::YD_HORIZ, 1); + $fullName->setWeight($yui::YD_HORIZ, 2); + + ## user 'login name' + $align = $factory->createRight($layout); + $hbox = $factory->createHBox($align); + $label = $factory->createLabel($hbox, N("Login:") ); + my $loginName = $factory->createInputField($hbox, "", 0); + $label->setWeight($yui::YD_HORIZ, 1); + $loginName->setWeight($yui::YD_HORIZ, 2); + $loginName->setNotify(1); + + ## user 'Password' + $align = $factory->createRight($layout); + $hbox = $factory->createHBox($align); + $label = $factory->createLabel($hbox, N("Password:") ); + my $password = $factory->createInputField($hbox, "", 1); + $label->setWeight($yui::YD_HORIZ, 1); + $password->setWeight($yui::YD_HORIZ, 2); + + ## user 'confirm Password' + $align = $factory->createRight($layout); + $hbox = $factory->createHBox($align); + $label = $factory->createLabel($hbox, N("Confirm Password:") ); + my $password1 = $factory->createInputField($hbox, "", 1); + $label->setWeight($yui::YD_HORIZ, 1); + $password1->setWeight($yui::YD_HORIZ, 2); + + ## user 'Login Shell' + $align = $factory->createRight($layout); + $hbox = $factory->createHBox($align); + $label = $factory->createLabel($hbox, N("Login Shell:") ); + my $loginShell = $factory->createComboBox($hbox, "", 0); + my $itemColl = new yui::YItemCollection; + foreach my $shell (@shells) { + my $item = new yui::YItem ($shell, 0); + $item->setSelected(1) if ($selected_shell && $selected_shell eq $shell); + $itemColl->push($item); + $item->DISOWN(); + } + $loginShell->addItems($itemColl); + $label->setWeight($yui::YD_HORIZ, 1); + $loginShell->setWeight($yui::YD_HORIZ, 2); + + my %userData = ( + full_name => $fullName, + login_name => $loginName, + password => $password, + password1 => $password1, + login_shell => $loginShell, + ); + + return ( %userData ); +} + +#============================================================= + +=head2 addUserDialog + +=head3 INPUT + + $self: this object + $standalone: if set the application title is set + from the name set in costructor + +=head3 DESCRIPTION + + This method creates and manages the dialog to add a new + user. + +=cut + +#============================================================= +sub addUserDialog { + my $self = shift; + my $standalone = shift; + + my $dontcreatehomedir = 0; + my $is_system = 0; + + ## push application title + my $appTitle = yui::YUI::app()->applicationTitle(); + ## set new title to get it in dialog + if ($standalone) { + yui::YUI::app()->setApplicationTitle($self->name); + } + else { + yui::YUI::app()->setApplicationTitle(N("Create New User")); + } + + my $factory = yui::YUI::widgetFactory; + my $optional = yui::YUI::optionalWidgetFactory; + + my $dlg = $factory->createPopupDialog(); + my $layout = $factory->createVBox($dlg); + + my %userData = $self->_buildUserData($layout); + + ##### add a separator + ## Create Home directory + my $align = $factory->createLeft($layout); + my $hbox = $factory->createHBox($align); + my $createHome = $factory->createCheckBox($hbox, N("Create Home Directory"), 1); + ## Home directory + $align = $factory->createLeft($layout); + $hbox = $factory->createHBox($align); + my $label = $factory->createLabel($hbox, N("Home Directory:") ); + my $homeDir = $factory->createInputField($hbox, "", 0); + $label->setWeight($yui::YD_HORIZ, 1); + $homeDir->setWeight($yui::YD_HORIZ, 2); + + # Create private group + $align = $factory->createLeft($layout); + $hbox = $factory->createHBox($align); + my $createGroup = $factory->createCheckBox($hbox, N("Create a private group for the user"), 1); + + # Specify user id manually + $align = $factory->createRight($layout); + $hbox = $factory->createHBox($align); + my $uidManually = $factory->createCheckBox($hbox, N("Specify user ID manually"), 0); + my $UID = $factory->createIntField($hbox, N("UID"), 1, 65000, 500); + $UID->setEnabled($uidManually->value()); + $uidManually->setNotify(1); + $uidManually->setWeight($yui::YD_HORIZ, 2); + $UID->setWeight($yui::YD_HORIZ, 1); + + ## user 'icon' + $hbox = $factory->createHBox($layout); + $factory->createLabel($hbox, N("Click on icon to change it") ); + my $iconFace = AdminPanel::Shared::Users::GetFaceIcon(); + my $icon = $factory->createPushButton($hbox, ""); + $icon->setIcon(AdminPanel::Shared::Users::face2png($iconFace)); + $icon->setLabel($iconFace); + + $hbox = $factory->createHBox($layout); + $align = $factory->createRight($hbox); + my $cancelButton = $factory->createPushButton($align, N("Cancel")); + my $okButton = $factory->createPushButton($hbox, N("Ok")); + while(1) { + my $event = $dlg->waitForEvent(); + my $eventType = $event->eventType(); + + #event type checking + if ($eventType == $yui::YEvent::CancelEvent) { + last; + } + elsif ($eventType == $yui::YEvent::WidgetEvent) { + # widget selected + my $widget = $event->widget(); + if ($widget == $cancelButton) { + last; + } + elsif ($widget == $icon) { + #remove shortcut from label + my $iconLabel = $self->_skipShortcut($icon->label()); + + my $nextIcon = GetFaceIcon($icon->label(), 1); + $icon->setLabel($nextIcon); + $icon->setIcon(AdminPanel::Shared::Users::face2png($nextIcon)); + } + elsif ($widget == $uidManually) { + # UID inserction enabled? + $UID->setEnabled($uidManually->value()); + } + elsif ($widget == $userData{ login_name }) { + my $username = $userData{ login_name }->value(); + $homeDir->setValue("/home/$username"); + } + elsif ($widget == $okButton) { + ## check data + my $username = $userData{ login_name }->value(); + my ($continue, $errorString) = valid_username($username); + my $nm = $continue && $self->ctx->LookupUserByName($username); + if ($nm) { + $userData{ login_name }->setValue(""); + $homeDir->setValue(""); + $errorString = N("User already exists, please choose another User Name"); + $continue = 0; + } + my $passwd = $continue && $userData{ password }->value(); + if ($continue && $passwd ne $userData{ password1 }->value()) { + $errorString = N("Password Mismatch"); + $continue = 0; + } + my $sec = security::level::get(); + if ($sec > 3 && length($passwd) < 6) { + $errorString = N("This password is too simple. \n Good passwords should be > 6 characters"); + $continue = 0; + } + my $userEnt = $continue && $self->ctx->InitUser($username, $is_system); + if ($continue && $createHome->value()) { + $dontcreatehomedir = 0; + my $homedir = $homeDir->value(); + $userEnt and $userEnt->HomeDir($homedir); + } else { + $dontcreatehomedir = 1; + } + my $uid = 0; + if ($continue && $uidManually->value()) { + if (($uid = $UID->value()) < 500) { + $errorString = ""; + my $uidchoice = AdminPanel::Shared::ask_YesOrNo(N("User Uid is < 500"), + N("Creating a user with a UID less than 500 is not recommended.\nAre you sure you want to do this?\n\n")); + $continue = $uidchoice and $userEnt->Uid($uid); + } else { + $userEnt and $userEnt->Uid($uid); + } + } + my $gid = 0; + if ($createGroup->value()) { + if ($continue) { + #Check if group exist + my $gr = $self->ctx->LookupGroupByName($username); + if ($gr) { + my $groupchoice = $self->ChooseGroup(); + if ($groupchoice == 0 ) { + #You choose to put it in the existing group + $gid = $gr->Gid($self->USER_GetValue); + } elsif ($groupchoice == 1) { + # Put it in 'users' group + log::explanations(N("Putting %s to 'users' group", + $username)); + $gid = AdminPanel::Shared::Users::Add2UsersGroup($username, $self->ctx); + } + else { + $errorString = ""; + $continue = 0; + } + } else { + #it's a new group: Add it + my $newgroup = $self->ctx->InitGroup($username,$is_system); + log::explanations(N("Creating new group: %s", $username)); + $gid = $newgroup->Gid($self->USER_GetValue); + $self->ctx->GroupAdd($newgroup); + } + } + } else { + $continue and $gid = AdminPanel::Shared::Users::Add2UsersGroup($username, $self->ctx); + } + + if (!$continue) { + #---rasie error + AdminPanel::Shared::msgBox($errorString) if ($errorString); + } + else { + ## OK let's create the user + print N("Adding user: ") . $username . " \n"; + log::explanations(N("Adding user: %s"), $username); + my $loginshell = $userData{ login_shell }->value(); + my $fullname = $userData{ full_name }->value(); + $userEnt->Gecos($fullname); $userEnt->LoginShell($loginshell); + $userEnt->Gid($gid); + $userEnt->ShadowMin(-1); $userEnt->ShadowMax(99999); + $userEnt->ShadowWarn(-1); $userEnt->ShadowInact(-1); + $self->ctx->UserAdd($userEnt, $is_system, $dontcreatehomedir); + $self->ctx->UserSetPass($userEnt, $passwd); + defined $icon->label() and + AdminPanel::Shared::Users::addKdmIcon($username, $icon->label()); +### TODO Migration wizard +# +# Refresh($sysfilter, $stringsearch); +# transfugdrake::get_windows_disk() +# and $in->ask_yesorno(N("Migration wizard"), +# N("Do you want to run the migration wizard in order to import Windows documents and settings in your Mageia distribution?")) +# and run_program::raw({ detach => 1 }, 'transfugdrake'); + + + last; + } + } + } + } + + destroy $dlg; + + #restore old application title + yui::YUI::app()->setApplicationTitle($appTitle) if $appTitle; +} + +#============================================================= + +=head2 _createUserTable + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + +This function create the User table to be added to the replace +point of the tab widget. Note this function is meant for internal +use only + +=cut + +#============================================================= +sub _createUserTable { + my $self = shift; + + $self->dialog->startMultipleChanges(); + $self->get_widget('replace_pnt')->deleteChildren(); + my $parent = $self->get_widget('replace_pnt'); + my $factory = yui::YUI::widgetFactory; + my $yTableHeader = new yui::YTableHeader(); + $yTableHeader->addColumn(N("User Name"), $yui::YAlignBegin); + $yTableHeader->addColumn(N("User ID"), $yui::YAlignBegin); + $yTableHeader->addColumn(N("Primary Group"), $yui::YAlignBegin); + $yTableHeader->addColumn(N("Full Name"), $yui::YAlignBegin); + $yTableHeader->addColumn(N("Login Shell"), $yui::YAlignBegin); + $yTableHeader->addColumn(N("Home Directory"), $yui::YAlignBegin); + $yTableHeader->DISOWN(); + + $self->set_widget(table => $factory->createTable($parent, $yTableHeader)); + + $self->get_widget('table')->setImmediateMode(1); + $self->get_widget('table')->DISOWN(); + $self->get_widget('replace_pnt')->showChild(); + $self->dialog->recalcLayout(); + $self->dialog->doneMultipleChanges(); + $self->_refreshUsers(); +} + +#============================================================= + +=head2 _createGroupTable + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + +This function create the Group table to be added to the replace +point of the tab widget. Note this function is meant for internal +use only + + +=cut + +#============================================================= +sub _createGroupTable { + my $self = shift; + + + $self->dialog->startMultipleChanges(); + $self->get_widget('replace_pnt')->deleteChildren(); + my $parent = $self->get_widget('replace_pnt'); + my $factory = yui::YUI::widgetFactory; + my $yTableHeader = new yui::YTableHeader(); + $yTableHeader->addColumn(N("Group Name"), $yui::YAlignBegin); + $yTableHeader->addColumn(N("Group ID"), $yui::YAlignBegin); + $yTableHeader->addColumn(N("Group Members"), $yui::YAlignBegin); + $yTableHeader->DISOWN(); + + $self->set_widget(table => $factory->createTable($parent, $yTableHeader)); + + $self->get_widget('table')->setImmediateMode(1); + $self->get_widget('table')->DISOWN(); + $self->get_widget('replace_pnt')->showChild(); + $self->dialog->recalcLayout(); + $self->dialog->doneMultipleChanges(); + $self->_refreshGroups(); +} + + +#============================================================= + +=head2 _computeLockExpire + +=head3 INPUT + + $l: login user info + +=head3 OUTPUT + + $status: Locked, Expired, or empty string + +=head3 DESCRIPTION + + This method returns if the login is Locked, Expired or ok. + Note this function is meant for internal use only + +=cut + +#============================================================= +sub _computeLockExpire { + my ( $self, $l ) = @_; + my $ep = $l->ShadowExpire($self->USER_GetValue); + my $tm = ceil(time()/(24*60*60)); + $ep = -1 if int($tm) <= $ep; + my $status = $self->ctx->IsLocked($l) ? N("Locked") : ($ep != -1 ? N("Expired") : ''); + $status; +} + +#============================================================= + +=head2 _refreshUsers + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + This method refresh user info into User tab widget. + Note this function is meant for internal use only + +=cut + +#============================================================= +sub _refreshUsers { + my $self = shift; + + my $strfilt = $self->get_widget('filter')->value(); + my $filterusers = $self->get_widget('filter_system')->isChecked(); + + my ($users, $group, $groupnm, $expr); + defined $self->ctx and $users = $self->ctx->UsersEnumerateFull; + + $self->dialog->startMultipleChanges(); + #for some reasons QT send an event using table->selectItem() + # WA remove notification immediate + $self->get_widget('table')->setImmediateMode(0); + $self->get_widget('table')->deleteAllItems(); + + my @UserReal; + LOOP: foreach my $l (@$users) { + next LOOP if $filterusers && $l->Uid($self->USER_GetValue) <= 499 || $l->Uid($self->USER_GetValue) == 65534; + push @UserReal, $l if $l->UserName($self->USER_GetValue) =~ /^\Q$strfilt/; + } + my $i; + my $itemColl = new yui::YItemCollection; + foreach my $l (@UserReal) { + $i++; + my $uid = $l->Uid($self->USER_GetValue); + if (!defined $uid) { + warn "bogus user at line $i\n"; + next; + } + my $a = $l->Gid($self->USER_GetValue); + $group = $self->ctx->LookupGroupById($a); + $groupnm = ''; + $expr = $self->_computeLockExpire($l); + $group and $groupnm = $group->GroupName($self->USER_GetValue); + my $s = $l->Gecos($self->USER_GetValue); + c::set_tagged_utf8($s); + my $username = $l->UserName($self->USER_GetValue); + my $Uid = $l->Uid($self->USER_GetValue); + my $shell = $l->LoginShell($self->USER_GetValue); + my $homedir = $l->HomeDir($self->USER_GetValue); + my $item = new yui::YTableItem ("$username", + "$Uid", + "$groupnm", + "$s", + "$shell", + "$homedir", + "$expr"); + # TODO workaround to get first cell at least until we don't + # a cast from YItem + $item->setLabel( $username ); + $itemColl->push($item); + $item->DISOWN(); + } + $self->get_widget('table')->addItems($itemColl); + my $item = $self->get_widget('table')->selectedItem(); + $self->get_widget('table')->selectItem($item, 0) if $item; + $self->dialog->recalcLayout(); + $self->dialog->doneMultipleChanges(); + $self->_refreshActions(); + $self->get_widget('table')->setImmediateMode(1); +} + +#============================================================= + +=head2 _refreshGroups + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + This method refresh group info into Group tab widget. + Note this function is meant for internal use only + +=cut + +#============================================================= +sub _refreshGroups { + my $self = shift; + + my $strfilt = $self->get_widget('filter')->value(); + my $filtergroups = $self->get_widget('filter_system')->isChecked(); + + my $groups; + defined $self->ctx and $groups = $self->ctx->GroupsEnumerateFull; + + $self->dialog->startMultipleChanges(); + #for some reasons QT send an event using table->selectItem() + # WA remove notification immediate + $self->get_widget('table')->setImmediateMode(0); + $self->get_widget('table')->deleteAllItems(); + my @GroupReal; + LOOP: foreach my $g (@$groups) { + next LOOP if $filtergroups && $g->Gid($self->USER_GetValue) <= 499 || $g->Gid($self->USER_GetValue) == 65534; + push @GroupReal, $g if $g->GroupName($self->USER_GetValue) =~ /^\Q$strfilt/; + } + + my $itemColl = new yui::YItemCollection; + foreach my $g (@GroupReal) { + my $a = $g->GroupName($self->USER_GetValue); + #my $group = $ctx->LookupGroupById($a); + my $u_b_g = $a && $self->ctx->EnumerateUsersByGroup($a); + my $listUbyG = join(',', @$u_b_g); + my $group_id = $g->Gid($self->USER_GetValue); + my $groupname = $g->GroupName($self->USER_GetValue); + my $item = new yui::YTableItem ("$groupname", + "$group_id", + "$listUbyG"); + $item->setLabel( $groupname ); + $itemColl->push($item); + $item->DISOWN(); + } + + $self->get_widget('table')->addItems($itemColl); + my $item = $self->get_widget('table')->selectedItem(); + $self->get_widget('table')->selectItem($item, 0) if $item; + $self->dialog->recalcLayout(); + $self->dialog->doneMultipleChanges(); + $self->_refreshActions(); + $self->get_widget('table')->setImmediateMode(1); +} + + +#============================================================= + +=head2 _getUserInfo + +=head3 INPUT + + $self: this object + +=head3 OUTPUT + + %userData: selected user info as: + username: username + full_name: full name of user + shell: shell used + homedir: home dir path + UID: User identifier + acc_check_exp: account expiration enabling + acc_expy: account expiration year + acc_expm: account expiration month + acc_expd: account expiration day + lockuser: account locked + pwd_check_exp: password expiration enabling + pwd_exp_min: days before changing password + is allowed + pwd_exp_max: days before changing password + is required + pwd_exp_warn: warning days before changing + pwd_exp_inact: days before account becomes + inact + members: Array containing groups the user + belongs to. + primary_group: primary group ID for the user + +=head3 DESCRIPTION + + Retrieves the selected user info from the system + Note that acc_expy, acc_expm and acc_expd are valid if + acc_check_exp is enabled. + Note that pwd_exp_min, pwd_exp_max, pwd_exp_warn, + pwd_exp_inact are valid if pwd_check_exp is enabled. + +=cut + +#============================================================= + +sub _getUserInfo { + my $self = shift; + + my $label = $self->_skipShortcut($self->get_widget('tabs')->selectedItem()->label()); + if ($label ne N("Users") ) { + return undef; + } + + my $item = $self->get_widget('table')->selectedItem(); + if (! $item) { + return undef; + } + + my %userData; + $userData{username} = $item->label(); + my $userEnt = $self->ctx->LookupUserByName($userData{username}); + + my $s = $userEnt->Gecos($self->USER_GetValue); + c::set_tagged_utf8($s); + $userData{full_name} = $s; + $userData{shell} = $userEnt->LoginShell($self->USER_GetValue); + $userData{homedir} = $userEnt->HomeDir($self->USER_GetValue); + $userData{UID} = $userEnt->Uid($self->USER_GetValue); + + # default expiration time + my ($day, $mo, $ye) = (localtime())[3, 4, 5]; + $userData{acc_expy} = $ye+1900; + $userData{acc_expm} = $mo+1; + $userData{acc_expd} = $day; + $userData{acc_check_exp} = 0; + my $expire = $userEnt->ShadowExpire($self->USER_GetValue); + if ($expire && $expire != -1) { + my $times = TimeOfArray($expire, 1); + $userData{acc_expy} = $times->{year}; + $userData{acc_expm} = $times->{month}; + $userData{acc_expd} = $times->{dayint}; + $userData{acc_check_exp} = 1; + } + + # user password are not retrieved if admin wants + # to change it has to insert a new one + $userData{password} = undef; + $userData{password1} = undef; + # Check if user account is locked + + $userData{lockuser} = $self->ctx->IsLocked($userEnt); + + $userData{icon_face} = AdminPanel::Shared::Users::GetFaceIcon($userData{username}); + $userData{pwd_check_exp} = 0; + $userData{pwd_exp_min} = $userEnt->ShadowMin($self->USER_GetValue); + $userData{pwd_exp_max} = $userEnt->ShadowMax($self->USER_GetValue); + $userData{pwd_exp_warn} = $userEnt->ShadowWarn($self->USER_GetValue); + $userData{pwd_exp_inact} = $userEnt->ShadowInact($self->USER_GetValue); + + if ($userData{pwd_exp_min} && $userData{pwd_exp_min} != -1 || + $userData{pwd_exp_max} && $userData{pwd_exp_max} != 99999 || + $userData{pwd_exp_warn} && $userData{pwd_exp_warn} != 7 && $userData{pwd_exp_warn} != -1 || + $userData{pwd_exp_inact} && $userData{pwd_exp_inact} != -1) { + $userData{pwd_check_exp} = 1; + } + + $userData{members} = $self->ctx->EnumerateGroupsByUser($userData{username}); + $userData{primary_group} = $userEnt->Gid($self->USER_GetValue); + + return %userData; + +} + +#============================================================= + +=head2 _getUserInfo + +=head3 INPUT + + $self: this object + +=head3 OUTPUT + + %groupData: selected group info as: + $groupname: group name + $members: users that are members of this group + +=head3 DESCRIPTION + + Retrieves the selected group info from the system + +=cut + +#============================================================= + +sub _getGroupInfo { + my $self = shift; + + my $label = $self->_skipShortcut($self->get_widget('tabs')->selectedItem()->label()); + if ($label ne N("Groups") ) { + return undef; + } + + my $item = $self->get_widget('table')->selectedItem(); + if (! $item) { + return undef; + } + + my %groupData; + $groupData{start_groupname} = $item->label(); + $groupData{groupname} = $item->label(); + + my $groupEnt = $self->ctx->LookupGroupByName($groupData{groupname}); + $groupData{members} = $self->ctx->EnumerateUsersByGroup($groupData{groupname}); + + return %groupData; + +} + +sub _storeDataFromGroupEditPreviousTab { + my ($self, %groupData) = @_; + + my $previus_tab = $self->get_edit_tab_widget('edit_tab_label'); + if (!$previus_tab) { + return %groupData; + } + elsif ($previus_tab eq $groupEditLabel{group_data}) { + $groupData{groupname} = $self->get_edit_tab_widget('groupname')->value(); + } + elsif ($previus_tab eq $groupEditLabel{group_users}) { + my $tbl = $self->get_edit_tab_widget('members'); + $groupData{members} = undef; + my @members; + my $i; + for($i=0;$i<$tbl->itemsCount();$i++) { + push (@members, $tbl->item($i)->label()) if $tbl->toCBYTableItem($tbl->item($i))->checked(); + } + $groupData{members} = [ @members ]; + } + + return %groupData; +} + + +sub _storeDataFromUserEditPreviousTab { + my ($self, %userData) = @_; + + my $previus_tab = $self->get_edit_tab_widget('edit_tab_label'); + if (!$previus_tab) { + return %userData; + } + elsif ($previus_tab eq $userEditLabel{user_data}) { + $userData{full_name} = $self->get_edit_tab_widget('full_name')->value(); + $userData{username} = $self->get_edit_tab_widget('login_name')->value() ; + $userData{shell} = $self->get_edit_tab_widget('login_shell')->value(); + $userData{homedir} = $self->get_edit_tab_widget('homedir')->value(); + my $passwd = $self->get_edit_tab_widget('password')->value(); + $userData{password} = $passwd; + $passwd = $self->get_edit_tab_widget('password1')->value(); + $userData{password1} = $passwd; + } + elsif ($previus_tab eq $userEditLabel{account_info}) { + $userData{acc_check_exp} = $self->get_edit_tab_widget('acc_check_exp')->value(); + $userData{acc_expy} = $self->get_edit_tab_widget('acc_expy')->value(); + $userData{acc_expm} = $self->get_edit_tab_widget('acc_expm')->value(); + $userData{acc_expd} = $self->get_edit_tab_widget('acc_expd')->value(); + $userData{lockuser} = $self->get_edit_tab_widget('lockuser')->value(); + $userData{icon_face} = $self->get_edit_tab_widget('icon_face')->label(); + } + elsif ($previus_tab eq $userEditLabel{password_info}) { + $userData{pwd_check_exp} = $self->get_edit_tab_widget('pwd_check_exp')->value(); + $userData{pwd_exp_min} = $self->get_edit_tab_widget('pwd_exp_min')->value(); + $userData{pwd_exp_max} = $self->get_edit_tab_widget('pwd_exp_max')->value(); + $userData{pwd_exp_warn} = $self->get_edit_tab_widget('pwd_exp_warn')->value(); + $userData{pwd_exp_inact} = $self->get_edit_tab_widget('pwd_exp_inact')->value(); + } + elsif ($previus_tab eq $userEditLabel{groups}) { + my $tbl = $self->get_edit_tab_widget('members'); + $userData{members} = undef; + my @members; + my $i; + for($i=0;$i<$tbl->itemsCount();$i++) { + push (@members, $tbl->item($i)->label()) if $tbl->toCBYTableItem($tbl->item($i))->checked(); + } + $userData{members} = [ @members ]; + + if ($self->get_edit_tab_widget('primary_group')->selectedItem()) { + my $Gent = $self->ctx->LookupGroupByName($self->get_edit_tab_widget('primary_group')->selectedItem()->label()); + my $primgroup = $Gent->Gid($self->USER_GetValue); + + $userData{primary_group} = $primgroup; + } + else { + $userData{primary_group} = -1; + } + } + + return %userData; +} + +#============================================================= + +=head2 _userDataTabWidget + +=head3 INPUT + + $self: this object + $dialog: YUI dialog that owns the YUI replace point + $replace_pnt: YUI replace point, needed to add a new tab + widget + %userData: hash containing user data info, tabs are + removed and added again on selection, so + data must be saved outside of widgets. + $previus_tab: previous tab widget label, needed to store + user data from the old tab before removing + it, if user changed something. + +=head3 OUTPUT + + %userDataWidget: hash containing new YUI widget objects + such as: + retunred onject from _buildUserData and + homedir. + +=head3 DESCRIPTION + + This internal method removes old tab widget saving its + relevant data into userData and creates new selected table + to be shown. + +=cut + +#============================================================= +sub _userDataTabWidget { + my ($self, $dialog, $replace_pnt, %userData) = @_; + + my $factory = yui::YUI::widgetFactory; + + $dialog->startMultipleChanges(); + + $replace_pnt->deleteChildren(); + my $layout = $factory->createVBox($replace_pnt); + my %userDataWidget = $self->_buildUserData($layout, $userData{shell}); + + ## user 'login name' + my $align = $factory->createRight($layout); + my $hbox = $factory->createHBox($align); + my $label = $factory->createLabel($hbox, N("Home:") ); + $userDataWidget{homedir} = $factory->createInputField($hbox, "", 0); + $label->setWeight($yui::YD_HORIZ, 1); + $userDataWidget{homedir}->setWeight($yui::YD_HORIZ, 2); + + # fill data into widgets + ## + # full_name, login_name, password, password1, + # login_shell + $userDataWidget{full_name}->setValue($userData{full_name}); + $userDataWidget{login_name}->setValue($userData{username}); + $userDataWidget{password}->setValue($userData{password}) if $userData{password}; + $userDataWidget{password1}->setValue($userData{password1}) if $userData{password1}; + $userDataWidget{homedir}->setValue($userData{homedir}); + + $replace_pnt->showChild(); + $dialog->recalcLayout(); + $dialog->doneMultipleChanges(); + + return %userDataWidget; +} + + +#============================================================= + +=head2 _groupDataTabWidget + +=head3 INPUT + + $self: this object + $dialog: YUI dialog that owns the YUI replace point + $replace_pnt: YUI replace point, needed to add a new tab + widget + %groupData: hash containing group data info, tabs are + removed and added again on selection, so + data must be saved outside of widgets. + $previus_tab: previous tab widget label, needed to store + group data from the old tab before removing + it, if user changed something. + +=head3 OUTPUT + + %groupDataWidget: hash containing new YUI widget objects + such as: + groupname. + +=head3 DESCRIPTION + + This internal method removes old tab widget saving its + relevant data into groupData and creates new selected table + to be shown. + +=cut + +#============================================================= +sub _groupDataTabWidget { + my ($self, $dialog, $replace_pnt, %groupData) = @_; + + my $factory = yui::YUI::widgetFactory; + + $dialog->startMultipleChanges(); + + $replace_pnt->deleteChildren(); + my $layout = $factory->createVBox($replace_pnt); + + my %groupDataWidget; + + ## user 'login name' + my $align = $factory->createRight($layout); + my $hbox = $factory->createHBox($align); + my $label = $factory->createLabel($hbox, N("Group Name:") ); + $groupDataWidget{groupname} = $factory->createInputField($hbox, "", 0); + $label->setWeight($yui::YD_HORIZ, 1); + $groupDataWidget{groupname}->setWeight($yui::YD_HORIZ, 2); + + $groupDataWidget{groupname}->setValue($groupData{groupname}); + + $replace_pnt->showChild(); + $dialog->recalcLayout(); + $dialog->doneMultipleChanges(); + + return %groupDataWidget; +} + + +sub _userAccountInfoTabWidget { + my ($self, $dialog, $replace_pnt, %userData) = @_; + + my $factory = yui::YUI::widgetFactory; + + $dialog->startMultipleChanges(); + + $replace_pnt->deleteChildren(); + my $layout = $factory->createVBox($replace_pnt); + + my %userAccountWidget; + $userAccountWidget{acc_check_exp} = $factory->createCheckBoxFrame($layout, N("Enable account expiration"), 1); + my $align = $factory->createRight($userAccountWidget{acc_check_exp}); + my $hbox = $factory->createHBox($align); + my $label = $factory->createLabel($hbox, N("Account expires (YYYY-MM-DD):")); + $userAccountWidget{acc_expy} = $factory->createIntField($hbox, "", 1970, 9999, $userData{acc_expy}); + $userAccountWidget{acc_expm} = $factory->createIntField($hbox, "", 1, 12, $userData{acc_expm}); + $userAccountWidget{acc_expd} = $factory->createIntField($hbox, "", 1, 31, $userData{acc_expd}); + $userAccountWidget{acc_check_exp}->setValue($userData{acc_check_exp}); + $label->setWeight($yui::YD_HORIZ, 2); + $align = $factory->createLeft($layout); + $userAccountWidget{lockuser} = $factory->createCheckBox($align, N("Lock User Account"), $userData{lockuser}); + + $align = $factory->createLeft($layout); + $hbox = $factory->createHBox($align); + $label = $factory->createLabel($hbox, N("Click on the icon to change it")); + $userAccountWidget{icon_face} = $factory->createPushButton($hbox, ""); + $userAccountWidget{icon_face}->setIcon(AdminPanel::Shared::Users::face2png($userData{icon_face})); + $userAccountWidget{icon_face}->setLabel($userData{icon_face}); + + $replace_pnt->showChild(); + $dialog->recalcLayout(); + $dialog->doneMultipleChanges(); + + return %userAccountWidget; +} + + +sub _userPasswordInfoTabWidget { + my ($self, $dialog, $replace_pnt, %userData) = @_; + + my $factory = yui::YUI::widgetFactory; + + $dialog->startMultipleChanges(); + + $replace_pnt->deleteChildren(); + my $layout = $factory->createVBox($replace_pnt); + + my %userPasswordWidget; + my $userEnt = $self->ctx->LookupUserByName($userData{username}); + my $lastchg = $userEnt->ShadowLastChange($self->USER_GetValue); + + my $align = $factory->createLeft($layout); + my $hbox = $factory->createHBox($align); + my $label = $factory->createLabel($hbox, N("User last changed password on: ")); + my $dayStr = $factory->createLabel($hbox, ""); + my $month = $factory->createLabel($hbox, ""); + my $dayInt = $factory->createLabel($hbox, ""); + my $year = $factory->createLabel($hbox, ""); + if ($lastchg) { + my $times = TimeOfArray($lastchg, 0); + $dayStr->setValue($times->{daystr}); + $month->setValue($times->{month}); + $dayInt->setValue($times->{dayint}); + $year->setValue($times->{year}); + } + + $userPasswordWidget{pwd_check_exp} = $factory->createCheckBoxFrame($layout, N("Enable Password Expiration"), 1); + $layout = $factory->createVBox($userPasswordWidget{pwd_check_exp}); + $align = $factory->createLeft($layout); + $hbox = $factory->createHBox($align); + $label = $factory->createLabel($hbox, N("Days before change allowed:")); + $userPasswordWidget{pwd_exp_min} = $factory->createInputField($hbox, "", 0); + $userPasswordWidget{pwd_exp_min}->setValue("$userData{pwd_exp_min}"); + $label->setWeight($yui::YD_HORIZ, 1); + $userPasswordWidget{pwd_exp_min}->setWeight($yui::YD_HORIZ, 2); + + $align = $factory->createLeft($layout); + $hbox = $factory->createHBox($align); + $label = $factory->createLabel($hbox, N("Days before change required:")); + $userPasswordWidget{pwd_exp_max} = $factory->createInputField($hbox, "", 0); + $userPasswordWidget{pwd_exp_max}->setValue("$userData{pwd_exp_max}"); + $label->setWeight($yui::YD_HORIZ, 1); + $userPasswordWidget{pwd_exp_max}->setWeight($yui::YD_HORIZ, 2); + + $align = $factory->createLeft($layout); + $hbox = $factory->createHBox($align); + $label = $factory->createLabel($hbox, N("Days warning before change:")); + $userPasswordWidget{pwd_exp_warn} = $factory->createInputField($hbox, "", 0); + $userPasswordWidget{pwd_exp_warn}->setValue("$userData{pwd_exp_warn}"); + $label->setWeight($yui::YD_HORIZ, 1); + $userPasswordWidget{pwd_exp_warn}->setWeight($yui::YD_HORIZ, 2); + + $align = $factory->createLeft($layout); + $hbox = $factory->createHBox($align); + $label = $factory->createLabel($hbox, N("Days before account inactive:")); + $userPasswordWidget{pwd_exp_inact} = $factory->createInputField($hbox, "", 0); + $userPasswordWidget{pwd_exp_inact}->setValue("$userData{pwd_exp_inact}"); + $label->setWeight($yui::YD_HORIZ, 1); + $userPasswordWidget{pwd_exp_inact}->setWeight($yui::YD_HORIZ, 2); + + $userPasswordWidget{pwd_check_exp}->setValue($userData{pwd_check_exp}); + + $replace_pnt->showChild(); + $dialog->recalcLayout(); + $dialog->doneMultipleChanges(); + + return %userPasswordWidget; +} + +sub _groupUsersTabWidget { + my ($self, $dialog, $replace_pnt, %groupData) = @_; + + my $factory = yui::YUI::widgetFactory; + my $mageiaPlugin = "mga"; + my $mgaFactory = yui::YExternalWidgets::externalWidgetFactory($mageiaPlugin); + $mgaFactory = yui::YMGAWidgetFactory::getYMGAWidgetFactory($mgaFactory); + + $dialog->startMultipleChanges(); + + $replace_pnt->deleteChildren(); + + my %groupUsersWidget; + + my $layout = labeledFrameBox($replace_pnt, N("Select the users to join this group:")); + + my $yTableHeader = new yui::YTableHeader(); + $yTableHeader->addColumn("", $yui::YAlignBegin); + $yTableHeader->addColumn(N("User"), $yui::YAlignBegin); + + $groupUsersWidget{members} = $mgaFactory->createCBTable($layout, $yTableHeader, $yui::YCBTableCheckBoxOnFirstColumn); + + my $groupEnt = $self->ctx->LookupGroupByName($groupData{groupname}); + my $users = $self->ctx->UsersEnumerate; + my @susers = sort(@$users); + + my $itemCollection = new yui::YItemCollection; + my $members = $groupData{members}; + foreach my $user (@susers) { + my $item = new yui::YCBTableItem($user); + $item->check(member($user, @$members)); + $item->setLabel($user); + $itemCollection->push($item); + $item->DISOWN(); + } + $groupUsersWidget{members}->addItems($itemCollection); + + $replace_pnt->showChild(); + $dialog->recalcLayout(); + $dialog->doneMultipleChanges(); + + return %groupUsersWidget; +} + +sub _userGroupsTabWidget { + my ($self, $dialog, $replace_pnt, %userData) = @_; + + my $factory = yui::YUI::widgetFactory; + my $mageiaPlugin = "mga"; + my $mgaFactory = yui::YExternalWidgets::externalWidgetFactory($mageiaPlugin); + $mgaFactory = yui::YMGAWidgetFactory::getYMGAWidgetFactory($mgaFactory); + + $dialog->startMultipleChanges(); + + $replace_pnt->deleteChildren(); + + my %userGroupsWidget; + my $userEnt = $self->ctx->LookupUserByName($userData{username}); + my $lastchg = $userEnt->ShadowLastChange($self->USER_GetValue); + + my $layout = labeledFrameBox($replace_pnt, N("Select groups that the user will be member of:")); + + my $yTableHeader = new yui::YTableHeader(); + $yTableHeader->addColumn("", $yui::YAlignBegin); + $yTableHeader->addColumn(N("Group"), $yui::YAlignBegin); + + $userGroupsWidget{members} = $mgaFactory->createCBTable($layout, $yTableHeader, $yui::YCBTableCheckBoxOnFirstColumn); + + my $grps = $self->ctx->GroupsEnumerate; + my @sgroups = sort @$grps; + + my $itemCollection = new yui::YItemCollection; + my $members = $userData{members}; + foreach my $group (@sgroups) { + my $item = new yui::YCBTableItem($group); + $item->check(member($group, @$members)); + $item->setLabel($group); + $itemCollection->push($item); + $item->DISOWN(); + } + $userGroupsWidget{members}->addItems($itemCollection); + $userGroupsWidget{members}->setNotify(1); + my $primgroup = ''; + if ($userData{primary_group} != -1) { + my $Gent = $self->ctx->LookupGroupById($userData{primary_group}); + $primgroup = $Gent->GroupName($self->USER_GetValue); + } + + my $align = $factory->createLeft($layout); + my $hbox = $factory->createHBox($align); + my $label = $factory->createLabel($hbox, N("Primary Group")); + $userGroupsWidget{primary_group} = $factory->createComboBox($hbox, "", 0); + my $itemColl = new yui::YItemCollection; + foreach my $member (@$members) { + my $item = new yui::YItem ($member, 0); + $item->setSelected(1) if ($item->label() eq $primgroup); + $itemColl->push($item); + $item->DISOWN(); + } + $userGroupsWidget{primary_group}->addItems($itemColl); + $label->setWeight($yui::YD_HORIZ, 1); + $userGroupsWidget{primary_group}->setWeight($yui::YD_HORIZ, 2); + + $replace_pnt->showChild(); + $dialog->recalcLayout(); + $dialog->doneMultipleChanges(); + + return %userGroupsWidget; +} + +sub _groupEdit_Ok { + my ($self, %groupData) = @_; + + # update last changes if any + %groupData = $self->_storeDataFromGroupEditPreviousTab(%groupData); + + my ($continue, $errorString) = valid_groupname($groupData{groupname}); + if (!$continue) { + AdminPanel::Shared::msgBox($errorString) if ($errorString); + return $continue; + } + my $groupEnt = $self->ctx->LookupGroupByName($groupData{start_groupname}); + if ($groupData{start_groupname} ne $groupData{groupname}) { + $groupEnt->GroupName($groupData{groupname}); + } + + my $members = $groupData{members}; + my $gid = $groupEnt->Gid($self->USER_GetValue); + my $users = $self->ctx->UsersEnumerate; + my @susers = sort(@$users); + + foreach my $user (@susers) { + my $uEnt = $self->ctx->LookupGroupByName($user); + if ($uEnt) { + my $ugid = $uEnt->Gid($self->USER_GetValue); + my $m = $self->ctx->EnumerateUsersByGroup($groupData{start_groupname}); + if (member($user, @$members)) { + if (!$self->_inArray($user, $m)) { + if ($ugid != $gid) { + eval { $groupEnt->MemberName($user,1) }; + } + } + } + else { + if ($self->_inArray($user, $m)) { + if ($ugid == $gid) { + AdminPanel::Shared::msgBox(N("You cannot remove user '%s' from their primary group", $user)); + return 0; + } + else { + eval { $groupEnt->MemberName($user,2) }; + } + } + } + } + } + + $self->ctx->GroupModify($groupEnt); + $self->_refresh(); + + return 1; +} + +sub _userEdit_Ok { + my ($self, %userData) = @_; + + # update last changes if any + %userData = $self->_storeDataFromUserEditPreviousTab(%userData); + + my ($continue, $errorString) = valid_username($userData{username}); + if (!$continue) { + AdminPanel::Shared::msgBox($errorString) if ($errorString); + return $continue; + } + + if ( $userData{password} ne $userData{password1}) { + AdminPanel::Shared::msgBox(N("Password Mismatch")); + return 0; + } + my $userEnt = $self->ctx->LookupUserByName($userData{username}); + if ($userData{password} ne '') { + my $sec = security::level::get(); + if ($sec > 3 && length($userData{password}) < 6) { + AdminPanel::Shared::msgBox(N("This password is too simple. \n Good passwords should be > 6 characters")); + return 0; + } + $self->ctx->UserSetPass($userEnt, $userData{password}); + } + + $userEnt->UserName($userData{username}); + $userEnt->Gecos($userData{full_name}); + $userEnt->HomeDir($userData{homedir}); + $userEnt->LoginShell($userData{shell}); + my $username = $userEnt->UserName($self->USER_GetValue); + my $grps = $self->ctx->GroupsEnumerate; + my @sgroups = sort @$grps; + + my $members = $userData{members}; + foreach my $group (@sgroups) { + + my $gEnt = $self->ctx->LookupGroupByName($group); + my $ugid = $gEnt->Gid($self->USER_GetValue); + my $m = $gEnt->MemberName(1,0); + if (member($group, @$members)) { + if (!$self->_inArray($username, $m) && $userData{primary_group} != $ugid) { + eval { $gEnt->MemberName($username, 1) }; + $self->ctx->GroupModify($gEnt); + } + } + else { + if ($self->_inArray($username, $m)) { + eval { $gEnt->MemberName($username, 2) }; + $self->ctx->GroupModify($gEnt); + } + } + } + if ($userData{primary_group} == -1) { + AdminPanel::Shared::msgBox(N("Please select at least one group for the user")); + return 0; + } + $userEnt->Gid($userData{primary_group}); + + if ($userData{acc_check_exp}) { + my $yr = $userData{acc_expy}; + my $mo = $userData{acc_expm}; + my $dy = $userData{acc_expd}; + if (!ValidInt($yr, $dy, $mo)) { + AdminPanel::Shared::msgBox(N("Please specify Year, Month and Day \n for Account Expiration ")); + return 0; + } + my $Exp = ConvTime($dy, $mo, $yr); + $userEnt->ShadowExpire($Exp); + } + else { + $userEnt->ShadowExpire(ceil(-1)) + } + + if ($userData{pwd_check_exp}) { + my $allowed = int($userData{pwd_exp_min}); + my $required = int($userData{pwd_exp_max}); + my $warning = int($userData{pwd_exp_warn}); + my $inactive = int($userData{pwd_exp_inact}); + if ($allowed && $required && $warning && $inactive) { + $userEnt->ShadowMin($allowed); + $userEnt->ShadowMax($required); + $userEnt->ShadowWarn($warning); + $userEnt->ShadowInact($inactive); + } + else { + AdminPanel::Shared::msgBox(N("Please fill up all fields in password aging\n")); + return 0; + } + } + else { + $userEnt->ShadowMin(-1); + $userEnt->ShadowMax(99999); + $userEnt->ShadowWarn(-1); + $userEnt->ShadowInact(-1); + } + + $self->ctx->UserModify($userEnt); + + if ($userData{lockuser}) { + !$self->ctx->IsLocked($userEnt) and $self->ctx->Lock($userEnt); + } + else { + $self->ctx->IsLocked($userEnt) and $self->ctx->UnLock($userEnt); + } + + defined $userData{icon_face} and AdminPanel::Shared::Users::addKdmIcon($userData{username}, $userData{icon_face}); + $self->_refresh(); + + return 1; +} + + + +sub _editUserDialog { + my $self = shift; + + my $dontcreatehomedir = 0; + my $is_system = 0; + + ## push application title + my $appTitle = yui::YUI::app()->applicationTitle(); + ## set new title to get it in dialog + yui::YUI::app()->setApplicationTitle(N("Edit User")); + + my $factory = yui::YUI::widgetFactory; + my $optional = yui::YUI::optionalWidgetFactory; + + my $dlg = $factory->createPopupDialog(); + my $layout = $factory->createVBox($dlg); + + my %tabs; + if ($optional->hasDumbTab()) { + my $hbox = $factory->createHBox($layout); + my $align = $factory->createHCenter($hbox); + $tabs{widget} = $optional->createDumbTab($align); + + $tabs{user_data} = new yui::YItem($userEditLabel{user_data}); + $tabs{user_data}->setSelected(); + $tabs{used} = $tabs{user_data}->label(); + $tabs{widget}->addItem( $tabs{user_data} ); + $tabs{user_data}->DISOWN(); + + $tabs{account_info} = new yui::YItem($userEditLabel{account_info}); + $tabs{widget}->addItem( $tabs{account_info} ); + $tabs{account_info}->DISOWN(); + + $tabs{password_info} = new yui::YItem($userEditLabel{password_info}); + $tabs{widget}->addItem( $tabs{password_info} ); + $tabs{password_info}->DISOWN(); + + $tabs{groups} = new yui::YItem($userEditLabel{groups}); + $tabs{widget}->addItem( $tabs{groups} ); + $tabs{groups}->DISOWN(); + + my $vbox = $factory->createVBox($tabs{widget}); + $align = $factory->createLeft($vbox); + $tabs{replace_pnt} = $factory->createReplacePoint($align); + + $hbox = $factory->createHBox($vbox); + $align = $factory->createRight($hbox); + my $cancelButton = $factory->createPushButton($align, N("Cancel")); + my $okButton = $factory->createPushButton($hbox, N("Ok")); + + my %userData = $self->_getUserInfo(); + # userData here should be tested because it could be undef + + # Useful entry point for the current edit user/group tab widget + $self->set_edit_tab_widget( $self->_userDataTabWidget($dlg, $tabs{replace_pnt}, %userData) ); + $self->set_edit_tab_widget( edit_tab_label => $userEditLabel{user_data}); + + while(1) { + my $event = $dlg->waitForEvent(); + my $eventType = $event->eventType(); + + #event type checking + if ($eventType == $yui::YEvent::CancelEvent) { + last; + } + elsif ($eventType == $yui::YEvent::MenuEvent) { + ### MENU ### + my $item = $event->item(); + if ($item->label() eq $tabs{user_data}->label()) { + %userData = $self->_storeDataFromUserEditPreviousTab(%userData); + my %edit_tab = $self->_userDataTabWidget($dlg, $tabs{replace_pnt}, %userData ); + $self->edit_tab_widgets( {} ); + $self->set_edit_tab_widget(%edit_tab); + $self->set_edit_tab_widget( edit_tab_label => $userEditLabel{user_data}); + } + elsif ($item->label() eq $tabs{account_info}->label()) { + %userData = $self->_storeDataFromUserEditPreviousTab(%userData); + my %edit_tab = $self->_userAccountInfoTabWidget($dlg, $tabs{replace_pnt}, %userData ); + $self->edit_tab_widgets( {} ); + $self->set_edit_tab_widget(%edit_tab); + $self->set_edit_tab_widget( edit_tab_label => $userEditLabel{account_info}); + } + elsif ($item->label() eq $tabs{password_info}->label()) { + %userData = $self->_storeDataFromUserEditPreviousTab(%userData); + my %edit_tab = $self->_userPasswordInfoTabWidget($dlg, $tabs{replace_pnt}, %userData ); + $self->edit_tab_widgets( {} ); + $self->set_edit_tab_widget(%edit_tab); + $self->set_edit_tab_widget( edit_tab_label => $userEditLabel{password_info}); + } + elsif ($item->label() eq $tabs{groups}->label()) { + %userData = $self->_storeDataFromUserEditPreviousTab(%userData); + my %edit_tab = $self->_userGroupsTabWidget($dlg, $tabs{replace_pnt}, %userData ); + $self->edit_tab_widgets( {} ); + $self->set_edit_tab_widget(%edit_tab); + $self->set_edit_tab_widget( edit_tab_label => $userEditLabel{groups}); + } + } + elsif ($eventType == $yui::YEvent::WidgetEvent) { + ### widget + my $widget = $event->widget(); + if ($widget == $cancelButton) { + last; + } + elsif ($widget == $okButton) { + ## save changes + if ($self->_userEdit_Ok(%userData)) { + last; + } + } +# last: managing tab widget events + else { + my $current_tab = $self->get_edit_tab_widget('edit_tab_label'); + if ($current_tab && $current_tab eq $userEditLabel{account_info}) { + if ($widget == $self->get_edit_tab_widget('icon_face')) { + my $iconLabel = $self->_skipShortcut($self->get_edit_tab_widget('icon_face')->label()); + my $nextIcon = GetFaceIcon($iconLabel, 1); + $self->get_edit_tab_widget('icon_face')->setLabel($nextIcon); + $self->get_edit_tab_widget('icon_face')->setIcon(AdminPanel::Shared::Users::face2png($nextIcon)); + } + } + elsif ($current_tab && $current_tab eq $userEditLabel{groups}) { + if ($widget == $self->get_edit_tab_widget('members')) { + my $item = $self->get_edit_tab_widget('members')->changedItem(); + if ($item) { + if ($item->checked()) { + # add it to possible primary groups + my $pgItem = new yui::YItem ($item->label(), 0); + $self->get_edit_tab_widget('primary_group')->addItem($pgItem); + } + else { + # remove it to possible primary groups + $dlg->startMultipleChanges(); + my $itemColl = new yui::YItemCollection; + my $tbl = $self->get_edit_tab_widget('members'); + for(my $i=0;$i < $tbl->itemsCount();$i++) { + if ($tbl->toCBYTableItem($tbl->item($i))->checked()) { + my $pgItem = new yui::YItem ($tbl->item($i)->label(), 0); + my $Gent = $self->ctx->LookupGroupById($userData{primary_group}); + my $primgroup = $Gent->GroupName($self->USER_GetValue); + $pgItem->setSelected(1) if ($pgItem->label() eq $primgroup); + + $itemColl->push($pgItem); + $pgItem->DISOWN(); + } + } + $self->get_edit_tab_widget('primary_group')->deleteAllItems(); + $self->get_edit_tab_widget('primary_group')->addItems($itemColl); + $dlg->recalcLayout(); + $dlg->doneMultipleChanges(); + } + } + } + } + } + } + } + + } + else { + AdminPanel::Shared::warningMsgBox(N("Cannot create tab widgets")); + } + + destroy $dlg; + + #restore old application title + yui::YUI::app()->setApplicationTitle($appTitle); + +} + +sub _editGroupDialog { + my $self = shift; + + ## push application title + my $appTitle = yui::YUI::app()->applicationTitle(); + ## set new title to get it in dialog + yui::YUI::app()->setApplicationTitle(N("Edit Group")); + + my $factory = yui::YUI::widgetFactory; + my $optional = yui::YUI::optionalWidgetFactory; + + my $dlg = $factory->createPopupDialog(); + my $layout = $factory->createVBox($dlg); + + my %tabs; + if ($optional->hasDumbTab()) { + my $hbox = $factory->createHBox($layout); + my $align = $factory->createHCenter($hbox); + $tabs{widget} = $optional->createDumbTab($align); + + $tabs{group_data} = new yui::YItem($groupEditLabel{group_data}); + $tabs{group_data}->setSelected(); + $tabs{widget}->addItem( $tabs{group_data} ); + $tabs{group_data}->DISOWN(); + + $tabs{group_users} = new yui::YItem($groupEditLabel{group_users}); + $tabs{widget}->addItem( $tabs{group_users} ); + $tabs{group_users}->DISOWN(); + + my $vbox = $factory->createVBox($tabs{widget}); + $align = $factory->createLeft($vbox); + $tabs{replace_pnt} = $factory->createReplacePoint($align); + + $hbox = $factory->createHBox($vbox); + $align = $factory->createRight($hbox); + my $cancelButton = $factory->createPushButton($align, N("Cancel")); + my $okButton = $factory->createPushButton($hbox, N("Ok")); + + my %groupData = $self->_getGroupInfo(); + # groupData here should be tested because it could be undef + +# %groupData: selected group info as: +# $groupname: group name +# $members: users that are members of this group + + + # Useful entry point for the current edit user/group tab widget + $self->set_edit_tab_widget( $self->_groupDataTabWidget($dlg, $tabs{replace_pnt}, %groupData) ); + $self->set_edit_tab_widget( edit_tab_label => $groupEditLabel{group_data}); + + while(1) { + my $event = $dlg->waitForEvent(); + my $eventType = $event->eventType(); + + #event type checking + if ($eventType == $yui::YEvent::CancelEvent) { + last; + } + elsif ($eventType == $yui::YEvent::MenuEvent) { + ### MENU ### + my $item = $event->item(); + if ($item->label() eq $tabs{group_data}->label()) { + %groupData = $self->_storeDataFromGroupEditPreviousTab(%groupData); + my %edit_tab = $self->_groupDataTabWidget($dlg, $tabs{replace_pnt}, %groupData ); + $self->edit_tab_widgets( {} ); + $self->set_edit_tab_widget(%edit_tab); + $self->set_edit_tab_widget( edit_tab_label => $groupEditLabel{group_data}); + } + elsif ($item->label() eq $tabs{group_users}->label()) { + %groupData = $self->_storeDataFromGroupEditPreviousTab(%groupData); + my %edit_tab = $self->_groupUsersTabWidget($dlg, $tabs{replace_pnt}, %groupData ); + $self->edit_tab_widgets( {} ); + $self->set_edit_tab_widget(%edit_tab); + $self->set_edit_tab_widget( edit_tab_label => $groupEditLabel{group_users}); + } + } + elsif ($eventType == $yui::YEvent::WidgetEvent) { + ### widget + my $widget = $event->widget(); + if ($widget == $cancelButton) { + last; + } + elsif ($widget == $okButton) { + ## save changes + if ($self->_groupEdit_Ok(%groupData)) { + last; + } + } + } + } + + } + else { + AdminPanel::Shared::warningMsgBox(N("Cannot create tab widgets")); + } + + destroy $dlg; + + #restore old application title + yui::YUI::app()->setApplicationTitle($appTitle); + +} + +sub _editUserOrGroup { + my $self = shift; + + # TODO item management avoid label if possible + my $label = $self->_skipShortcut($self->get_widget('tabs')->selectedItem()->label()); + if ($label eq N("Users") ) { + $self->_editUserDialog(); + } + else { + $self->_editGroupDialog(); + } + $self->_refresh(); +} + + +sub _deleteUserOrGroup { + my $self = shift; + + # TODO item management avoid label if possible + my $label = $self->_skipShortcut($self->get_widget('tabs')->selectedItem()->label()); + if ($label eq N("Users") ) { + $self->_deleteUserDialog(); + $self->_refresh(); + } + else { + $self->_deleteGroupDialog(); + $self->_refresh(); + } +} + + +sub _refresh { + my $self = shift; + + # TODO item management avoid label if possible + my $label = $self->_skipShortcut($self->get_widget('tabs')->selectedItem()->label()); + if ($label eq N("Users") ) { + $self->_refreshUsers(); + } + else { + $self->_refreshGroups(); + } +# TODO xguest +# RefreshXguest(1); +} + +# TODO context menu creation is missed in libyui +sub _contextMenuActions { + my $self = shift; + + my $item = $self->get_widget('table')->selectedItem(); + if ($item) { + } +} + +sub _refreshActions { + my $self = shift; + + my $item = $self->get_widget('table')->selectedItem(); + $self->dialog->startMultipleChanges(); + $self->get_widget('action_menu')->deleteAllItems(); + + # do we need to undef them first? + $self->set_action_menu( + add_user => undef, + add_group => undef, + edit => undef, + del => undef, + inst => undef, + ); + $self->set_action_menu( + add_user => new yui::YMenuItem(N("Add User")), + add_group => new yui::YMenuItem(N("Add Group")), + edit => new yui::YMenuItem(N("&Edit")), + del => new yui::YMenuItem(N("&Delete")), + inst => new yui::YMenuItem(N("Install guest account")), + ); + + my $itemColl = new yui::YItemCollection; + for my $pair ( $self->action_menu_pairs ) { + my $menuItem = $pair->[1]; + if ($pair->[0] eq 'edit' || $pair->[0] eq 'del') { + if ($item) { + $itemColl->push($menuItem); + } + } + else { + $itemColl->push($menuItem); + } + $menuItem->DISOWN(); + } + $self->get_widget('action_menu')->addItems($itemColl); + $self->get_widget('action_menu')->rebuildMenuTree(); + if ($item) { + $self->get_widget('edit')->setEnabled(); + $self->get_widget('del')->setEnabled(); + } + else { + $self->get_widget('edit')->setDisabled(); + $self->get_widget('del')->setDisabled(); + } + + $self->dialog->doneMultipleChanges(); +} + + +sub manageUsersDialog { + my $self = shift; + + ## TODO fix for adminpanel + my $pixdir = '/usr/share/userdrake/pixmaps/'; + ## push application title + my $appTitle = yui::YUI::app()->applicationTitle(); + + ## set new title to get it in dialog + yui::YUI::app()->setApplicationTitle($self->name); + ## set icon if not already set by external launcher + yui::YUI::app()->setApplicationIcon($self->icon); + + + my $factory = yui::YUI::widgetFactory; + my $optional = yui::YUI::optionalWidgetFactory; + + + $self->dialog($factory->createMainDialog()); + my $layout = $factory->createVBox($self->dialog); + + my $hbox_headbar = $factory->createHBox($layout); + 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,N("File")), + refresh => new yui::YMenuItem(N("Refresh")), + quit => new yui::YMenuItem(N("&Quit")), + ); + + $fileMenu{ widget }->addItem($fileMenu{ refresh }); + $fileMenu{ widget }->addItem($fileMenu{ quit }); + $fileMenu{ widget }->rebuildMenuTree(); + + my $actionMenu = $factory->createMenuButton($headbar, N("Actions")); + $actionMenu->DISOWN(); + + my %helpMenu = ( + widget => $factory->createMenuButton($headRight, N("&Help")), + help => new yui::YMenuItem(N("Help")), + report_bug => new yui::YMenuItem(N("Report Bug")), + about => new yui::YMenuItem(N("&About")), + ); + + while ( my ($key, $value) = each(%helpMenu) ) { + if ($key ne 'widget' ) { + $helpMenu{ widget }->addItem($value); + } + } + $helpMenu{ widget }->rebuildMenuTree(); + + my $hbox = $factory->createHBox($layout); + $hbox = $factory->createHBox($factory->createLeft($hbox)); + $self->set_widget( + add_user => $factory->createIconButton($hbox, $pixdir . 'user_add.png', N("Add User")), + add_group => $factory->createIconButton($hbox, $pixdir . 'group_add.png', N("Add Group")), + edit => $factory->createIconButton($hbox, $pixdir . 'user_conf.png', N("Edit")), + del => $factory->createIconButton($hbox, $pixdir . 'user_del.png', N("Delete")), + refresh => $factory->createIconButton($hbox, $pixdir . 'refresh.png', N("Refresh")), + action_menu => $actionMenu, + ); + + + $hbox = $factory->createHBox($layout); + $head_align_left = $factory->createLeft($hbox); + $self->set_widget(filter_system => $factory->createCheckBox($head_align_left, N("Filter system users"), 1)); + $factory->createHSpacing($hbox, 3); + $head_align_right = $factory->createRight($hbox); + $headRight = $factory->createHBox($head_align_right); + $factory->createLabel($headRight, N("Search:")); + $self->set_widget(filter => $factory->createInputField($headRight, "", 0)); + $self->set_widget(apply_filter => $factory->createPushButton($headRight, N("Apply filter"))); + $self->get_widget('filter')->setWeight($yui::YD_HORIZ, 2); + $self->get_widget('apply_filter')->setWeight($yui::YD_HORIZ, 1); + $self->get_widget('filter_system')->setNotify(1); + + my %tabs; + if ($optional->hasDumbTab()) { + $hbox = $factory->createHBox($layout); + my $align = $factory->createHCenter($hbox); + $self->set_widget(tabs => $optional->createDumbTab($align)); + $tabs{users} = new yui::YItem(N("Users")); + $tabs{users}->setSelected(); + $self->get_widget('tabs')->addItem( $tabs{users} ); + $tabs{users}->DISOWN(); + $tabs{groups} = new yui::YItem(N("Groups")); + $self->get_widget('tabs')->addItem( $tabs{groups} ); + $tabs{groups}->DISOWN(); + my $vbox = $factory->createVBox($self->get_widget('tabs')); + $align = $factory->createLeft($vbox); + $self->set_widget(replace_pnt => $factory->createReplacePoint($align)); + $self->_createUserTable(); + $self->get_widget('table')->setImmediateMode(1); + $self->get_widget('table')->DISOWN(); + } + + $self->_refreshActions(); + + # main loop + while(1) { + my $event = $self->dialog->waitForEvent(); + my $eventType = $event->eventType(); + + #event type checking + if ($eventType == $yui::YEvent::CancelEvent) { + last; + } + elsif ($eventType == $yui::YEvent::MenuEvent) { +### MENU ### + my $item = $event->item(); + my $menuLabel = $item->label(); + if ($menuLabel eq $fileMenu{ quit }->label()) { + last; + } + elsif ($menuLabel eq $helpMenu{about}->label()) { + my $license = translate($AdminPanel::Shared::License); + AboutDialog({ name => N("AdminUser"), + version => $self->VERSION, + copyright => N("Copyright (C) %s Mageia community", '2013-2014'), + license => $license, + comments => N("AdminUser is a Mageia user management tool \n(from the original idea of Mandriva userdrake)."), + website => 'http://www.mageia.org', + website_label => N("Mageia"), + authors => "Angelo Naselli \nMatteo Pasotti ", + translator_credits => + #-PO: put here name(s) and email(s) of translator(s) (eg: "John Smith ") + N("_: Translator(s) name(s) & email(s)\n")} + ); + } + elsif ($menuLabel eq $self->get_action_menu('add_user')->label()) { + $self->addUserDialog(); + $self->_refresh(); + } + elsif ($menuLabel eq $self->get_action_menu('add_group')->label()) { + $self->_addGroupDialog(); + $self->_refresh(); + } + elsif ($menuLabel eq $self->get_action_menu('del')->label()) { + $self->_deleteUserOrGroup(); + } + elsif ($menuLabel eq $self->get_action_menu('edit')->label()) { + $self->_editUserOrGroup(); + } + elsif ($self->get_widget('tabs') && $menuLabel eq $tabs{groups}->label()) { + $self->_createGroupTable(); + } + elsif ($self->get_widget('tabs') && $menuLabel eq $tabs{users}->label()) { + $self->_createUserTable(); + } + elsif ($menuLabel eq $fileMenu{refresh}->label()) { + $self->_refresh(); + } + } + elsif ($eventType == $yui::YEvent::WidgetEvent) { +### Buttons and widgets ### + my $widget = $event->widget(); + if ($widget == $self->get_widget('add_user')) { + $self->addUserDialog(); + $self->_refresh(); + } + elsif ($widget == $self->get_widget('del')) { + $self->_deleteUserOrGroup(); + } + elsif ($widget == $self->get_widget('table')) { + $self->_refreshActions(); + my $wEvent = yui::YMGAWidgetFactory::getYWidgetEvent($event); + if ($wEvent && $wEvent->reason() == $yui::YEvent::Activated) { + $self->_editUserOrGroup(); + } + } + elsif ($widget == $self->get_widget('add_group')) { + $self->_addGroupDialog(); + $self->_refresh(); + } + elsif ($widget == $self->get_widget('edit')) { + $self->_editUserOrGroup(); + } + elsif ( $widget == $self->get_widget('filter_system') || + $widget == $self->get_widget('refresh') || + $widget == $self->get_widget('apply_filter') ) { + $self->_refresh(); + } + } + } + + $self->dialog->destroy() ; + + #restore old application title + yui::YUI::app()->setApplicationTitle($appTitle) if $appTitle; +} + +#============================================================= + +=head2 _skipShortcut + +=head3 INPUT + + $self: this object + $label: an item label to be cleaned by keyboard shortcut "&" + +=head3 OUTPUT + + $label: cleaned label + +=head3 DESCRIPTION + + This internal method is a workaround to label that are + changed by "&" due to keyborad shortcut. + +=cut + +#============================================================= +sub _skipShortcut { + my ($self, $label) = @_; + + $label =~ s/&// if ($label); + + return ($label); +} + +#============================================================= + +=head2 _inArray + +=head3 INPUT + + $self: this object + $item: item to search + $arr: array container + +=head3 OUTPUT + + true: if the array contains the item + +=head3 DESCRIPTION + +This method returns if an item is into the array container + +=cut + +#============================================================= +sub _inArray { + my ($self, $item, $arr) = @_; + + return grep( /^$item$/, @$arr ); +} + + +sub ValidInt { + foreach my $i (@_) { $i =~ /\d+/ or return 0 } + return 1; +} + +sub ConvTime { + my ($day, $month, $year) = @_; + my ($tm, $days, $mon, $yr); + $mon = $month - 1; $yr = $year - 1900; + $tm = POSIX::mktime(0, 0, 0, $day, $mon, $yr); + $days = ceil($tm / (24 * 60 * 60)); + return $days; +} + +sub TimeOfArray { + my ($reltime, $cm) = @_; + my $h; my %mth = (Jan => 1, Feb => 2, Mar => 3, Apr => 4, May => 5, Jun => 6, Jul => 7, Aug => 8, Sep => 9, Oct => 10, Nov => 11, Dec => 12); + my $_t = localtime($reltime * 24 * 60 * 60) =~ /(\S+)\s+(\S+)\s+(\d+)\s+(\S+)\s+(\d+)/; + $h->{daystr} = $1; + $h->{month} = $2; + $h->{dayint} = $3; + $h->{year} = $5; + $cm and $h->{month} = $mth{$2}; + $h; +} + + +no Moose; +__PACKAGE__->meta->make_immutable; + +1; diff --git a/lib/AdminPanel/Privileges.pm b/lib/AdminPanel/Privileges.pm new file mode 100644 index 00000000..73f20984 --- /dev/null +++ b/lib/AdminPanel/Privileges.pm @@ -0,0 +1,61 @@ +# vim: set et ts=4 sw=4: +# Copyright 2012-2013 Matteo Pasotti +# +# This file is part of AdminPanel +# +# AdminPanel is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# AdminPanel is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with AdminPanel. If not, see . + +package AdminPanel::Privileges; + +use strict; +use warnings; +use diagnostics; +require Exporter; +use base qw(Exporter); +use English qw(-no_match_vars); + +our @EXPORT = qw(require_root_capability + ask_for_authentication); + +my $wrappers = { "sudo" => "sudo", + "pkit" => "pkexec", + "chlp" => "consolehelper" + }; + +my $wrapper = 0; + +sub require_root_capability { + return $EUID != 0; +} + +sub ask_for_authentication { + my $wrapper_id = shift; + $wrapper = $wrappers->{$wrapper_id} if(defined($wrappers->{$wrapper_id})); + my ($command, @args) = wrap_command($0, @ARGV); + unshift(@args,$command->[1]); + unshift(@args, '-n') if($wrapper_id eq "sudo"); # let sudo die if password is needed + exec { $command->[0] } $command->[1], @args or die ("command %s missing", $command->[0]); +} + +sub wrap_command { + my ($app, @args) = @_; + return ([$wrapper, $app], @args); +} + +sub get_wrapper { + my $id = shift; + return $wrappers->{$id} if(defined($wrappers->{$id})); +} + +1; diff --git a/lib/AdminPanel/Rpmdragora/.perl_checker b/lib/AdminPanel/Rpmdragora/.perl_checker new file mode 100644 index 00000000..202e0535 --- /dev/null +++ b/lib/AdminPanel/Rpmdragora/.perl_checker @@ -0,0 +1 @@ +Basedir .. diff --git a/lib/AdminPanel/Rpmdragora/edit_urpm_sources.pm b/lib/AdminPanel/Rpmdragora/edit_urpm_sources.pm new file mode 100644 index 00000000..9ef5d00b --- /dev/null +++ b/lib/AdminPanel/Rpmdragora/edit_urpm_sources.pm @@ -0,0 +1,1216 @@ +# vim: set et ts=4 sw=4: +package AdminPanel::Rpmdragora::edit_urpm_sources; +#***************************************************************************** +# +# Copyright (c) 2002 Guillaume Cottenceau +# Copyright (c) 2002-2007 Thierry Vignaud +# Copyright (c) 2002-2007 Mandriva Linux +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** +# +# $Id: edit_urpm_sources.pm 266598 2010-03-03 12:00:58Z tv $ + + +use strict; +use lib qw(/usr/lib/libDrakX); +use common; +use AdminPanel::rpmdragora; +use AdminPanel::Rpmdragora::open_db; +use AdminPanel::Rpmdragora::formatting; +use URPM::Signature; +use MDK::Common::Math qw(max); +use urpm::media; +use urpm::download; +use urpm::lock; + +use Exporter; +our @ISA = qw(Exporter); +our @EXPORT = qw(run); + +#use mygtk2 qw(gtknew gtkset); +#use ugtk2 qw(:all); + +my $urpm; +my ($mainw, $list_tv, $something_changed); + +my %col = ( + mainw => { + is_enabled => 0, + is_update => 1, + type => 2, + name => 3, + activatable => 4 + }, +); + + +sub get_medium_type { + my ($medium) = @_; + my %medium_type = ( + cdrom => N("CD-ROM"), + ftp => N("FTP"), + file => N("Local"), + http => N("HTTP"), + https => N("HTTPS"), + nfs => N("NFS"), + removable => N("Removable"), + rsync => N("rsync"), + ssh => N("NFS"), + ); + return N("Mirror list") if $medium->{mirrorlist}; + return $medium_type{$1} if $medium->{url} =~ m!^([^:]*)://!; + return 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() { + distro_type(0) eq 'updates' ? interactive_msg( + N("Choose media type"), +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 => N("Full set of sources"), no => 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; + my $distro = $rpmdragora::mandrake_release; + my ($mirror) = choose_mirror($urpm, message => +N("This will attempt to install all official sources corresponding to your +distribution (%s). + +I need to contact the Mageia website to get the mirror list. +Please check that your network is currently running. + +Is it ok to continue?", $distro), + transient => $::main_window, + ) or return 0; + ref $mirror or return; + my $wait = wait_msg(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; + warn_for_network_need(undef, transient => $::main_window) or return; + my $wait = wait_msg(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; +} + +sub add_callback() { + my $w = ugtk2->new(N("Add a medium"), grab => 1, center => 1, transient => $::main_window); + my $prev_main_window = $::main_window; + local $::main_window = $w->{real_window}; + my %radios_infos = ( + local => { name => N("Local files"), url => N("Medium path:"), dirsel => 1 }, + ftp => { name => N("FTP server"), url => N("URL:"), loginpass => 1 }, + rsync => { name => N("RSYNC server"), url => N("URL:") }, + http => { name => N("HTTP server"), url => N("URL:") }, + removable => { name => N("Removable device (CD-ROM, DVD, ...)"), url => N("Path or mount point:"), dirsel => 1 }, + ); + my @radios_names_ordered = qw(local ftp rsync http removable); + # TODO: replace NoteBook by sensitive widgets and Label->set() + my $notebook = gtknew('Notebook'); + $notebook->set_show_tabs(0); $notebook->set_show_border(0); + my ($count_nbs, %pages); + my $size_group = Gtk2::SizeGroup->new('horizontal'); + my ($cb1, $cb2); + foreach (@radios_names_ordered) { + my $info = $radios_infos{$_}; + my $url_entry = sub { + gtkpack_( + gtknew('HBox'), + 1, $info->{url_entry} = gtkentry(), + if_( + $info->{dirsel}, + 0, gtksignal_connect( + gtknew('Button', text => but(N("Browse..."))), + clicked => sub { $info->{url_entry}->set_text(ask_dir()) }, + ) + ), + ); + }; + my $checkbut_entry = sub { + my ($name, $label, $visibility, $callback, $tip) = @_; + my $w = [ gtksignal_connect( + $info->{$name . '_check'} = gtkset(gtknew('CheckButton', text => $label), tip => $tip), + clicked => sub { + $info->{$name . '_entry'}->set_sensitive($_[0]->get_active); + $callback and $callback->(@_); + }, + ), + gtkset_visibility(gtkset_sensitive($info->{$name . '_entry'} = gtkentry(), 0), $visibility) ]; + $size_group->add_widget($info->{$name . '_check'}); + $w; + }; + my $loginpass_entries = sub { + map { + $checkbut_entry->( + @$_, sub { + $info->{pass_check}->set_active($_[0]->get_active); + $info->{login_check}->set_active($_[0]->get_active); + } + ); + } ([ 'login', N("Login:"), 1 ], [ 'pass', N("Password:"), 0 ]); + }; + $pages{$info->{name}} = $count_nbs++; + $notebook->append_page( + gtkshow(create_packtable( + { xpadding => 0, ypadding => 0 }, + [ gtkset_alignment(gtknew('Label', text => N("Medium name:")), 0, 0.5), + $info->{name_entry} = gtkentry('') ], + [ gtkset_alignment(gtknew('Label', text => $info->{url}), 0, 0.5), + $url_entry->() ], + if_($info->{loginpass}, $loginpass_entries->()), + sub { + [ $info->{distrib_check} = $cb1 = gtknew('CheckButton', text => N("Create media for a whole distribution"), + toggled => sub { + return if !$cb2; + my ($w) = @_; + $info->{update_check}->set_sensitive(!$w->get_active); + }) + ]; + }->(), + sub { + [ $info->{update_check} = $cb2 = gtknew('CheckButton', text => N("Tag this medium as an update medium")) ]; + }->(), + )) + ); + } + $size_group->add_widget($_) foreach $cb1, $cb2; + + my $checkok = sub { + my $info = $radios_infos{$radios_names_ordered[$notebook->get_current_page]}; + my ($name, $url) = map { $info->{$_ . '_entry'}->get_text } qw(name url); + $name eq '' || $url eq '' and interactive_msg('rpmdragora', N("You need to fill up at least the two first entries.")), return 0; + if (member($name, map { $_->{name} } @{$urpm->{media}})) { + $info->{name_entry}->select_region(0, -1); + interactive_msg('rpmdragora', +N("There is already a medium by that name, do you +really want to replace it?"), yesno => 1) or return 0; + } + 1; + }; + + my $type = 'local'; + my (%i, %make_url); + gtkadd( + $w->{window}, + gtkpack( + gtknew('VBox', spacing => 5), + gtknew('Title2', label => N("Adding a medium:")), + gtknew('HBox', children_tight => [ + Gtk2::Label->new(but(N("Type of medium:"))), + gtknew('ComboBox', text_ref => \$type, + list => \@radios_names_ordered, + format => sub { $radios_infos{$_[0]}{name} }, + changed => sub { $notebook->set_current_page($pages{$_[0]->get_text}) }) + ]), + $notebook, + gtknew('HSeparator'), + gtkpack( + gtknew('HButtonBox'), + gtknew('Button', text => N("Cancel"), clicked => sub { $w->{retval} = 0; Gtk2->main_quit }), + gtksignal_connect( + gtknew('Button', text => N("Ok")), clicked => sub { + if ($checkok->()) { + $w->{retval} = { nb => $notebook->get_current_page }; + my $info = $radios_infos{$type}; + %i = ( + name => $info->{name_entry}->get_text, + url => $info->{url_entry}->get_text, + distrib => $info->{distrib_check} ? $info->{distrib_check}->get_active : 0, + update => $info->{update_check}->get_active ? 1 : undef, + ); + %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", + $info->{login_check}->get_active + ? ($info->{login_entry}->get_text . ':' . $info->{pass_entry}->get_text . '@') + : '', + $i{url}; + Gtk2->main_quit; + } + }, + ), + ), + ), + ); + + if ($w->main) { + $::main_window = $prev_main_window; + if ($i{distrib}) { + add_medium_and_check( + $urpm, + { nolock => 1, distrib => 1 }, + $i{name}, $make_url{$type}, 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{$type}, $i{hdlist}, update => $i{update}, + ); + } + return 1; + } + return 0; +} + +sub options_callback() { + my $w = ugtk2->new(N("Global options for package installation"), grab => 1, center => 1, transient => $::main_window); + local $::main_window = $w->{real_window}; + my %verif = (0 => N("never"), 1 => N("always")); + my $verify_rpm = $urpm->{global_config}{'verify-rpm'}; + my @avail_downloaders = urpm::download::available_ftp_http_downloaders(); + my $downloader = $urpm->{global_config}{downloader} || $avail_downloaders[0]; + my %xml_info_policies = ( + 'never' => N("Never"), + 'on-demand' => N("On-demand"), + 'update-only' => N("Update-only"), + 'always' => N("Always"), + ); + my $xml_info_policy = $urpm->{global_config}{'xml-info'}; + + gtkadd( + $w->{window}, + gtkpack( + gtknew('VBox', spacing => 5), + gtknew('HBox', children_loose => [ gtknew('Label', text => N("Verify RPMs to be installed:")), + gtknew('ComboBox', list => [ keys %verif ], text_ref => \$verify_rpm, + format => sub { $verif{$_[0]} || $_[0] }, + ) + ]), + gtknew('HBox', children_loose => [ gtknew('Label', text => N("Download program to use:")), + gtknew('ComboBox', list => \@avail_downloaders, text_ref => \$downloader, + format => sub { $verif{$_[0]} || $_[0] }, + ) + ]), + gtknew('HBox', + children_loose => + [ gtknew('Label', text => N("XML meta-data download policy:")), + gtknew('ComboBox', + list => [ keys %xml_info_policies ], text_ref => \$xml_info_policy, + + format => sub { $xml_info_policies{$_[0]} || $_[0] }, + tip => + join("\n", + N("For remote media, specify when XML meta-data (file lists, changelogs & information) are downloaded."), + '', + N("Never"), + N("For remote media, XML meta-data are never downloaded."), + '', + N("On-demand"), + N("(This is the default)"), + N("The specific XML info file is downloaded when clicking on package."), + '', + N("Update-only"), + N("Updating media implies updating XML info files already required at least once."), + '', + N("Always"), + N("All XML info files are downloaded when adding or updating media."), + ), + ), + ]), + + gtkpack( + gtknew('HButtonBox'), + gtknew('Button', text => N("Cancel"), clicked => sub { Gtk2->main_quit }), + gtksignal_connect( + gtknew('Button', text => N("Ok")), clicked => sub { + $urpm->{global_config}{'verify-rpm'} = $verify_rpm; + $urpm->{global_config}{downloader} = $downloader; + $urpm->{global_config}{'xml-info'} = $xml_info_policy; + $something_changed = 1; + urpm::media::write_config($urpm); + $urpm = fast_open_urpmi_db(); + Gtk2->main_quit; + }, + ), + ), + ), + ); + $w->main; +} + +sub remove_callback() { + my @rows = selected_rows(); + @rows == 0 and return; + interactive_msg( + N("Source Removal"), + @rows == 1 ? + N("Are you sure you want to remove source \"%s\"?", $urpm->{media}[$rows[0]]{name}) : + N("Are you sure you want to remove the following sources?") . "\n\n" . + format_list(map { $urpm->{media}[$_]{name} } @rows), + yesno => 1, scroll => 1, + transient => $::main_window, + ) or return; + + my $wait = wait_msg(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; +} + +sub renum_media ($$$) { + my ($model, @iters) = @_; + my @rows = map { $model->get_path($_)->to_string } @iters; + my @media = map { $urpm->{media}[$_] } @rows; + $urpm->{media}[$rows[$_]] = $media[1 - $_] foreach 0, 1; + $model->swap(@iters); + $something_changed = 1; + urpm::media::write_config($urpm); + $urpm = fast_open_urpmi_db(); +} + +sub upwards_callback() { + my @rows = selected_rows(); + @rows == 0 and return; + my $model = $list_tv->get_model; + my $prev = $model->get_iter_from_string($rows[0] - 1); + defined $prev and renum_media($model, $model->get_iter_from_string($rows[0]), $prev); + $list_tv->get_selection->signal_emit('changed'); +} + +sub downwards_callback() { + my @rows = selected_rows(); + @rows == 0 and return; + my $model = $list_tv->get_model; + my $iter = $model->get_iter_from_string($rows[0]); + my $next = $model->iter_next($iter); + defined $next and renum_media($model, $iter, $next); + $list_tv->get_selection->signal_emit('changed'); +} + +#- returns the name of the media for which edition failed, or undef on success +sub edit_callback() { + my ($row) = selected_rows(); + $row == -1 and return; + 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 $old_main_window = $::main_window; + my $w = ugtk2->new(N("Edit a medium"), grab => 1, center => 1, transient => $::main_window); + local $::main_window = $w->{real_window}; + my ($url_entry, $downloader_entry, $url, $downloader); + gtkadd( + $w->{window}, + gtkpack_( + gtknew('VBox', spacing => 5), + 0, gtknew('Title2', label => N("Editing medium \"%s\":", $medium->{name})), + 0, create_packtable( + {}, + [ gtknew('Label_Left', text => N("URL:")), $url_entry = gtkentry($verbatim_medium->{url} || $verbatim_medium->{mirrorlist}) ], + [ gtknew('Label_Left', text => N("Downloader:")), + my $download_combo = Gtk2::ComboBox->new_with_strings([ urpm::download::available_ftp_http_downloaders() ], + $verbatim_medium->{downloader} || '') ], + ), + 0, gtknew('HSeparator'), + 0, gtkpack( + gtknew('HButtonBox'), + gtksignal_connect( + gtknew('Button', text => N("Cancel")), + clicked => sub { $w->{retval} = 0; Gtk2->main_quit }, + ), + gtksignal_connect( + gtknew('Button', text => N("Save changes")), + clicked => sub { + $w->{retval} = 1; + $url = $url_entry->get_text; + $downloader = $downloader_entry->get_text; + Gtk2->main_quit; + }, + ), + gtksignal_connect( + gtknew('Button', text => N("Proxy...")), + clicked => sub { proxy_callback($medium) }, + ), + ) + ) + ); + $downloader_entry = $download_combo->entry; + $w->{rwindow}->set_size_request(600, -1); + if ($w->main) { + my ($name, $update) = map { $medium->{$_} } qw(name update); + $url =~ m|^removable://| and ( + interactive_msg( + N("You need to insert the medium to continue"), + N("In order to save the changes, you need to insert the medium in the drive."), + yesno => 1, text => { yes => N("Ok"), no => N("Cancel") } + ) or return 0 + ); + my $saved_proxy = urpm::download::get_proxy($name); + undef $saved_proxy if !defined $saved_proxy->{http_proxy} && !defined $saved_proxy->{ftp_proxy}; + urpm::media::select_media($urpm, $name); + if (my ($media) = grep { $_->{name} eq $name } @{$urpm->{media}}) { + put_in_hash($media, { + ($verbatim_medium->{mirrorlist} ? 'mirrorlist' : 'url') => $url, + name => $name, + if_($update ne $media->{update} || $update, update => $update), + if_($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); + local $::main_window = $old_main_window; + update_sources_noninteractive($urpm, [ $name ], transient => $::main_window, nolock => 1); + } else { + urpm::media::remove_selected_media($urpm); + add_medium_and_check($urpm, { nolock => 1, proxy => $saved_proxy }, $name, $url, undef, update => $update, if_($downloader, downloader => $downloader)); + } + return $name; + } + return undef; +} + +sub update_callback() { + update_sources_interactive($urpm, transient => $::main_window, nolock => 1); +} + +sub proxy_callback { + my ($medium) = @_; + my $medium_name = $medium ? $medium->{name} : ''; + my $w = ugtk2->new(N("Configure proxies"), grab => 1, center => 1, transient => $::main_window); + local $::main_window = $w->{real_window}; + require curl_download; + my ($proxy, $proxy_user) = curl_download::readproxy($medium_name); + my ($user, $pass) = $proxy_user =~ /^([^:]*):(.*)$/; + my ($proxybutton, $proxyentry, $proxyuserbutton, $proxyuserentry, $proxypasswordentry); + my $sg = Gtk2::SizeGroup->new('horizontal'); + gtkadd( + $w->{window}, + gtkpack__( + gtknew('VBox', spacing => 5), + gtknew('Title2', label => + $medium_name + ? N("Proxy settings for media \"%s\"", $medium_name) + : N("Global proxy settings") + ), + gtknew('Label_Left', text => N("If you need a proxy, enter the hostname and an optional port (syntax: ):")), + gtkpack_( + gtknew('HBox', spacing => 10), + 1, gtkset_active($proxybutton = gtknew('CheckButton', text => N("Proxy hostname:")), to_bool($proxy)), + 0, gtkadd_widget($sg, gtkset_sensitive($proxyentry = gtkentry($proxy), to_bool($proxy))), + ), + gtkset_active($proxyuserbutton = gtknew('CheckButton', text => N("You may specify a username/password for the proxy authentication:")), to_bool($proxy_user)), + gtkpack_( + my $hb_user = gtknew('HBox', spacing => 10, sensitive => to_bool($proxy_user)), + 1, gtknew('Label_Left', text => N("User:")), + 0, gtkadd_widget($sg, $proxyuserentry = gtkentry($user)), + ), + gtkpack_( + my $hb_pswd = gtknew('HBox', spacing => 10, sensitive => to_bool($proxy_user)), + 1, gtknew('Label_Left', text => N("Password:")), + 0, gtkadd_widget($sg, gtkset_visibility($proxypasswordentry = gtkentry($pass), 0)), + ), + gtknew('HSeparator'), + gtkpack( + gtknew('HButtonBox'), + gtksignal_connect( + gtknew('Button', text => N("Ok")), + clicked => sub { + $w->{retval} = 1; + $proxy = $proxybutton->get_active ? $proxyentry->get_text : ''; + $proxy_user = $proxyuserbutton->get_active + ? ($proxyuserentry->get_text . ':' . $proxypasswordentry->get_text) : ''; + Gtk2->main_quit; + }, + ), + gtksignal_connect( + gtknew('Button', text => N("Cancel")), + clicked => sub { $w->{retval} = 0; Gtk2->main_quit }, + ) + ) + ) + ); + $sg->add_widget($_) foreach $proxyentry, $proxyuserentry, $proxypasswordentry; + $proxybutton->signal_connect( + clicked => sub { + $proxyentry->set_sensitive($_[0]->get_active); + $_[0]->get_active and return; + $proxyuserbutton->set_active(0); + $hb_user->set_sensitive(0); + $hb_pswd->set_sensitive(0); + } + ); + $proxyuserbutton->signal_connect(clicked => sub { $_->set_sensitive($_[0]->get_active) foreach $hb_user, $hb_pswd; + $proxypasswordentry->set_sensitive($_[0]->get_active) }); + + $w->main and do { + $something_changed = 1; + curl_download::writeproxy($proxy, $proxy_user, $medium_name); + }; +} + +sub parallel_read_sysconf() { + my @conf; + foreach (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 => N("Ok"), clicked => sub { $w->{retval} = 1; $get_value->(); Gtk2->main_quit }), + gtknew('Button', text => 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 ? N("Add a parallel group") : 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_(N("Add a medium limit"), 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_(N("Add a host"), 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 => N("Editing parallel group \"%s\":", $edited->{name})) + ), + 1, create_packtable( + {}, + [ N("Group name:"), $name_entry = gtkentry($edited->{name}) ], + [ N("Protocol:"), gtknew('HBox', children_tight => [ + @protocols = gtkradio($edited->{protocol}, @protocols_names) ]) ], + [ 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(N("Add"))), clicked => sub { $add_media->() }), + gtksignal_connect(Gtk2::Button->new(but(N("Remove"))), clicked => sub { + remove_from_list($medias, $edited->{medias}, $medias_ls); + }) ]) ]) ], + [ 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(N("Add"))), clicked => sub { $add_host->() }), + gtksignal_connect(Gtk2::Button->new(but(N("Remove"))), clicked => sub { + remove_from_list($hosts, $hosts_list, $hosts_ls); + }) ]) ]) ] + ), + 0, gtknew('HSeparator'), + 0, gtkpack( + gtknew('HButtonBox'), + gtksignal_connect( + gtknew('Button', text => 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 => 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(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)) } N("Group"), N("Protocol"), N("Media limit"); + $list->append_column(my $commandcol = Gtk2::TreeViewColumn->new_with_attributes(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}}) : 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(N("Remove"))), + clicked => sub { remove_parallel(selrow($list), $conf); $reread->() }, + ), + gtksignal_connect( + Gtk2::Button->new(but(N("Edit..."))), + clicked => sub { + my $row = selrow($list); + $row != -1 and edit_parallel($row, $conf); + $reread->(); + }, + ), + gtksignal_connect( + Gtk2::Button->new(but(N("Add..."))), + clicked => sub { edit_parallel(-1, $conf) and $reread->() }, + ) + ) + ), + 0, gtknew('HSeparator'), + 0, gtkpack( + gtknew('HButtonBox'), + gtknew('Button', text => N("Ok"), clicked => sub { Gtk2->main_quit }) + ) + ) + ); + $w->main; +} + +sub keys_callback() { + my $w = ugtk2->new(N("Manage keys for digital signatures of packages"), grab => 1, center => 1, transient => $mainw->{real_window}); + local $::main_window = $w->{real_window}; + $w->{real_window}->set_size_request(600, 300); + + my $media_list_ls = Gtk2::ListStore->new("Glib::String"); + my $media_list = Gtk2::TreeView->new_with_model($media_list_ls); + $media_list->append_column(Gtk2::TreeViewColumn->new_with_attributes(N("Medium"), Gtk2::CellRendererText->new, 'text' => 0)); + $media_list->get_selection->set_mode('browse'); + + my $key_col_size = 200; + my $keys_list_ls = Gtk2::ListStore->new("Glib::String", "Glib::String"); + my $keys_list = Gtk2::TreeView->new_with_model($keys_list_ls); + $keys_list->set_rules_hint(1); + $keys_list->append_column(my $col = Gtk2::TreeViewColumn->new_with_attributes(N("_:cryptographic keys\nKeys"), my $renderer = Gtk2::CellRendererText->new, 'text' => 0)); + $col->set_sizing('fixed'); + $col->set_fixed_width($key_col_size); + $renderer->set_property('width' => 1); + $renderer->set_property('wrap-width', $key_col_size); + $keys_list->get_selection->set_mode('browse'); + + my ($current_medium, $current_medium_nb, @keys); + + 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->(); + $media_list->get_selection->signal_emit('changed'); + }; + $read_conf->(); + my $key_name = sub { + exists $urpm->{keys}{$_[0]} ? $urpm->{keys}{$_[0]}{name} + : N("no name found, key doesn't exist in rpm keyring!"); + }; + $media_list_ls->append_set([ 0 => $_->{name} ]) foreach @{$urpm->{media}}; + $media_list->get_selection->signal_connect(changed => sub { + my ($model, $iter) = $_[0]->get_selected; + $model && $iter or return; + $current_medium = $model->get($iter, 0); + $current_medium_nb = $model->get_path($iter)->to_string; + $keys_list_ls->clear; + $keys_list_ls->append_set([ 0 => sprintf("%s (%s)", $_, $key_name->($_)), 1 => $_ ]) foreach @{$keys[$current_medium_nb]}; + }); + + my $add_key = sub { + my $available_keyz_ls = Gtk2::ListStore->new("Glib::String", "Glib::String"); + my $available_keyz = Gtk2::TreeView->new_with_model($available_keyz_ls); + $available_keyz->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, 'text' => 0)); + $available_keyz->set_headers_visible(0); + $available_keyz->get_selection->set_mode('browse'); + $available_keyz_ls->append_set([ 0 => sprintf("%s (%s)", $_, $key_name->($_)), 1 => $_ ]) foreach keys %{$urpm->{keys}}; + my $key; + add_callback_(N("Add a key"), N("Choose a key to add to the medium %s", $current_medium), $w, $available_keyz, + sub { + my ($model, $iter) = $available_keyz->get_selection->get_selected; + $model && $iter and $key = $model->get($iter, 1); + }, + sub { + return if !defined $key; + $urpm->{media}[$current_medium_nb]{'key-ids'} = join(',', sort(uniq(@{$keys[$current_medium_nb]}, $key))); + $write->(); + } + ); + + + }; + + my $remove_key = sub { + my ($model, $iter) = $keys_list->get_selection->get_selected; + $model && $iter or return; + my $key = $model->get($iter, 1); + interactive_msg(N("Remove a key"), + N("Are you sure you want to remove the key %s from medium %s?\n(name of the key: %s)", + $key, $current_medium, $key_name->($key)), + yesno => 1, transient => $w->{real_window}) or return; + $urpm->{media}[$current_medium_nb]{'key-ids'} = join(',', difference2(\@{$keys[$current_medium_nb]}, [ $key ])); + $write->(); + }; + + gtkadd( + $w->{window}, + gtkpack_( + gtknew('VBox', spacing => 5), + 1, gtkpack_( + gtknew('HBox', spacing => 10), + 1, create_scrolled_window($media_list), + 1, create_scrolled_window($keys_list), + 0, gtkpack__( + gtknew('VBox', spacing => 5), + gtksignal_connect( + Gtk2::Button->new(but(N("Add"))), + clicked => \&$add_key, + ), + gtksignal_connect( + Gtk2::Button->new(but(N("Remove"))), + clicked => \&$remove_key, + ) + ) + ), + 0, gtknew('HSeparator'), + 0, gtkpack( + gtknew('HButtonBox'), + gtknew('Button', text => N("Ok"), clicked => sub { Gtk2->main_quit }) + ), + ), + ); + $w->main; +} + +sub mainwindow() { + undef $something_changed; + $mainw = ugtk2->new(N("Configure media"), center => 1, transient => $::main_window, modal => 1); + local $::main_window = $mainw->{real_window}; + + my $reread_media; + + my ($menu, $_factory) = create_factory_menu( + $mainw->{real_window}, + [ N("/_File"), undef, undef, undef, '' ], + [ N("/_File") . N("/_Update"), N("U"), sub { update_callback() and $reread_media->() }, undef, '', ], + [ N("/_File") . N("/Add a specific _media mirror"), N("M"), sub { easy_add_callback_with_mirror() and $reread_media->() }, undef, '' ], + [ N("/_File") . N("/_Add a custom medium"), N("A"), sub { add_callback() and $reread_media->() }, undef, '' ], + [ N("/_File") . N("/Close"), N("W"), sub { Gtk2->main_quit }, undef, '', ], + [ N("/_Options"), undef, undef, undef, '' ], + [ N("/_Options") . N("/_Global options"), N("G"), \&options_callback, undef, '' ], + [ N("/_Options") . N("/Manage _keys"), N("K"), \&keys_callback, undef, '' ], + [ N("/_Options") . N("/_Parallel"), N("P"), \¶llel_callback, undef, '' ], + [ N("/_Options") . N("/P_roxy"), N("R"), \&proxy_callback, undef, '' ], + if_($0 =~ /edit-urpm-sources/, + [ N("/_Help"), undef, undef, undef, '' ], + [ N("/_Help") . N("/_Report Bug"), undef, sub { run_drakbug('edit-urpm-sources.pl') }, undef, '' ], + [ N("/_Help") . N("/_Help"), undef, sub { rpmdragora::open_help('sources') }, undef, '' ], + [ N("/_Help") . N("/_About..."), undef, sub { + my $license = formatAlaTeX(translate($::license)); + $license =~ s/\n/\n\n/sg; # nicer formatting + my $w = gtknew('AboutDialog', name => N("Rpmdragora"), + version => $rpmdragora::distro_version, + copyright => N("Copyright (C) %s by Mandriva", '2002-2008'), + license => $license, wrap_license => 1, + comments => N("Rpmdragora is the Mageia package management tool."), + website => 'http://www.mageia.org/', + website_label => N("Mageia"), + authors => 'Thierry Vignaud ', + artists => 'Hรฉlรจne Durosini ', + translator_credits => + #-PO: put here name(s) and email(s) of translator(s) (eg: "John Smith ") + N("_: Translator(s) name(s) & email(s)\n"), + transient_for => $::main_window, modal => 1, position_policy => 'center-on-parent', + ); + $w->show_all; + $w->run; + }, undef, '' + ] + ), + ); + + my $list = Gtk2::ListStore->new("Glib::Boolean", "Glib::Boolean", "Glib::String", "Glib::String", "Glib::Boolean"); + $list_tv = Gtk2::TreeView->new_with_model($list); + $list_tv->get_selection->set_mode('multiple'); + my ($dw_button, $edit_button, $remove_button, $up_button); + $list_tv->get_selection->signal_connect(changed => sub { + my ($selection) = @_; + my @rows = $selection->get_selected_rows; + my $model = $list; + # we can delete several medium at a time: + $remove_button and $remove_button->set_sensitive($#rows != -1); + # we can only edit/move one item at a time: + $_ and $_->set_sensitive(@rows == 1) foreach $up_button, $dw_button, $edit_button; + + # we can only up/down one item if not at begin/end: + return if @rows != 1; + + my $curr_path = $rows[0]; + my $first_path = $model->get_path($model->get_iter_first); + $up_button->set_sensitive($first_path && $first_path->compare($curr_path)); + + $curr_path->next; + my $next_item = $model->get_iter($curr_path); + $dw_button->set_sensitive($next_item); # && !$model->get($next_item, 0) + }); + + $list_tv->set_rules_hint(1); + $list_tv->set_reorderable(1); + + my $reorder_ok = 1; + $list->signal_connect( + row_deleted => sub { + $reorder_ok or return; + my ($model) = @_; + my @media; + $model->foreach( + sub { + my (undef, undef, $iter) = @_; + my $name = $model->get($iter, $col{mainw}{name}); + push @media, urpm::media::name2medium($urpm, $name); + 0; + }, undef); + @{$urpm->{media}} = @media; + }, + ); + + $list_tv->append_column(Gtk2::TreeViewColumn->new_with_attributes(N("Enabled"), + my $tr = Gtk2::CellRendererToggle->new, + 'active' => $col{mainw}{is_enabled})); + $list_tv->append_column(Gtk2::TreeViewColumn->new_with_attributes(N("Updates"), + my $cu = Gtk2::CellRendererToggle->new, + 'active' => $col{mainw}{is_update}, + activatable => $col{mainw}{activatable})); + $list_tv->append_column(Gtk2::TreeViewColumn->new_with_attributes(N("Type"), + Gtk2::CellRendererText->new, + 'text' => $col{mainw}{type})); + $list_tv->append_column(Gtk2::TreeViewColumn->new_with_attributes(N("Medium"), + Gtk2::CellRendererText->new, + 'text' => $col{mainw}{name})); + my $id; + $id = $tr->signal_connect( + toggled => sub { + my (undef, $path) = @_; + $tr->signal_handler_block($id); + my $_guard = before_leaving { $tr->signal_handler_unblock($id) }; + my $iter = $list->get_iter_from_string($path); + $urpm->{media}[$path]{ignore} = !$urpm->{media}[$path]{ignore} || undef; + $list->set($iter, $col{mainw}{is_enabled}, !$urpm->{media}[$path]{ignore}); + urpm::media::write_config($urpm); + my $ignored = $urpm->{media}[$path]{ignore}; + $reread_media->(); + if (!$ignored && $urpm->{media}[$path]{ignore}) { + # reread media failed to un-ignore an ignored medium + # probably because urpm::media::check_existing_medium() complains + # about missing synthesis when the medium never was enabled before; + # thus it restored the ignore bit + $urpm->{media}[$path]{ignore} = !$urpm->{media}[$path]{ignore} || undef; + urpm::media::write_config($urpm); + #- Enabling this media failed, force update + interactive_msg('rpmdragora', + N("This medium needs to be updated to be usable. Update it now?"), + yesno => 1, + ) and $reread_media->($urpm->{media}[$path]{name}); + } + }, + ); + + $cu->signal_connect( + toggled => sub { + my (undef, $path) = @_; + my $iter = $list->get_iter_from_string($path); + $urpm->{media}[$path]{update} = !$urpm->{media}[$path]{update} || undef; + $list->set($iter, $col{mainw}{is_update}, ! !$urpm->{media}[$path]{update}); + $something_changed = 1; + }, + ); + + $reread_media = sub { + my ($name) = @_; + $reorder_ok = 0; + $something_changed = 1; + if (defined $name) { + urpm::media::select_media($urpm, $name); + update_sources_check( + $urpm, + { nolock => 1 }, + 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(); + $list->clear; + foreach (grep { ! $_->{external} } @{$urpm->{media}}) { + my $name = $_->{name}; + $list->append_set($col{mainw}{is_enabled} => !$_->{ignore}, + $col{mainw}{is_update} => ! !$_->{update}, + $col{mainw}{type} => get_medium_type($_), + $col{mainw}{name} => $name, + $col{mainw}{activatable} => to_bool($::expert), + ); + } + $reorder_ok = 1; + }; + $reread_media->(); + $something_changed = 0; + + gtkadd( + $mainw->{window}, + gtkpack_( + gtknew('VBox', spacing => 5), + 0, $menu, + ($0 =~ /rpm-edit-media|edit-urpm-sources/ ? (0, Gtk2::Banner->new($ugtk2::wm_icon, N("Configure media"))) : ()), + 1, gtkpack_( + gtknew('HBox', spacing => 10), + 1, gtknew('ScrolledWindow', child => $list_tv), + 0, gtkpack__( + gtknew('VBox', spacing => 5), + gtksignal_connect( + $remove_button = Gtk2::Button->new(but(N("Remove"))), + clicked => sub { remove_callback() and $reread_media->() }, + ), + gtksignal_connect( + $edit_button = Gtk2::Button->new(but(N("Edit"))), + clicked => sub { + my $name = edit_callback(); defined $name and $reread_media->($name); + } + ), + gtksignal_connect( + Gtk2::Button->new(but(N("Add"))), + clicked => sub { easy_add_callback() and $reread_media->() }, + ), + gtkpack( + gtknew('HBox'), + gtksignal_connect( + $up_button = gtknew('Button', + image => gtknew('Image', stock => 'gtk-go-up')), + clicked => \&upwards_callback), + + gtksignal_connect( + $dw_button = gtknew('Button', + image => gtknew('Image', stock => 'gtk-go-down')), + clicked => \&downwards_callback), + ), + ) + ), + 0, gtknew('HSeparator'), + 0, gtknew('HButtonBox', layout => 'edge', children_loose => [ + gtksignal_connect(Gtk2::Button->new(but(N("Help"))), clicked => sub { rpmdragora::open_help('sources') }), + gtksignal_connect(Gtk2::Button->new(but(N("Ok"))), clicked => sub { Gtk2->main_quit }) + ]) + ) + ); + $_->set_sensitive(0) foreach $dw_button, $edit_button, $remove_button, $up_button; + + $mainw->{rwindow}->set_size_request(600, 400); + $mainw->main; + return $something_changed; +} + + +sub run() { + # ignore rpmdragora's option regarding ignoring debug media: + local $ignore_debug_media = [ 0 ]; + local $ugtk2::wm_icon = get_icon('rpmdragora-mdk', 'title-media'); + my $lock; + { + $urpm = fast_open_urpmi_db(); + my $err_msg = "urpmdb locked\n"; + local $urpm->{fatal} = sub { + interactive_msg('rpmdragora', + N("The Package Database is locked. Please close other applications +working with the Package Database. Do you have another media +manager on another desktop, or are you currently installing +packages as well?")); + die $err_msg; + }; + # lock urpmi DB + eval { $lock = urpm::lock::urpmi_db($urpm, 'exclusive', wait => $urpm->{options}{wait_lock}) }; + if (my $err = $@) { + return if $err eq $err_msg; + die $err; + } + } + + my $res = mainwindow(); + urpm::media::write_config($urpm); + + writeconf(); + + undef $lock; + $res; +} + + +1; diff --git a/lib/AdminPanel/Rpmdragora/formatting.pm b/lib/AdminPanel/Rpmdragora/formatting.pm new file mode 100644 index 00000000..ccbdf0c8 --- /dev/null +++ b/lib/AdminPanel/Rpmdragora/formatting.pm @@ -0,0 +1,192 @@ +# vim: set et ts=4 sw=4: +package AdminPanel::Rpmdragora::formatting; +#***************************************************************************** +# +# Copyright (c) 2002 Guillaume Cottenceau +# Copyright (c) 2002-2006 Thierry Vignaud +# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA +# Copyright (c) 2005, 2006 Mandriva SA +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** +# +# $Id: formatting.pm 261189 2009-10-01 14:44:39Z tv $ + +use strict; +use utf8; +use POSIX qw(strftime); +use AdminPanel::rpmdragora; +use lib qw(/usr/lib/libDrakX); +use MDK::Common::Various; # included for internal_error subroutine +use common; +#use ugtk2 qw(escape_text_for_TextView_markup_format); + +use Exporter; +our @ISA = qw(Exporter); +our @EXPORT = qw( + $spacing + ensure_utf8 + format_changelog_changelogs + format_changelog_string + format_field + format_header + format_list + format_name_n_summary + format_size + format_filesize + format_update_field + my_fullname + pkg2medium + rpm_description + split_fullname + urpm_name + ); + + +sub escape_text_for_TextView_markup_format { + my ($str) = @_; + my %rules = ('&' => '&', + '<' => '<', + '>' => '>', + ); + eval { $str =~ s!([&<>])!$rules{$1}!g }; #^(&(amp|lt|gt);)!!) { + if (my $err = $@) { + internal_error("$err\n$str"); + } + $str; +} + +# from rpmtools, #37482: +sub ensure_utf8 { + if (utf8::is_utf8($_[0])) { + utf8::valid($_[0]) and return; + + utf8::encode($_[0]); #- disable utf8 flag + utf8::upgrade($_[0]); + } else { + utf8::decode($_[0]); #- try to set utf8 flag + utf8::valid($_[0]) and return; + warn "do not know what to with $_[0]\n"; + } +} + +sub rpm_description { + my ($description) = @_; + ensure_utf8($description); + my ($t, $tmp); + foreach (split "\n", $description) { + s/^\s*//; + if (/^$/ || /^\s*(-|\*|\+|o)\s/) { + $t || $tmp and $t .= "$tmp\n"; + $tmp = $_; + } else { + $tmp = ($tmp ? "$tmp " : ($t && "\n") . $tmp) . $_; + } + } + "$t$tmp\n"; +} + +sub split_fullname { $_[0] =~ /^(.*)-([^-]+)-([^-]+)\.([^.-]+)$/ } + +sub my_fullname { + return '?-?-?' unless ref $_[0]; + my ($name, $version, $release) = $_[0]->fullname; + "$name-$version-$release"; +} + +sub urpm_name { + return '?-?-?.?' unless ref $_[0]; + scalar $_[0]->fullname; +} + +sub pkg2medium { + my ($p, $urpm) = @_; + return if !ref $p; + return { name => N("None (installed)") } if !defined($p->id); # if installed + URPM::pkg2media($urpm->{media}, $p) || { name => N("Unknown"), fake => 1 }; +} + +# [ duplicate urpmi's urpm::msg::localtime2changelog() ] +#- strftime returns a string in the locale charset encoding; +#- but gtk2 requires UTF-8, so we use to_utf8() to ensure the +#- output of localtime2changelog() is always in UTF-8 +#- as to_utf8() uses LC_CTYPE for locale encoding and strftime() uses LC_TIME, +#- it doesn't work if those two variables have values with different +#- encodings; but if a user has a so broken setup we can't do much anyway +sub localtime2changelog { to_utf8(POSIX::strftime("%c", localtime($_[0]))) } + +our $spacing = " "; +sub format_changelog_string { + my ($installed_version, $string) = @_; + #- preprocess changelog for faster TextView insert reaction + require Gtk2::Pango; + my %date_attr = ('weight' => Gtk2::Pango->PANGO_WEIGHT_BOLD); + my %update_attr = ('style' => 'italic'); + my $version; + my $highlight; + [ map { + my %attrs; + if (/^\*/) { + add2hash(\%attrs, \%date_attr); + ($version) = /(\S*-\S*)\s*$/; + $highlight = $installed_version ne N("(none)") && 0 < URPM::rpmvercmp($version, $installed_version); + } + add2hash(\%attrs, \%update_attr) if $highlight; + [ "$spacing$_\n", if_(%attrs, \%attrs) ]; + } split("\n", $string) ]; +} + +sub format_changelog_changelogs { + my ($installed_version, @changelogs) = @_; + format_changelog_string($installed_version, join("\n", map { + "* " . localtime2changelog($_->{time}) . " $_->{name}\n\n$_->{text}\n"; + } @changelogs)); +} + +sub format_update_field { + my ($name) = @_; + '' . eval { escape_text_for_TextView_markup_format($name) } . ''; +} + +sub format_name_n_summary { + my ($name, $summary) = @_; + join("\n", '' . $name . '', escape_text_for_TextView_markup_format($summary)); +} + +sub format_header { + my ($str) = @_; + '' . escape_text_for_TextView_markup_format($str) . ''; +} + +sub format_field { + my ($str) = @_; + '' . escape_text_for_TextView_markup_format($str) . ''; +} + +sub format_size { + my ($size) = @_; + $size >= 0 ? + N("%s of additional disk space will be used.", formatXiB($size)) : + N("%s of disk space will be freed.", formatXiB(-$size)); +} + +sub format_filesize { + my ($filesize) = @_; + $filesize ? N("%s of packages will be retrieved.", formatXiB($filesize)) : (); +} + +sub format_list { join("\n", map { s/^(\s)/ $1/mg; "- $_" } sort { uc($a) cmp uc($b) } @_) } + +1; diff --git a/lib/AdminPanel/Rpmdragora/gui.pm b/lib/AdminPanel/Rpmdragora/gui.pm new file mode 100644 index 00000000..66d41fda --- /dev/null +++ b/lib/AdminPanel/Rpmdragora/gui.pm @@ -0,0 +1,1220 @@ +# vim: set et ts=4 sw=4: +package AdminPanel::Rpmdragora::gui; +#***************************************************************************** +# +# Copyright (c) 2002 Guillaume Cottenceau +# Copyright (c) 2002-2007 Thierry Vignaud +# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA +# Copyright (c) 2005-2007 Mandriva SA +# Copyright (c) 2013 Matteo Pasotti +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** +# +# $Id$ + +############################################################ +# WARNING: do not modify before asking matteo or anaselli +############################################################ + +use strict; +our @ISA = qw(Exporter); +use lib qw(/usr/lib/libDrakX); +use common; + +# TO WORKAROUND LOCALIZATION ISSUE +use AdminPanel::Rpmdragora::localization; + +use AdminPanel::rpmdragora; +use AdminPanel::Rpmdragora::open_db; +use AdminPanel::Rpmdragora::formatting; +use AdminPanel::Rpmdragora::init; +use AdminPanel::Rpmdragora::icon; +use AdminPanel::Rpmdragora::pkg; +use AdminPanel::Shared; +use yui; +use feature 'state'; + +our @EXPORT = qw( + $descriptions + $find_entry + $force_displaying_group + $force_rebuild + $pkgs + $results_ok + $results_none + $size_free + $size_selected + $urpm + %grp_columns + %pkg_columns + @filtered_pkgs + @initial_selection + ask_browse_tree_given_widgets_for_rpmdragora + build_tree + callback_choices + compute_main_window_size + do_action + get_info + get_summary + group_has_parent + group_parent + groups_tree + is_locale_available + node_state + pkgs_provider + real_quit + reset_search + set_node_state + sort_callback + switch_pkg_list_mode + toggle_all + toggle_nodes + fast_toggle + ); + +our ($descriptions, %filters, @filtered_pkgs, %filter_methods, $force_displaying_group, $force_rebuild, @initial_selection, $pkgs, $size_free, $size_selected, $urpm); +our ($results_ok, $results_none) = (N("Search results"), N("Search results (none)")); + +our %grp_columns = ( + label => 0, + icon => 2, +); + +our %pkg_columns = ( + text => 0, + state_icon => 1, + state => 2, + selected => 3, + short_name => 4, + version => 5, + release => 6, + 'arch' => 7, + selectable => 8, +); + +sub compute_main_window_size { + my ($w) = @_; + ($typical_width) = string_size($w->{real_window}, translate("Graphical Environment") . "xmms-more-vis-plugins"); + $typical_width > 600 and $typical_width = 600; #- try to not being crazy with a too large value + $typical_width < 150 and $typical_width = 150; +} + +sub get_summary { + my ($key) = @_; + my $summary = translate($pkgs->{$key}{pkg}->summary); + require utf8; + utf8::valid($summary) ? $summary : @{[]}; +} + +sub build_expander { + my ($pkg, $label, $type, $get_data, $o_installed_version) = @_; + my $textview; + gtkadd( + gtkshow(my $exp = gtksignal_connect( + Gtk2::Expander->new(format_field($label)), + activate => sub { + state $first; + return if $first; + $first = 1; + slow_func($::main_window->window, sub { + extract_header($pkg, $urpm, $type, $o_installed_version); + gtktext_insert($textview, $get_data->() || [ [ N("(Not available)") ] ]); + }); + })), + $textview = gtknew('TextView') + ); + $exp->set_use_markup(1); + $exp; +} + + +sub get_advisory_link { + my ($update_descr) = @_; + my $link = gtkshow(Gtk2::LinkButton->new($update_descr->{URL}, N("Security advisory"))); + $link->set_uri_hook(\&run_help_callback); + [ $link ]; +} + +sub get_description { + my ($pkg, $update_descr) = @_; + + join("
", + (eval { + $pkg->{description} || $update_descr->{description}; + } || ''. N("No description").'')); +} + +sub get_string_from_keywords { + my ($medium, $name) = @_; + my @media_types; + if ($medium->{mediacfg}) { + my ($distribconf, $medium_path) = @{$medium->{mediacfg}}; + @media_types = split(':', $distribconf->getvalue($medium_path, 'media_type')) if $distribconf; + } + + my $unsupported = N("It is not supported by Mageia."); + my $dangerous = N("It may break your system."); + my $s; + $s .= N("This package is not free software") . "\n" if member('non-free', @media_types); + if ($pkgs->{$name}{is_backport} || member('backport', @media_types)) { + return join("\n", + N("This package contains a new version that was backported."), + $unsupported, $dangerous, $s); + } elsif (member('testing', @media_types)) { + return join("\n", + N("This package is a potential candidate for an update."), + $unsupported, $dangerous, $s); + } elsif (member('updates', @media_types)) { + return join("\n", + (member('official', @media_types) ? + N("This is an official update which is supported by Mageia.") + : (N("This is an unofficial update."), $unsupported)) + , + $s); + } else { + $s .= N("This is an official package supported by Mageia") . "\n" if member('official', @media_types); + return $s; + } +} + +sub get_main_text { + my ($medium, $fullname, $name, $summary, $is_update, $update_descr) = @_; + + my $txt = get_string_from_keywords($medium, $fullname); + + join("
", + format_header(join(' - ', $name, $summary)) . + if_($txt, format_field(N("Notice: ")) . $txt), + if_($is_update, # is it an update? + format_field(N("Importance: ")) . format_update_field($update_descr->{importance}), + format_field(N("Reason for update: ")) . format_update_field(rpm_description($update_descr->{pre})), + ), + '' # extra empty line + ); +} + +sub get_details { + my ($pkg, $upkg, $installed_version, $raw_medium) = @_; + my @details = (); + push @details, format_field(N("Version: ")) . $upkg->EVR; + push @details, format_field(N("Currently installed version: ")) . $installed_version if($upkg->flag_installed); + push @details, format_field(N("Group: ")) . translate_group($upkg->group); + push @details, format_field(N("Architecture: ")) . $upkg->arch; + push @details, format_field(N("Size: ")) . N("%s KB", int($upkg->size/1024)); + push @details, eval { format_field(N("Medium: ")) . $raw_medium->{name} }; + + my @link = get_url_link($upkg, $pkg); + push @details, join("
   ",@link) if(@link); + unshift @details, "
   "; + join("
   ", @details); +} + +sub get_new_deps { + my ($urpm, $upkg) = @_; + my $deps_textview; + my @a = [ gtkadd( + gtksignal_connect( + gtkshow(my $dependencies = Gtk2::Expander->new(format_field(N("New dependencies:")))), + activate => sub { + slow_func($::main_window->window, sub { + my $state = {}; + my $db = open_rpm_db(); + my @requested = $urpm->resolve_requested__no_suggests_( + $db, $state, + { $upkg->id => 1 }, + ); + @requested = $urpm->resolve_requested_suggests($db, $state, \@requested); + undef $db; + my @nodes_with_deps = map { urpm_name($_) } @requested; + my @deps = sort { $a cmp $b } difference2(\@nodes_with_deps, [ urpm_name($upkg) ]); + @deps = N("All dependencies installed.") if !@deps; + gtktext_insert($deps_textview, join("\n", @deps)); + }); + } + ), + $deps_textview = gtknew('TextView') + ) ]; + $dependencies->set_use_markup(1); + @a; +} + +sub get_url_link { + my ($upkg, $pkg) = @_; + + my $url = $upkg->url || $pkg->{url}; + + if (!$url) { + open_rpm_db()->traverse_tag_find('name', $upkg->name, sub { $url = $_[0]->url }); + } + + return if !$url; + + my @a; + push @a, format_field(N("URL: "))."${spacing}$url"; + @a; +} + +sub files_format { + my ($files) = @_; + ugtk2::markup_to_TextView_format( + '' . $spacing #- to highlight information + . join("\n$spacing", map { "\x{200e}$_" } @$files) + . ''); +} + +sub format_pkg_simplifiedinfo { + my ($pkgs, $key, $urpm, $descriptions) = @_; + my ($name) = split_fullname($key); + my $pkg = $pkgs->{$key}; + my $upkg = $pkg->{pkg}; + return if !$upkg; + my $raw_medium = pkg2medium($upkg, $urpm); + my $medium = !$raw_medium->{fake} ? $raw_medium->{name} : undef; + my $update_descr = $descriptions->{$medium}{$name}; + # discard update fields if not matching: + my $is_update = ($upkg->flag_upgrade && $update_descr && $update_descr->{pre}); + my $summary = get_summary($key); + my $dummy_string = get_main_text($raw_medium, $key, $name, $summary, $is_update, $update_descr); + my $s; + push @$s, $dummy_string; + push @$s, get_advisory_link($update_descr) if $is_update; + + push @$s, get_description($pkg, $update_descr); + push @$s, [ "\n" ]; + my $installed_version = eval { find_installed_version($upkg) }; + + #push @$s, [ gtkadd(gtkshow(my $details_exp = Gtk2::Expander->new(format_field(N("Details:")))), + # gtknew('TextView', text => get_details($pkg, $upkg, $installed_version, $raw_medium))) ]; + push @$s, join("\n", format_field(N("Details:"))."\n".get_details($pkg, $upkg, $installed_version, $raw_medium)); + #$details_exp->set_use_markup(1); + push @$s, [ "\n\n" ]; + #push @$s, [ build_expander($pkg, N("Files:"), 'files', sub { files_format($pkg->{files}) }) ]; + push @$s, [ "\n\n" ]; + #push @$s, [ build_expander($pkg, N("Changelog:"), 'changelog', sub { $pkg->{changelog} }, $installed_version) ]; + + push @$s, [ "\n\n" ]; + if ($upkg->id) { # If not installed + # push @$s, get_new_deps($urpm, $upkg); + } + $s; +} + +sub format_pkg_info { + my ($pkgs, $key, $urpm, $descriptions) = @_; + my $pkg = $pkgs->{$key}; + my $upkg = $pkg->{pkg}; + my ($name, $version) = split_fullname($key); + my @files = ( + format_field(N("Files:\n")), + exists $pkg->{files} + ? '' . join("\n", map { "\x{200e}$_" } @{$pkg->{files}}) . '' #- to highlight information + : N("(Not available)"), + ); + my @chglo = (format_field(N("Changelog:\n")), ($pkg->{changelog} ? @{$pkg->{changelog}} : N("(Not available)"))); + my @source_info = ( + $MODE eq 'remove' || !@$max_info_in_descr + ? () + : ( + format_field(N("Medium: ")) . pkg2medium($upkg, $urpm)->{name}, + format_field(N("Currently installed version: ")) . find_installed_version($upkg), + ) + ); + my @max_info = @$max_info_in_descr && $changelog_first ? (@chglo, @files) : (@files, '', @chglo); + ugtk2::markup_to_TextView_format(join("\n", format_field(N("Name: ")) . $name, + format_field(N("Version: ")) . $version, + format_field(N("Architecture: ")) . $upkg->arch, + format_field(N("Size: ")) . N("%s KB", int($upkg->size/1024)), + if_( + $MODE eq 'update', + format_field(N("Importance: ")) . $descriptions->{$name}{importance} + ), + @source_info, + '', # extra empty line + format_field(N("Summary: ")) . $upkg->summary, + '', # extra empty line + if_( + $MODE eq 'update', + format_field(N("Reason for update: ")) . rpm_description($descriptions->{$name}{pre}), + ), + format_field(N("Description: ")), ($pkg->{description} || $descriptions->{$name}{description} || N("No description")), + @max_info, + )); +} + +sub warn_if_no_pkg { + my ($name) = @_; + my ($short_name) = split_fullname($name); + state $warned; + if (!$warned) { + $warned = 1; + interactive_msg(N("Warning"), + join("\n", + N("The package \"%s\" was found.", $name), + N("However this package is not in the package list."), + N("You may want to update your urpmi database."), + '', + N("Matching packages:"), + '', + join("\n", sort map { + #-PO: this is list fomatting: "- (medium: )" + #-PO: eg: "- rpmdragora (medium: "Main Release" + N("- %s (medium: %s)", $_, pkg2medium($pkgs->{$_}{pkg}, $urpm)->{name}); + } grep { /^$short_name/ } keys %$pkgs), + ), + scroll => 1, + ); + } + return 'XXX'; +} + +sub node_state { + my ($name) = @_; + #- checks $_[0] -> hack for partial tree displaying + return 'XXX' if !$name; + my $pkg = $pkgs->{$name}; + my $urpm_obj = $pkg->{pkg}; + return warn_if_no_pkg($name) if !$urpm_obj; + $pkg->{selected} ? + ($urpm_obj->flag_installed ? + ($urpm_obj->flag_upgrade ? 'to_install' : 'to_remove') + : 'to_install') + : ($urpm_obj->flag_installed ? + ($pkgs->{$name}{is_backport} ? 'backport' : + ($urpm_obj->flag_upgrade ? 'to_update' + : ($urpm_obj->flag_base ? 'base' : 'installed'))) + : 'uninstalled'); +} + +my ($common, $w, %wtree, %ptree, %pix, @table_item_list); + +sub set_node_state { + my ($tblItem, $state, $detail_list) = @_; + return if $state eq 'XXX' || !$state; + $detail_list->parent()->parent()->startMultipleChanges(); + $tblItem->addCell($state,"/usr/share/rpmdrake/icons/state_$state.png") if(ref $tblItem eq "yui::YCBTableItem"); + if(to_bool(member($state, qw(base installed to_install)))){ + # it should be parent()->setChecked(1) + $detail_list->checkItem($tblItem, 1); + # $tblItem->setSelected(1); + }else{ + $detail_list->checkItem($tblItem, 0); + # $tblItem->setSelected(0); + } + if(!to_bool($state ne 'base')){ + #$iter->cell(0)->setLabel('-'); + $tblItem->cell(0)->setLabel('-'); + } + $detail_list->parent()->parent()->doneMultipleChanges(); +} + +sub set_leaf_state { + my ($leaf, $state, $detail_list) = @_; + # %ptree is a hash using the pkg name as key and a monodimensional array (?) as value + # were it is stored the index of the item into the table + my $nodeIndex = $ptree{$leaf}[0]; + my $node = itemAt($detail_list,$nodeIndex); + set_node_state($node, $state, $detail_list); +} + +sub grep_unselected { + my @l = shift(); + my @result = grep { exists $pkgs->{$_} && !$pkgs->{$_}{selected} } @l ; + return @result; +} + +my %groups_tree = (); + +sub add_parent { + my ($tree, $root, $state) = @_; + $tree or return undef; + #$root or return undef; + my $parent = 0; + my @items = split('\|', $root); + my $i = 0; + for my $item (@items) { + chomp $item; + $item = trim($item); + my $treeItem; + if($i == 0){ + $parent = $item; + $treeItem = new yui::YTreeItem($item,get_icon_path($item,0),0); + if(!defined($groups_tree{$parent})) { + $groups_tree{$parent}{parent} = $treeItem; + $groups_tree{$parent}{children} = (); + $tree->addItem($groups_tree{$parent}{'parent'}); + } + }else{ + #if(any { $_ ne $item } @{$groups_tree{$parent}{'children'}}){ + # push @{$groups_tree{$parent}{'children'}}, $item; + #} + if(!defined($groups_tree{$parent}{'children'}{$item})){ + $treeItem = new yui::YTreeItem($item,get_icon_path($item,$parent),0); + $groups_tree{$parent}{'children'}{$item} = $treeItem; + $groups_tree{$parent}{'parent'}->addChild($treeItem); + } + } + $i++; + } + $tree->rebuildTree(); +} + +sub add_node { + my ($leaf, $root, $o_options) = @_; + my $state = node_state($leaf) or return; + if ($leaf) { + my $iter; + if (is_a_package($leaf)) { + my ($name, $version, $release, $arch) = split_fullname($leaf); + #OLD $iter = $w->{detail_list_model}->append_set([ $pkg_columns{text} => $leaf, + # $pkg_columns{short_name} => format_name_n_summary($name, get_summary($leaf)), + # $pkg_columns{version} => $version, + # $pkg_columns{release} => $release, + # $pkg_columns{arch} => $arch, + # ]); + $name = "" if(!defined($name)); + $version = "" if(!defined($version)); + $release = "" if(!defined($release)); + $arch = "" if(!defined($arch)); + #my $newTableItem = new yui::YTableItem(format_name_n_summary($name, get_summary($leaf)), + my $newTableItem = new yui::YCBTableItem($name."\n".get_summary($leaf), + $version, + $release, + $arch); + $w->{detail_list}->addItem($newTableItem); + set_node_state($newTableItem, $state, $w->{detail_list}); + # $ptree{$leaf} = [ $newTableItem->label() ]; + $ptree{$leaf} = [ $newTableItem->index() ]; + $table_item_list[$newTableItem->index()] = $leaf; + $newTableItem->DISOWN(); + } else { + $iter = $w->{tree_model}->append_set(add_parent($w->{tree},$root, $state), [ $grp_columns{label} => $leaf ]); + #push @{$wtree{$leaf}}, $iter; + } + } else { + my $parent = add_parent($w->{tree}, $root, $state); + #- hackery for partial displaying of trees, used in rpmdragora: + #- if leaf is void, we may create the parent and one child (to have the [+] in front of the parent in the ctree) + #- though we use '' as the label of the child; then rpmdragora will connect on tree_expand, and whenever + #- the first child has '' as the label, it will remove the child and add all the "right" children + $o_options->{nochild} or $w->{tree_model}->append_set($parent, [ $grp_columns{label} => '' ]); # test $leaf? + } +} + +my ($prev_label); +sub update_size { + my ($common) = shift @_; + if ($w->{status}) { + my $new_label = $common->{get_status}(); + $prev_label="" if(!defined($prev_label)); + $prev_label ne $new_label and $w->{status}->setText($prev_label = $new_label); + } +} + +sub treeview_children { + my($tbl) = @_; + my $it; + my @l; + my $i=0; + # using iterators + for ($it = $tbl->itemsBegin(); $it != $tbl->itemsEnd(); ) { + my $item = $tbl->YItemIteratorToYItem($it); + push @l, $item; + $it = $tbl->nextItem($it); + $i++; + if ($i == $tbl->itemsCount()) { + last; + } + } + # using items + #for($i=0;$i<$tbl->itemsCount();$i++) { + # print " item label " . $tbl->item($i)->cell(0)->label() . "\n"; + # push @l, $tbl->item($i); + #} + return @l; +} + +sub children { + my ($w, @table_item_list) = @_; + # map { $w->{detail_list}->get($_, $pkg_columns{text}) } treeview_children($w->{detail_list}); + # map { $table_item_list[$_->index()] } treeview_children($w->{detail_list}); + my @children = treeview_children($w->{detail_list}); + my @result; + for my $child(@children){ + push @result, $table_item_list[$child->index()]; + } + return @result; +} + +sub itemAt { + my ($table, $index) = @_; + return $table->item($index); + #return bless ($table->item($index),'yui::YTableItem'); + #foreach my $item(treeview_children($table)){ + # if($item->index() == $index){ + # print "\n== item label ".$item->label()."\n"; + # return bless ($item, 'yui::YTableItem'); + # } + #} +} + +sub toggle_all { + my ($common, $_val) = @_; + my $w = $common->{widgets}; + my @l = children($w, $common->{table_item_list}) or return; + + my @unsel = grep_unselected(@l); + my @p = @unsel ? + #- not all is selected, select all if no option to potentially override + (exists $common->{partialsel_unsel} && $common->{partialsel_unsel}->(\@unsel, \@l) ? difference2(\@l, \@unsel) : @unsel) + : @l; + # toggle_nodes($w->{detail_list}, $w->{detail_list_model}, \&set_leaf_state, node_state($p[0]), @p); + toggle_nodes($w->{detail_list}, $w->{detail_list}, \&set_leaf_state, node_state($p[0][0]), @{$p[0]}); + update_size($common); +} + +sub fast_toggle { + my ($item) = @_; + #gtkset_mousecursor_wait($w->{w}{rwindow}->window); + #my $_cleaner = before_leaving { gtkset_mousecursor_normal($w->{w}{rwindow}->window) }; + my $name = $common->{table_item_list}[$item->index()]; + my $urpm_obj = $pkgs->{$name}{pkg}; + if ($urpm_obj->flag_base) { + interactive_msg(N("Warning"), N("Removing package %s would break your system", $name)); + return ''; + } + if ($urpm_obj->flag_skip) { + interactive_msg(N("Warning"), N("The \"%s\" package is in urpmi skip list.\nDo you want to select it anyway?", $name), yesno => 1) or return ''; + $urpm_obj->set_flag_skip(0); + } + if ($Rpmdragora::pkg::need_restart && !$priority_up_alread_warned) { + $priority_up_alread_warned = 1; + interactive_msg(N("Warning"), '' . N("Rpmdragora or one of its priority dependencies needs to be updated first. Rpmdragora will then restart.") . '' . "\n\n"); + } + # toggle_nodes($w->{tree}->window, $w->{detail_list_model}, \&set_leaf_state, $w->{detail_list_model}->get($iter, $pkg_columns{state}), + my $state; +#pasmatt checked should be to install no? + if($item->checked()){ + $state = "to_install"; + }else{ + $state = "to_remove"; + } + toggle_nodes($w->{tree}, $w->{detail_list}, \&set_leaf_state, $state, $name); + update_size($common); +}; + +# ask_browse_tree_given_widgets_for_rpmdragora will run gtk+ loop. its main parameter "common" is a hash containing: +# - a "widgets" subhash which holds: +# o a "w" reference on a ugtk2 object +# o "tree" & "info" references a TreeView +# o "info" is a TextView +# o "tree_model" is the associated model of "tree" +# o "status" references a Label +# - some methods: get_info, node_state, build_tree, partialsel_unsel, grep_unselected, rebuild_tree, toggle_nodes, get_status +# - "tree_submode": the default mode (by group, ...), ... +# - "state": a hash of misc flags: => { flat => '0' }, +# o "flat": is the tree flat or not +# - "tree_mode": mode of the tree ("gui_pkgs", "by_group", ...) (mainly used by rpmdragora) + +sub ask_browse_tree_given_widgets_for_rpmdragora { + ($common) = @_; + $w = $common->{widgets}; + + $common->{table_item_list} = \@table_item_list; + + $w->{detail_list} ||= $w->{tree}; + #$w->{detail_list_model} ||= $w->{tree_model}; + + $common->{add_parent} = \&add_parent; + my $clear_all_caches = sub { + %ptree = %wtree = (); + @table_item_list = (); + }; + $common->{clear_all_caches} = $clear_all_caches; + $common->{delete_all} = sub { + $clear_all_caches->(); + $w->{detail_list}->deleteAllItems() if($w->{detail_list}->hasItems()); + $w->{tree}->deleteAllItems() if($w->{tree}->hasItems()); + %groups_tree = (); + }; + $common->{rebuild_tree} = sub { + $common->{delete_all}->(); + $common->{build_tree}($common->{state}{flat}, $common->{tree_mode}); + update_size($common); + }; + $common->{delete_category} = sub { + my ($cat) = @_; + exists $wtree{$cat} or return; + %ptree = (); + + if (exists $wtree{$cat}) { + my $_iter_str = $w->{tree_model}->get_path_str($wtree{$cat}); + $w->{tree_model}->remove($wtree{$cat}); + delete $wtree{$cat}; + } + update_size($common); + }; + $common->{add_nodes} = sub { + my (@nodes) = @_; + $w->{detail_list}->deleteAllItems(); + #$w->{detail_list}->scroll_to_point(0, 0); + foreach(@nodes){ + add_node($_->[0], $_->[1], $_->[2]); + } + update_size($common); + }; + + $common->{display_info} = sub { + gtktext_insert($w->{info}, get_info($_[0], $w->{tree}->window)); + $w->{info}->scroll_to_iter($w->{info}->get_buffer->get_start_iter, 0, 0, 0, 0); + 0; + }; + + my $fast_toggle = sub { + my ($item) = @_; + #gtkset_mousecursor_wait($w->{w}{rwindow}->window); + #my $_cleaner = before_leaving { gtkset_mousecursor_normal($w->{w}{rwindow}->window) }; + my $name = $common->{table_item_list}[$item->index()]; + my $urpm_obj = $pkgs->{$name}{pkg}; + + if ($urpm_obj->flag_base) { + interactive_msg(N("Warning"), + N("Removing package %s would break your system", $name)); + return ''; + } + + if ($urpm_obj->flag_skip) { + interactive_msg(N("Warning"), N("The \"%s\" package is in urpmi skip list.\nDo you want to select it anyway?", $name), yesno => 1) or return ''; + $urpm_obj->set_flag_skip(0); + } + + if ($Rpmdragora::pkg::need_restart && !$priority_up_alread_warned) { + $priority_up_alread_warned = 1; + interactive_msg(N("Warning"), '' . N("Rpmdragora or one of its priority dependencies needs to be updated first. Rpmdragora will then restart.") . '' . "\n\n"); + } + + # toggle_nodes($w->{tree}->window, $w->{detail_list_model}, \&set_leaf_state, $w->{detail_list_model}->get($iter, $pkg_columns{state}), + toggle_nodes($w->{tree}->window, $w->{detail_list_model}, \&set_leaf_state, $item->selected, $common->{table_item_list}[$item->index()]); + update_size($common); + }; + #$w->{detail_list}->get_selection->signal_connect(changed => sub { + #my ($model, $iter) = $_[0]->get_selected; + #$model && $iter or return; + # $common->{display_info}($model->get($iter, $pkg_columns{text})); + #}); + # WARNING: รจ interessante! + #($w->{detail_list}->get_column(0)->get_cell_renderers)[0]->signal_connect(toggled => sub { + # my ($_cell, $path) = @_; #text_ + # my $iter = $w->{detail_list_model}->get_iter_from_string($path); + # $fast_toggle->($iter) if $iter; + # 1; + #}); + $common->{rebuild_tree}->(); + update_size($common); + $common->{initial_selection} and toggle_nodes($w->{tree}->window, $w->{detail_list}, \&set_leaf_state, undef, @{$common->{initial_selection}}); + my $_b = before_leaving { $clear_all_caches->() }; + $common->{init_callback}->() if $common->{init_callback}; + #OLD $w->{w}->main; + $w->{w}; +} + +our $find_entry; + +sub reset_search() { + return if !$common; + $common->{delete_category}->($_) foreach $results_ok, $results_none; + # clear package list: + $common->{add_nodes}->(); +} + +sub is_a_package { + my ($pkg) = @_; + return exists $pkgs->{$pkg}; +} + +sub switch_pkg_list_mode { + my ($mode) = @_; + return if !$mode; + return if !$filter_methods{$mode}; + $force_displaying_group = 1; + $filter_methods{$mode}->(); +} + +sub is_updatable { + my $p = $pkgs->{$_[0]}; + $p->{pkg} && !$p->{selected} && $p->{pkg}->flag_installed && $p->{pkg}->flag_upgrade; +} + +sub pkgs_provider { + my ($mode, %options) = @_; + return if !$mode; + my $h = &get_pkgs(%options); + ($urpm, $descriptions) = @$h{qw(urpm update_descr)}; + $pkgs = $h->{all_pkgs}; + %filters = ( + non_installed => $h->{installable}, + installed => $h->{installed}, + all => [ keys %$pkgs ], + ); + my %tmp_filter_methods = ( + all => sub { + [ difference2([ keys %$pkgs ], $h->{inactive_backports}) ]; + }, + all_updates => sub { + # potential "updates" from media not tagged as updates: + if (!$options{pure_updates} && !$Rpmdragora::pkg::need_restart) { + [ @{$h->{updates}}, + difference2([ grep { is_updatable($_) } @{$h->{installable}} ], $h->{backports}) ]; + } else { + [ difference2($h->{updates}, $h->{inactive_backports}) ]; + } + }, + backports => sub { $h->{backports} }, + meta_pkgs => sub { + [ difference2($h->{meta_pkgs}, $h->{inactive_backports}) ]; + }, + gui_pkgs => sub { + [ difference2($h->{gui_pkgs}, $h->{inactive_backports}) ]; + }, + ); + foreach my $importance (qw(bugfix security normal)) { + $tmp_filter_methods{$importance} = sub { + my @media = keys %$descriptions; + [ grep { + my ($name) = split_fullname($_); + my $medium = find { $descriptions->{$_}{$name} } @media; + $medium && $descriptions->{$medium}{$name}{importance} eq $importance } @{$h->{updates}} ]; + }; + } + + undef %filter_methods; + foreach my $type (keys %tmp_filter_methods) { + $filter_methods{$type} = sub { + $force_rebuild = 1; # force rebuilding tree since we changed filter (FIXME: switch to SortModel) + @filtered_pkgs = intersection($filters{$filter->[0]}, $tmp_filter_methods{$type}->()); + }; + } + + switch_pkg_list_mode($mode); +} + +sub closure_removal { + local $urpm->{state} = {}; + urpm::select::find_packages_to_remove($urpm, $urpm->{state}, \@_); +} + +sub is_locale_available { + my ($name) = @_; + any { $urpm->{depslist}[$_]->flag_selected } keys %{$urpm->{provides}{$name} || {}} and return 1; + my $found; + open_rpm_db()->traverse_tag_find('name', $name, sub { $found = 1 }); + return $found; +} + +sub callback_choices { + my (undef, undef, undef, $choices) = @_; + return $choices->[0] if $::rpmdragora_options{auto}; + foreach my $pkg (@$choices) { + foreach ($pkg->requires_nosense) { + /locales-/ or next; + is_locale_available($_) and return $pkg; + } + } + my $callback = sub { interactive_msg(N("More information on package..."), get_info($_[0]), scroll => 1) }; + $choices = [ sort { $a->name cmp $b->name } @$choices ]; + my @choices = interactive_list_(N("Please choose"), (scalar(@$choices) == 1 ? + N("The following package is needed:") : N("One of the following packages is needed:")), + [ map { urpm_name($_) } @$choices ], $callback, nocancel => 1); + defined $choices[0] ? $choices->[$choices[0]] : undef; +} + +sub deps_msg { + return 1 if $dont_show_selections->[0]; + my ($title, $msg, $nodes, $nodes_with_deps) = @_; + my @deps = sort { $a cmp $b } difference2($nodes_with_deps, $nodes); + @deps > 0 or return 1; + deps_msg_again: + my $results = interactive_msg( + $title, $msg . + format_list(map { scalar(urpm::select::translate_why_removed_one($urpm, $urpm->{state}, $_)) } @deps) + . "\n\n" . format_size($urpm->selected_size($urpm->{state})), + yesno => [ N("Cancel"), N("More info"), N("Ok") ], + scroll => 1, + ); + if ($results eq + #-PO: Keep it short, this is gonna be on a button + N("More info")) { + interactive_packtable( + N("Information on packages"), + $::main_window, + undef, + [ map { my $pkg = $_; + [ gtknew('HBox', children_tight => [ gtkset_selectable(gtknew('Label', text => $pkg), 1) ]), + gtknew('Button', text => N("More information on package..."), + clicked => sub { + interactive_msg(N("More information on package..."), get_info($pkg), scroll => 1); + }) ] } @deps ], + [ gtknew('Button', text => N("Ok"), + clicked => sub { Gtk2->main_quit }) ] + ); + goto deps_msg_again; + } else { + return $results eq N("Ok"); + } +} + +sub toggle_nodes { + my ($widget, $detail_list, $set_state, $old_state, @nodes) = @_; + @nodes = grep { exists $pkgs->{$_} } @nodes + or return; + #- avoid selecting too many packages at once + return if !$dont_show_selections->[0] && @nodes > 2000; + my $new_state = !$pkgs->{$nodes[0]}{selected}; + + my @nodes_with_deps; + + my $bar_id = statusbar_msg(N("Checking dependencies of package..."), 0); + + my $warn_about_additional_packages_to_remove = sub { + my ($msg) = @_; + statusbar_msg_remove($bar_id); + deps_msg(N("Some additional packages need to be removed"), + formatAlaTeX($msg) . "\n\n", + \@nodes, \@nodes_with_deps) or @nodes_with_deps = (); + }; + + if (member($old_state, qw(to_remove installed))) { # remove pacckages + if ($new_state) { + my @remove; + slow_func($widget, sub { @remove = closure_removal(@nodes) }); + @nodes_with_deps = grep { !$pkgs->{$_}{selected} && !/^basesystem/ } @remove; + $warn_about_additional_packages_to_remove->( + N("Because of their dependencies, the following package(s) also need to be removed:")); + my @impossible_to_remove; + foreach (grep { exists $pkgs->{$_}{base} } @remove) { + ${$pkgs->{$_}{base}} == 1 ? push @impossible_to_remove, $_ : ${$pkgs->{$_}{base}}--; + } + @impossible_to_remove and interactive_msg(N("Some packages cannot be removed"), + N("Removing these packages would break your system, sorry:\n\n") . + format_list(@impossible_to_remove)); + @nodes_with_deps = difference2(\@nodes_with_deps, \@impossible_to_remove); + } else { + @nodes_with_deps = grep { intersection(\@nodes, [ closure_removal($_) ]) } + grep { $pkgs->{$_}{selected} && !member($_, @nodes) } keys %$pkgs; + push @nodes_with_deps, @nodes; + $warn_about_additional_packages_to_remove->( + N("Because of their dependencies, the following package(s) must be unselected now:\n\n")); + $pkgs->{$_}{base} && ${$pkgs->{$_}{base}}++ foreach @nodes_with_deps; + } + } else { + if ($new_state) { + if (@nodes > 1) { + #- unselect i18n packages of which locales is not already present (happens when user clicks on KDE group) + my @bad_i18n_pkgs; + foreach my $sel (@nodes) { + foreach ($pkgs->{$sel}{pkg}->requires_nosense) { + /locales-([^-]+)/ or next; + $sel =~ /-$1[-_]/ && !is_locale_available($_) and push @bad_i18n_pkgs, $sel; + } + } + @nodes = difference2(\@nodes, \@bad_i18n_pkgs); + } + my @requested; + @requested = $urpm->resolve_requested( + open_rpm_db(), $urpm->{state}, + { map { $pkgs->{$_}{pkg}->id => 1 } @nodes }, + callback_choices => \&callback_choices, + ); + @nodes_with_deps = map { urpm_name($_) } @requested; + statusbar_msg_remove($bar_id); + if (!deps_msg(N("Additional packages needed"), + formatAlaTeX(N("To satisfy dependencies, the following package(s) also need to be installed:\n\n")) . "\n\n", + \@nodes, \@nodes_with_deps)) { + @nodes_with_deps = (); + $urpm->disable_selected(open_rpm_db(), $urpm->{state}, @requested); + goto packages_selection_ok; + } + + if (my $conflicting_msg = urpm::select::conflicting_packages_msg($urpm, $urpm->{state})) { + if (!interactive_msg(N("Conflicting Packages"), $conflicting_msg, yesno => 1, scroll => 1)) { + @nodes_with_deps = (); + $urpm->disable_selected(open_rpm_db(), $urpm->{state}, @requested); + goto packages_selection_ok; + } + } + + if (my @cant = sort(difference2(\@nodes, \@nodes_with_deps))) { + my @ask_unselect = urpm::select::unselected_packages($urpm->{state}); + my @reasons = map { + my $cant = $_; + my $unsel = find { $_ eq $cant } @ask_unselect; + $unsel + ? join("\n", urpm::select::translate_why_unselected($urpm, $urpm->{state}, $unsel)) + : ($pkgs->{$_}{pkg}->flag_skip ? N("%s (belongs to the skip list)", $cant) : $cant); + } @cant; + my $count = @reasons; + interactive_msg( + ($count == 1 ? N("One package cannot be installed") : N("Some packages cannot be installed")), + ($count == 1 ? + N("Sorry, the following package cannot be selected:\n\n%s", format_list(@reasons)) + : N("Sorry, the following packages cannot be selected:\n\n%s", format_list(@reasons))), + scroll => 1, + ); + foreach (@cant) { + next unless $pkgs->{$_}{pkg}; + $pkgs->{$_}{pkg}->set_flag_requested(0); + $pkgs->{$_}{pkg}->set_flag_required(0); + } + } + packages_selection_ok: + } else { + my @unrequested; + @unrequested = $urpm->disable_selected(open_rpm_db(), $urpm->{state}, + map { $pkgs->{$_}{pkg} } @nodes); + @nodes_with_deps = map { urpm_name($_) } @unrequested; + statusbar_msg_remove($bar_id); + if (!deps_msg(N("Some packages need to be removed"), + N("Because of their dependencies, the following package(s) must be unselected now:\n\n"), + \@nodes, \@nodes_with_deps)) { + @nodes_with_deps = (); + $urpm->resolve_requested(open_rpm_db(), $urpm->{state}, { map { $_->id => 1 } @unrequested }); + goto packages_unselection_ok; + } + packages_unselection_ok: + } + } + + foreach (@nodes_with_deps) { + #- some deps may exist on some packages which aren't listed because + #- not upgradable (older than what currently installed) + exists $pkgs->{$_} or next; + if (!$pkgs->{$_}{pkg}) { #- can't be removed # FIXME; what about next packages in the loop? + undef $pkgs->{$_}{selected}; + log::explanations("can't be removed: $_"); + } else { + $pkgs->{$_}{selected} = $new_state; + } + # invoke set_leaf_state($pkgname, node_state, ) + # node_state = {to_install, to_remove,...} + $set_state->($_, node_state($_), $detail_list); + if (my $pkg = $pkgs->{$_}{pkg}) { + # FIXME: shouldn't we threat all of them as POSITIVE (as selected size) + $size_selected += $pkg->size * ($pkg->flag_installed && !$pkg->flag_upgrade ? ($new_state ? -1 : 1) : ($new_state ? 1 : -1)); + } + } +} + +sub is_there_selected_packages() { + int(grep { $pkgs->{$_}{selected} } keys %$pkgs); +} + +sub real_quit() { + if (is_there_selected_packages()) { + interactive_msg(N("Some packages are selected."), N("Some packages are selected.") . "\n" . N("Do you really want to quit?"), yesno => 1) or return; + } + Gtk2->main_quit; +} + +sub do_action__real { + my ($options, $callback_action, $o_info) = @_; + require urpm::sys; + if (!urpm::sys::check_fs_writable()) { + $urpm->{fatal}(1, N("Error: %s appears to be mounted read-only.", $urpm::sys::mountpoint)); + return 1; + } + if (!$Rpmdragora::pkg::need_restart && !is_there_selected_packages()) { + interactive_msg(N("You need to select some packages first."), N("You need to select some packages first.")); + return 1; + } + my $size_added = sum(map { if_($_->flag_selected && !$_->flag_installed, $_->size) } @{$urpm->{depslist}}); + if ($MODE eq 'install' && $size_free - $size_added/1024 < 50*1024) { + interactive_msg(N("Too many packages are selected"), + N("Warning: it seems that you are attempting to add so many +packages that your filesystem may run out of free diskspace, +during or after package installation ; this is particularly +dangerous and should be considered with care. + +Do you really want to install all the selected packages?"), yesno => 1) + or return 1; + } + my $res = $callback_action->($urpm, $pkgs); + if (!$res) { + $force_rebuild = 1; + pkgs_provider($options->{tree_mode}, if_($Rpmdragora::pkg::probe_only_for_updates, pure_updates => 1), skip_updating_mu => 1); + reset_search(); + $size_selected = 0; + (undef, $size_free) = MDK::Common::System::df('/usr'); + $options->{rebuild_tree}->() if $options->{rebuild_tree}; + gtktext_insert($o_info, '') if $o_info; + } + $res; +} + +sub do_action { + my ($options, $callback_action, $o_info) = @_; + my $res = eval { do_action__real($options, $callback_action, $o_info) }; + my $err = $@; + # FIXME: offer to report the problem into bugzilla: + if ($err && $err !~ /cancel_perform/) { + interactive_msg(N("Fatal error"), + N("A fatal error occurred: %s.", $err)); + } + $res; +} + +sub translate_group { + join('/', map { translate($_) } split m|/|, $_[0]); +} + +sub ctreefy { + join('|', map { translate($_) } split m|/|, $_[0]); +} + +sub _build_tree { + my ($tree, $elems, @elems) = @_; + #- we populate all the groups tree at first + %$elems = (); + # better loop on packages, create groups tree and push packages in the proper place: + foreach my $pkg (@elems) { + my $grp = $pkg->[1]; + # no state for groups (they're not packages and thus have no state) + add_parent($tree, $grp, undef); + $elems->{$grp} ||= []; + push @{$elems->{$grp}}, $pkg; + } +} + + +sub build_tree { + my ($tree, $tree_model, $elems, $options, $force_rebuild, $flat, $mode) = @_; + state $old_mode; + $mode = $options->{rmodes}{$mode} || $mode; + $old_mode = '' if(!defined($old_mode)); + return if $old_mode eq $mode && !$force_rebuild; + $old_mode = $mode; + undef $force_rebuild; + my @elems; + my $wait; $wait = statusbar_msg(N("Please wait, listing packages...")) if $MODE ne 'update'; + { + my @keys = @filtered_pkgs; + if (member($mode, qw(all_updates security bugfix normal))) { + @keys = grep { + my ($name) = split_fullname($_); + member($descriptions->{$name}{importance}, @$mandrakeupdate_wanted_categories) + || ! $descriptions->{$name}{importance}; + } @keys; + if (@keys == 0) { + add_node('', N("(none)"), { nochild => 1 }); + state $explanation_only_once; + $explanation_only_once or interactive_msg(N("No update"), + N("The list of updates is empty. This means that either there is +no available update for the packages installed on your computer, +or you already installed all of them.")); + $explanation_only_once = 1; + } + } + # FIXME: better do this on first group access for faster startup... + @elems = map { [ $_, !$flat && ctreefy($pkgs->{$_}{pkg}->group) ] } sort_packages(@keys); + } + my %sortmethods = ( + by_size => sub { sort { $pkgs->{$b->[0]}{pkg}->size <=> $pkgs->{$a->[0]}{pkg}->size } @_ }, + by_selection => sub { sort { $pkgs->{$b->[0]}{selected} <=> $pkgs->{$a->[0]}{selected} + || uc($a->[0]) cmp uc($b->[0]) } @_ }, + by_leaves => sub { + # inlining part of MDK::Common::Data::difference2(): + my %l; @l{map { $_->[0] } @_} = (); + my @pkgs_times = ('rpm', '-q', '--qf', '%{name}-%{version}-%{release}.%{arch} %{installtime}\n', + map { chomp_($_) } run_program::get_stdout('urpmi_rpm-find-leaves')); + sort { $b->[1] <=> $a->[1] } grep { exists $l{$_->[0]} } map { chomp; [ split ] } run_rpm(@pkgs_times); + }, + flat => sub { no locale; sort { uc($a->[0]) cmp uc($b->[0]) } @_ }, + by_medium => sub { sort { $a->[2] <=> $b->[2] || uc($a->[0]) cmp uc($b->[0]) } @_ }, + ); + if ($flat) { + add_node($tree->currentItem()->label(), '') foreach $sortmethods{$::mode->[0] || 'flat'}->(@elems); + } else { + if (0 && $MODE eq 'update') { + foreach ($sortmethods{flat}->(@elems)){ + add_node($tree->currentItem()->label(), $_->[0], N("All")) + } + $tree->expand_row($tree_model->get_path($tree_model->get_iter_first), 0); + } elsif ($::mode->[0] eq 'by_source') { + _build_tree($tree, $elems, $sortmethods{by_medium}->(map { + my $m = pkg2medium($pkgs->{$_->[0]}{pkg}, $urpm); [ $_->[0], $m->{name}, $m->{priority} ]; + } @elems)); + } elsif ($::mode->[0] eq 'by_presence') { + _build_tree($tree, $elems, map { + my $pkg = $pkgs->{$_->[0]}{pkg}; + [ $_->[0], $pkg->flag_installed ? + (!$pkg->flag_skip && $pkg->flag_upgrade ? N("Upgradable") : N("Installed")) + : N("Addable") ]; + } $sortmethods{flat}->(@elems)); + } else { + _build_tree($tree, $elems, @elems); + # INFO: $elems contains references to the packages of the group, see _build_tree + } + } + statusbar_msg_remove($wait) if defined $wait; +} + +sub get_info { + my ($key, $widget) = @_; + #- the package information hasn't been loaded. Instead of rescanning the media, just give up. + exists $pkgs->{$key} or return [ [ N("Description not available for this package\n") ] ]; + #- get the description if needed: + exists $pkgs->{$key}{description} or slow_func($widget, sub { extract_header($pkgs->{$key}, $urpm, 'info', find_installed_version($pkgs->{$key}{pkg})) }); + format_pkg_simplifiedinfo($pkgs, $key, $urpm, $descriptions); +} + +sub sort_callback { + my ($store, $treeiter1, $treeiter2) = @_; + URPM::rpmvercmp(map { $store->get_value($_, $pkg_columns{version}) } $treeiter1, $treeiter2); +} + +sub run_help_callback { + my (undef, $url) = @_; + my ($user) = grep { $_->[2] eq $ENV{USERHELPER_UID} } list_passwd(); + local $ENV{HOME} = $user->[7] if $user && $ENV{USERHELPER_UID}; + run_program::raw({ detach => 1, as_user => 1 }, 'www-browser', $url); +} + +sub groups_tree { + return %groups_tree; +} + +sub group_has_parent { + my ($group) = shift; + return 0 if(!defined($group)); + return defined($groups_tree{$group}{parent}); +} + +sub group_parent { + my ($group) = shift; + # if group is a parent itself return it + # who use group_parent have to take care of the comparison + # between a group and its parent + # e.g. group System has groups_tree{'System'}{parent}->label() = 'System' + return $groups_tree{$group}{parent} if(group_has_parent($group)); + for my $sup (keys %groups_tree){ + for my $item(keys %{$groups_tree{$sup}{children}}){ + if(defined($group) && ($item eq $group)){ + return $groups_tree{$sup}{parent}; + } + } + } + return undef; +} + +1; diff --git a/lib/AdminPanel/Rpmdragora/gurpm.pm b/lib/AdminPanel/Rpmdragora/gurpm.pm new file mode 100644 index 00000000..983f0554 --- /dev/null +++ b/lib/AdminPanel/Rpmdragora/gurpm.pm @@ -0,0 +1,138 @@ +# vim: set et ts=4 sw=4: +package AdminPanel::Rpmdragora::gurpm; +#***************************************************************************** +# +# Copyright (c) 2002 Guillaume Cottenceau +# Copyright (c) 2002-2007 Thierry Vignaud +# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA +# Copyright (c) 2005-2007 Mandriva SA +# Copyright (c) 2013 Matteo Pasotti +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** +# +# $Id: gurpm.pm 255450 2009-04-03 16:00:16Z tv $ + +use strict; +use lib qw(/usr/lib/libDrakX); +use yui; +use Time::HiRes; +use feature 'state'; + +sub new { + my ($class, $title, $initializing, %options) = @_; + my $self = { + my $label = 0, + my $factory = 0, + my $mainw = 0, + my $vbox = 0, + my $progressbar = 0, + my $cancel = 0 + }; + bless $self, 'AdminPanel::Rpmdragora::gurpm'; + #my $mainw = bless(ugtk2->new($title, %options, default_width => 600, width => 600), $self); + $self->{factory} = yui::YUI::widgetFactory; + $self->{mainw} = $self->{factory}->createPopupDialog(); + #$::main_window = $self->{mainw}; + $self->{vbox} = $self->{factory}->createVBox($self->{mainw}); + #OLD $mainw->{label} = gtknew('Label', text => $initializing, alignment => [ 0.5, 0 ]); + $self->{label} = $self->{factory}->createLabel($self->{vbox}, $initializing); + # size label's heigh to 2 lines in order to prevent dummy vertical resizing: + #my $context = $mainw->{label}->get_layout->get_context; + #my $metrics = $context->get_metrics($mainw->{label}->style->font_desc, $context->get_language); + #$mainw->{label}->set_size_request(-1, 2 * Gtk2::Pango->PANGO_PIXELS($metrics->get_ascent + $metrics->get_descent)); + + #OLD $mainw->{progressbar} = gtknew('ProgressBar'); + $self->{progressbar} = $self->{factory}->createProgressBar($self->{vbox}, ""); + #gtkadd($mainw->{window}, $mainw->{vbox} = gtknew('VBox', spacing => 5, border_width => 6, children_tight => [ + # $mainw->{label}, + # $mainw->{progressbar} + #])); + #$mainw->{rwindow}->set_position('center-on-parent'); + #$mainw->{real_window}->show_all; + #select(undef, undef, undef, 0.1); #- hackish :-( + #$mainw->SUPER::sync; + $self->{mainw}->pollEvent(); + $self->flush(); + $self; +} + +sub flush { + my ($self) = @_; + $self->{mainw}->recalcLayout(); + $self->{mainw}->doneMultipleChanges(); +} + +sub label { + my ($self, $label) = @_; + $self->{label} = $self->{factory}->createLabel($self->{vbox},$label); + #select(undef, undef, undef, 0.1); #- hackish :-( + $self->flush(); +} + +sub progress { + my ($self, $value) = @_; + state $time; + $time = 0 if(!defined($time)); + $value = 0 if $value < 0; + $value = 100 if 1 < $value; + $self->{progressbar}->setValue($value); + return if Time::HiRes::clock_gettime() - $time < 0.333; + $time = Time::HiRes::clock_gettime(); + $self->flush(); +} + +sub DESTROY { + my ($self) = @_; + #mygtk2::may_destroy($self); + $self and $self->{mainw}->destroy; + #$self = undef; + $self->{cancel} = undef; #- in case we'll do another one later +} + +sub validate_cancel { + my ($self, $cancel_msg, $cancel_cb) = @_; + if (!$self->{cancel}) { + $self->{cancel} = $self->{factory}->createIconButton($self->{vbox},"",$cancel_msg); + #gtkpack__( + #$self->{vbox}, + #$self->{hbox_cancel} = gtkpack__( + #gtknew('HButtonBox'), + #$self->{cancel} = gtknew('Button', text => $cancel_msg, clicked => \&$cancel_cb), + #), + #); + } + #$self->{cancel}->set_sensitive(1); + #$self->{cancel}->show; + $self->flush(); +} + +sub invalidate_cancel { + my ($self) = @_; + $self->{cancel} and $self->{cancel}->setEnabled(0); +} + +sub invalidate_cancel_forever { + my ($self) = @_; + #$self->{hbox_cancel} or return; + #$self->{hbox_cancel}->destroy; + # FIXME: temporary workaround that prevents + # Gtk2::Label::set_text() set_text_internal() -> queue_resize() -> + # size_allocate() call chain to mess up when ->shrink_topwindow() + # has been called (#32613): + #$self->shrink_topwindow; +} + +1; diff --git a/lib/AdminPanel/Rpmdragora/icon.pm b/lib/AdminPanel/Rpmdragora/icon.pm new file mode 100644 index 00000000..1dee4e5c --- /dev/null +++ b/lib/AdminPanel/Rpmdragora/icon.pm @@ -0,0 +1,236 @@ +# vim: set et ts=4 sw=4: +package AdminPanel::Rpmdragora::icon; +#***************************************************************************** +# +# Copyright (c) 2002 Guillaume Cottenceau +# Copyright (c) 2002-2007 Thierry Vignaud +# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA +# Copyright (c) 2005-2007 Mandriva SA +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** +# +# $Id: icon.pm 237459 2008-02-26 14:20:47Z tv $ + +use strict; +our @ISA = qw(Exporter); +use lib qw(/usr/lib/libDrakX); +use POSIX; +use common; + +# TO WORKAROUND LOCALIZATION ISSUE +use AdminPanel::Rpmdragora::localization; + +our @EXPORT = qw(get_icon_path); +#- /usr/share/rpmlint/config (duplicates are normal, so that we are not too far away from .py) +my %group_icons = ( + N("All") => 'system_section', + N("Accessibility") => 'accessibility_section', + N("Archiving") => 'archiving_section', + join('|', N("Archiving"), N("Backup")) => 'backup_section', + join('|', N("Archiving"), N("Cd burning")) => 'cd_burning_section', + join('|', N("Archiving"), N("Compression")) => 'compression_section', + join('|', N("Archiving"), N("Other")) => 'other_archiving', + N("Communications") => 'communications_section', + join('|', N("Communications"), N("Bluetooth")) => 'communications_bluetooth_section', + join('|', N("Communications"), N("Dial-Up")) => 'communications_dialup_section', + join('|', N("Communications"), N("Fax")) => 'communications_fax_section', + join('|', N("Communications"), N("Mobile")) => 'communications_mobile_section', + join('|', N("Communications"), N("Radio")) => 'communications_radio_section', + join('|', N("Communications"), N("Serial")) => 'communications_serial_section', + join('|', N("Communications"), N("Telephony")) => 'communications_phone_section', + N("Databases") => 'databases_section', + N("Development") => 'development_section', + join('|', N("Development"), N("Basic")) => '', + join('|', N("Development"), N("C")) => '', + join('|', N("Development"), N("C++")) => '', + join('|', N("Development"), N("C#")) => '', + join('|', N("Development"), N("Databases")) => 'databases_section', + join('|', N("Development"), N("Debug")) => '', + join('|', N("Development"), N("Erlang")) => '', + join('|', N("Development"), N("GNOME and GTK+")) => 'gnome_section', + join('|', N("Development"), N("Java")) => '', + join('|', N("Development"), N("KDE and Qt")) => 'kde_section', + join('|', N("Development"), N("Kernel")) => '', + join('|', N("Development"), N("OCaml")) => '', + join('|', N("Development"), N("Other")) => '', + join('|', N("Development"), N("Perl")) => '', + join('|', N("Development"), N("PHP")) => '', + join('|', N("Development"), N("Python")) => '', + join('|', N("Development"), N("Tools")) => 'development_tools_section', + join('|', N("Development"), N("X11")) => '', + N("Documentation") => 'documentation_section', + N("Editors") => 'editors_section', + N("Education") => 'education_section', + N("Emulators") => 'emulators_section', + N("File tools") => 'file_tools_section', + N("Games") => 'amusement_section', + join('|', N("Games"), N("Adventure")) => 'adventure_section', + join('|', N("Games"), N("Arcade")) => 'arcade_section', + join('|', N("Games"), N("Boards")) => 'boards_section', + join('|', N("Games"), N("Cards")) => 'cards_section', + join('|', N("Games"), N("Other")) => 'other_amusement', + join('|', N("Games"), N("Puzzles")) => 'puzzle_section', + join('|', N("Games"), N("Shooter")) => 'shooter_section', + join('|', N("Games"), N("Simulation")) => 'simulation_section', + join('|', N("Games"), N("Sports")) => 'sport_section', + join('|', N("Games"), N("Strategy")) => 'strategy_section', + N("Geography") => 'geography_section', + N("Graphical desktop") => 'graphical_desktop_section', + join('|', N("Graphical desktop"), + #-PO: This is a package/product name. Only translate it if needed: + N("Enlightenment")) => 'enlightment_section', + join('|', N("Graphical desktop"), + #-PO: This is a package/product name. Only translate it if needed: + N("GNOME")) => 'gnome_section', + join('|', N("Graphical desktop"), + #-PO: This is a package/product name. Only translate it if needed: + N("Icewm")) => 'icewm_section', + join('|', N("Graphical desktop"), + #-PO: This is a package/product name. Only translate it if needed: + N("KDE")) => 'kde_section', + join('|', N("Graphical desktop"), N("Other")) => 'more_applications_other_section', + join('|', N("Graphical desktop"), + #-PO: This is a package/product name. Only translate it if needed: + N("WindowMaker")) => 'windowmaker_section', + join('|', N("Graphical desktop"), + #-PO: This is a package/product name. Only translate it if needed: + N("Xfce")) => 'xfce_section', + N("Graphics") => 'graphics_section', + join('|', N("Graphics"), N("3D")) => 'graphics_3d_section', + join('|', N("Graphics"), N("Editors and Converters")) => 'graphics_editors_section', + join('|', N("Graphics"), N("Utilities")) => 'graphics_utilities_section', + join('|', N("Graphics"), N("Photography")) => 'graphics_photography_section', + join('|', N("Graphics"), N("Scanning")) => 'graphics_scanning_section', + join('|', N("Graphics"), N("Viewers")) => 'graphics_viewers_section', + N("Monitoring") => 'monitoring_section', + N("Networking") => 'networking_section', + join('|', N("Networking"), N("File transfer")) => 'file_transfer_section', + join('|', N("Networking"), N("IRC")) => 'irc_section', + join('|', N("Networking"), N("Instant messaging")) => 'instant_messaging_section', + join('|', N("Networking"), N("Mail")) => 'mail_section', + join('|', N("Networking"), N("News")) => 'news_section', + join('|', N("Networking"), N("Other")) => 'other_networking', + join('|', N("Networking"), N("Remote access")) => 'remote_access_section', + join('|', N("Networking"), N("WWW")) => 'networking_www_section', + N("Office") => 'office_section', + join('|', N("Office"), N("Dictionary")) => 'office_dictionary_section', + join('|', N("Office"), N("Finance")) => 'finances_section', + join('|', N("Office"), N("Management")) => 'timemanagement_section', + join('|', N("Office"), N("Organizer")) => 'timemanagement_section', + join('|', N("Office"), N("Utilities")) => 'office_accessories_section', + join('|', N("Office"), N("Spreadsheet")) => 'spreadsheet_section', + join('|', N("Office"), N("Suite")) => 'office_suite', + join('|', N("Office"), N("Word processor")) => 'wordprocessor_section', + N("Publishing") => 'publishing_section', + N("Sciences") => 'sciences_section', + join('|', N("Sciences"), N("Astronomy")) => 'astronomy_section', + join('|', N("Sciences"), N("Biology")) => 'biology_section', + join('|', N("Sciences"), N("Chemistry")) => 'chemistry_section', + join('|', N("Sciences"), N("Computer science")) => 'computer_science_section', + join('|', N("Sciences"), N("Geosciences")) => 'geosciences_section', + join('|', N("Sciences"), N("Mathematics")) => 'mathematics_section', + join('|', N("Sciences"), N("Other")) => 'other_sciences', + join('|', N("Sciences"), N("Physics")) => 'physics_section', + N("Security") => 'security_section', + N("Shells") => 'shells_section', + N("Sound") => 'sound_section', + join('|', N("Sound"), N("Editors and Converters")) => 'sound_editors_section', + join('|', N("Sound"), N("Midi")) => 'sound_midi_section', + join('|', N("Sound"), N("Mixers")) => 'sound_mixers_section', + join('|', N("Sound"), N("Players")) => 'sound_players_section', + join('|', N("Sound"), N("Utilities")) => 'sound_utilities_section', + N("System") => 'system_section', + join('|', N("System"), N("Base")) => 'system_section', + join('|', N("System"), N("Boot and Init")) => 'boot_init_section', + join('|', N("System"), N("Cluster")) => 'parallel_computing_section', + join('|', N("System"), N("Configuration")) => 'configuration_section', + join('|', N("System"), N("Fonts")) => 'chinese_section', + join('|', N("System"), N("Fonts"), N("True type")) => '', + join('|', N("System"), N("Fonts"), N("Type1")) => '', + join('|', N("System"), N("Fonts"), N("X11 bitmap")) => '', + join('|', N("System"), N("Internationalization")) => 'chinese_section', + join('|', N("System"), N("Kernel and hardware")) => 'hardware_configuration_section', + join('|', N("System"), N("Libraries")) => 'system_section', + join('|', N("System"), N("Networking")) => 'networking_configuration_section', + join('|', N("System"), N("Packaging")) => 'packaging_section', + join('|', N("System"), N("Printing")) => 'printing_section', + join('|', N("System"), N("Servers")) => 'servers_section', + join('|', N("System"), + #-PO: This is a package/product name. Only translate it if needed: + N("X11")) => 'x11_section', + N("Terminals") => 'terminals_section', + N("Text tools") => 'text_tools_section', + N("Toys") => 'toys_section', + N("Video") => 'video_section', + join('|', N("Video"), N("Editors and Converters")) => 'video_editors_section', + join('|', N("Video"), N("Players")) => 'video_players_section', + join('|', N("Video"), N("Television")) => 'video_television_section', + join('|', N("Video"), N("Utilities")) => 'video_utilities_section', + + # for Mageia Choice: + N("Workstation") => 'system_section', + join('|', N("Workstation"), N("Configuration")) => 'configuration_section', + join('|', N("Workstation"), N("Console Tools")) => 'interpreters_section', + join('|', N("Workstation"), N("Documentation")) => 'documentation_section', + join('|', N("Workstation"), N("Game station")) => 'amusement_section', + join('|', N("Workstation"), N("Internet station")) => 'networking_section', + join('|', N("Workstation"), N("Multimedia station")) => 'multimedia_section', + join('|', N("Workstation"), N("Network Computer (client)")) => 'other_networking', + join('|', N("Workstation"), N("Office Workstation")) => 'office_section', + join('|', N("Workstation"), N("Scientific Workstation")) => 'sciences_section', + N("Graphical Environment") => 'graphical_desktop_section', + + join('|', N("Graphical Environment"), N("GNOME Workstation")) => 'gnome_section', + join('|', N("Graphical Environment"), N("IceWm Desktop")) => 'icewm_section', + join('|', N("Graphical Environment"), N("KDE Workstation")) => 'kde_section', + join('|', N("Graphical Environment"), N("Other Graphical Desktops")) => 'more_applications_other_section', + N("Development") => 'development_section', + join('|', N("Development"), N("Development")) => 'development_section', + join('|', N("Development"), N("Documentation")) => 'documentation_section', + N("Server") => 'servers_section', + join('|', N("Server"), N("DNS/NIS")) => 'networking_section', + join('|', N("Server"), N("Database")) => 'databases_section', + join('|', N("Server"), N("Firewall/Router")) => 'networking_section', + join('|', N("Server"), N("Mail")) => 'mail_section', + join('|', N("Server"), N("Mail/Groupware/News")) => 'mail_section', + join('|', N("Server"), N("Network Computer server")) => 'networking_section', + join('|', N("Server"), N("Web/FTP")) => 'networking_www_section', + + ); + +sub get_icon_path { + my ($group, $parent) = @_; + my $path; + if(isdigit($parent) && $parent == 0){ + $path = '/usr/share/icons/'; + }else{ + $path = '/usr/share/icons/mini/'; + } + my $icon_path = ""; + if(defined($group_icons{$group})){ + $icon_path = join('', $path, $group_icons{$group}, '.png'); + }elsif(defined($group_icons{$parent."\|".$group})){ + $icon_path = join('', $path, $group_icons{$parent."\|".$group}, '.png'); + }else{ + $icon_path = join('', $path, 'applications_section', '.png'); + } + unless(-e $icon_path){ + $icon_path = join('', $path, 'applications_section', '.png'); + } + return $icon_path; +} + +1; diff --git a/lib/AdminPanel/Rpmdragora/init.pm b/lib/AdminPanel/Rpmdragora/init.pm new file mode 100644 index 00000000..34581bf2 --- /dev/null +++ b/lib/AdminPanel/Rpmdragora/init.pm @@ -0,0 +1,174 @@ +# vim: set et ts=4 sw=4: +package AdminPanel::Rpmdragora::init; +#***************************************************************************** +# +# Copyright (c) 2002 Guillaume Cottenceau +# Copyright (c) 2002-2007 Thierry Vignaud +# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA +# Copyright (c) 2005-2007 Mandriva SA +# Copyright (c) 2013 Matteo Pasotti +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** +# +# $Id: init.pm 263915 2009-12-03 17:41:04Z tv $ + +use strict; +use MDK::Common::Func 'any'; +use lib qw(/usr/lib/libDrakX); +use common; +use English; +BEGIN { $::no_global_argv_parsing = 1 } +require urpm::args; + +use Exporter; +our @ISA = qw(Exporter); +our @EXPORT = qw(init + warn_about_user_mode + $MODE + $changelog_first + $default_list_mode + %rpmdragora_options + @ARGV_copy + ); + +our @ARGV_copy = @ARGV; + +BEGIN { #- we want to run this code before the Gtk->init of the use-my_gtk + my $basename = sub { local $_ = shift; s|/*\s*$||; s|.*/||; $_ }; + any { /^--?h/ } @ARGV and do { + printf join("\n", N("Usage: %s [OPTION]...", $basename->($0)), +N(" --auto assume default answers to questions"), +N(" --changelog-first display changelog before filelist in the description window"), +N(" --media=medium1,.. limit to given media"), +N(" --merge-all-rpmnew propose to merge all .rpmnew/.rpmsave files found"), +N(" --mode=MODE set mode (install (default), remove, update)"), +N(" --justdb update the database, but do not modify the filesystem"), +N(" --no-confirmation don't ask first confirmation question in update mode"), +N(" --no-media-update don't update media at startup"), +N(" --no-verify-rpm don't verify package signatures"), +if_($0 !~ /MageiaUpdate/, N(" --parallel=alias,host be in parallel mode, use \"alias\" group, use \"host\" machine to show needed deps")), +N(" --rpm-root=path use another root for rpm installation"), +N(" --urpmi-root use another root for urpmi db & rpm installation"), +N(" --run-as-root force to run as root"), +N(" --search=pkg run search for \"pkg\""), +N(" --test only verify if the installation can be achieved correctly"), +chomp_(N(" --version print this tool's version number +")), +"" +); + exit 0; + }; +} + +BEGIN { #- for mcc + if ("@ARGV" =~ /--embedded (\w+)/) { + $::XID = $1; + $::isEmbedded = 1; + } +} + + +#- 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. +use POSIX qw(setlocale LC_ALL LC_COLLATE strftime); +use locale; +my $collation_locale = $ENV{LC_ALL}; +if ($collation_locale) { + $collation_locale =~ /UTF-8/ or setlocale(LC_ALL, "$collation_locale.UTF-8"); +} else { + $collation_locale = setlocale(LC_COLLATE); + $collation_locale =~ /UTF-8/ or setlocale(LC_COLLATE, "$collation_locale.UTF-8"); +} + +our $version = 1; +our %rpmdragora_options; + +my $i; +foreach (@ARGV) { + $i++; + /^-?-(\S+)$/ or next; + my $val = $1; + if ($val =~ /=/) { + my ($name, $values) = split /=/, $val; + my @values = split /,/, $values; + $rpmdragora_options{$name} = \@values if @values; + } else { + if ($val eq 'version') { + print "$0 $version\n"; + exit(0); + } elsif ($val =~ /^(test|expert)$/) { + eval "\$::$1 = 1"; + } elsif ($val =~ /^(q|quiet)$/) { + urpm::args::set_verbose(-1); + } elsif ($val =~ /^(v|verbose)$/) { + urpm::args::set_verbose(1); + } else { + $rpmdragora_options{$val} = 1; + } + } +} + +foreach my $option (qw(media mode parallel rpm-root search)) { + if (defined $rpmdragora_options{$option} && !ref($rpmdragora_options{$option})) { + warn qq(wrong usage of "$option" option!\n); + exit(-1); # too early for my_exit() + } +} + +$urpm::args::options{basename} = 1; + +our $MODE = ref $rpmdragora_options{mode} ? $rpmdragora_options{mode}[0] : undef; +our $overriding_config = defined $MODE; +unless ($MODE) { + $MODE = 'install'; + $0 =~ m|remove$| and $MODE = 'remove'; + $0 =~ m|update$|i and $MODE = 'update'; +} + +our $default_list_mode; +$default_list_mode = 'gui_pkgs' if $MODE eq 'install'; +if ($MODE eq 'remove') { + $default_list_mode = 'installed'; +} elsif ($MODE eq 'update') { + $default_list_mode = 'all_updates'; +} + +$MODE eq 'update' || $rpmdragora_options{'run-as-root'} and require_root_capability(); +$::noborderWhenEmbedded = 1; + +require AdminPanel::rpmdragora; + +our $changelog_first = $rpmdragora::changelog_first_config->[0]; +$changelog_first = 1 if $rpmdragora_options{'changelog-first'}; + +sub warn_about_user_mode() { + my $title = N("Running in user mode"); + my $msg = N("You are launching this program as a normal user.\n". + "You will not be able to perform modifications on the system,\n". + "but you may still browse the existing database."); + + if(($EUID != 0) and (!AdminPanel::rpmdragora::interactive_msg($title, $msg))) { + return 0; + } + return 1; +} + +sub init() { + URPM::bind_rpm_textdomain_codeset(); +} + +1; diff --git a/lib/AdminPanel/Rpmdragora/localization.pm b/lib/AdminPanel/Rpmdragora/localization.pm new file mode 100644 index 00000000..fb199d93 --- /dev/null +++ b/lib/AdminPanel/Rpmdragora/localization.pm @@ -0,0 +1,35 @@ +#!/usr/bin/perl +# vim: set et ts=4 sw=4: +package AdminPanel::Rpmdragora::localization; +#***************************************************************************** +# +# Copyright (c) 2013 Matteo Pasotti +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** +use strict; +use warnings; +use diagnostics; +use lib qw(/usr/lib/libDrakX); +use common; + +Locale::gettext::bind_textdomain_codeset($_, 'UTF8') foreach 'libDrakX', if_(!$::isInstall, 'libDrakX-standalone'), + if_($::isRestore, 'draksnapshot'), if_($::isInstall, 'urpmi'), + 'drakx-net', 'drakx-kbd-mouse-x11', # shared translation + @::textdomains; + +#========= UGLY WORKAROUND ============ +push @::textdomains, 'rpmdrake'; +#========= UGLY WORKAROUND ============ diff --git a/lib/AdminPanel/Rpmdragora/open_db.pm b/lib/AdminPanel/Rpmdragora/open_db.pm new file mode 100644 index 00000000..aa1fd14d --- /dev/null +++ b/lib/AdminPanel/Rpmdragora/open_db.pm @@ -0,0 +1,162 @@ +# vim: set et ts=4 sw=4: +package AdminPanel::Rpmdragora::open_db; +#***************************************************************************** +# +# Copyright (c) 2002 Guillaume Cottenceau +# Copyright (c) 2002-2007 Thierry Vignaud +# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA +# Copyright (c) 2005-2007 Mandriva SA +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** +# +# $Id: open_db.pm 268344 2010-05-06 13:06:08Z jvictor $ + +use strict; +use common; +use AdminPanel::rpmdragora; +use URPM; +use urpm; +use urpm::args; +use urpm::select; +use urpm::media; +use feature 'state'; + +use Exporter; +our @ISA = qw(Exporter); +our @EXPORT = qw(fast_open_urpmi_db + get_backport_media + get_inactive_backport_media + get_update_medias + is_it_a_devel_distro + open_rpm_db + open_urpmi_db + ); + + +# because rpm blocks some signals when rpm DB is opened, we don't keep open around: +sub open_rpm_db { + my ($o_force) = @_; + my $host; + log::explanations("opening the RPM database"); + if ($::rpmdragora_options{parallel} && ((undef, $host) = @{$::rpmdragora_options{parallel}})) { + state $done; + my $dblocation = "/var/cache/urpmi/distantdb/$host"; + if (!$done || $o_force) { + print "syncing db from $host to $dblocation..."; + mkdir_p "$dblocation/var/lib/rpm"; + system "rsync -Sauz -e ssh $host:/var/lib/rpm/ $dblocation/var/lib/rpm"; + $? == 0 or die "Couldn't sync db from $host to $dblocation"; + $done = 1; + print "done.\n"; + } + URPM::DB::open($dblocation) or die "Couldn't open RPM DB"; + } else { + my $db; + if ($::env) { + #- URPM has same methods as URPM::DB and empty URPM will be seen as empty URPM::DB. + $db = new URPM; + $db->parse_synthesis("$::env/rpmdb.cz"); + } else { + $db = URPM::DB::open($::rpmdragora_options{'rpm-root'}[0]); + } + $db or die "Couldn't open RPM DB (" . ($::env ? "$::env/rpmdb.cz" : $::rpmdragora_options{'rpm-root'}[0]) . ")"; + } +} + +# do not pay the urpm::media::configure() heavy cost: +sub fast_open_urpmi_db() { + my $urpm = urpm->new; + my $error_happened; + $urpm->{fatal} = sub { + $error_happened = 1; + interactive_msg(N("Fatal error"), + N("A fatal error occurred: %s.", $_[1])); + }; + + urpm::set_files($urpm, $::rpmdragora_options{'urpmi-root'}[0]) if $::rpmdragora_options{'urpmi-root'}[0]; + $::rpmdragora_options{'rpm-root'}[0] ||= $::rpmdragora_options{'urpmi-root'}[0]; + urpm::args::set_root($urpm, $::rpmdragora_options{'rpm-root'}[0]) if $::rpmdragora_options{'rpm-root'}[0]; + urpm::args::set_debug($urpm) if $::rpmdragora_options{debug}; + $urpm->get_global_options; + $urpm->{options}{wait_lock} = $::rpmdragora_options{'wait-lock'}; + $urpm->{options}{'verify-rpm'} = !$::rpmdragora_options{'no-verify-rpm'} if defined $::rpmdragora_options{'no-verify-rpm'}; + $urpm->{options}{auto} = $::rpmdragora_options{auto} if defined $::rpmdragora_options{auto}; + urpm::args::set_verbosity(); + if ($::rpmdragora_options{env} && $::rpmdragora_options{env}[0]) { + $::env = $::rpmdragora_options{env}[0]; + # prevent crashing in URPM.pm prevent when using --env: + $::env = "$ENV{PWD}/$::env" if $::env !~ m!^/!; + urpm::set_env($urpm, $::env); + } + + $urpm::args::options{justdb} = $::rpmdragora_options{justdb}; + + urpm::media::read_config($urpm, 0); + foreach (@{$urpm->{media}}) { + next if $_->{ignore}; + urpm::media::_tempignore($_, 1) if $ignore_debug_media->[0] && $_->{name} =~ /debug/i; + } + # FIXME: seems uneeded with newer urpmi: + if ($error_happened) { + touch('/etc/urpmi/urpmi.cfg'); + exec('edit-urpm-sources.pl'); + } + $urpm; +} + +sub is_it_a_devel_distro() { + state $res; + return $res if defined $res; + + my $path = $::rpmdragora_options{'urpmi-root'}[0] . '/etc/product.id'; + $res = common::parse_LDAP_namespace_structure(cat_($path))->{branch} eq 'Devel'; + return $res; +} + +sub get_backport_media { + my ($urpm) = @_; + grep { $_->{name} =~ /backport/i && + $_->{name} !~ /debug|sources/i } @{$urpm->{media}}; +} + +sub get_inactive_backport_media { + my ($urpm) = @_; + map { $_->{name} } grep { $_->{ignore} } get_backport_media($urpm); +} + +sub get_update_medias { + my ($urpm) = @_; + if (is_it_a_devel_distro()) { + grep { !$_->{ignore} } @{$urpm->{media}}; + } else { + grep { !$_->{ignore} && $_->{update} } @{$urpm->{media}}; + } +} + +sub open_urpmi_db { + my (%urpmi_options) = @_; + my $urpm = fast_open_urpmi_db(); + my $media = ref $::rpmdragora_options{media} ? join(',', @{$::rpmdragora_options{media}}) : ''; + + my $searchmedia = $urpmi_options{update} ? undef : join(',', get_inactive_backport_media($urpm)); + $urpm->{lock} = urpm::lock::urpmi_db($urpm, undef, wait => $urpm->{options}{wait_lock}) if !$::env; + my $previous = $::rpmdragora_options{'previous-priority-upgrade'}; + urpm::select::set_priority_upgrade_option($urpm, (ref $previous ? join(',', @$previous) : ())); + urpm::media::configure($urpm, media => $media, if_($searchmedia, searchmedia => $searchmedia), %urpmi_options); + $urpm; +} + +1; diff --git a/lib/AdminPanel/Rpmdragora/pkg.pm b/lib/AdminPanel/Rpmdragora/pkg.pm new file mode 100644 index 00000000..e8c1a08a --- /dev/null +++ b/lib/AdminPanel/Rpmdragora/pkg.pm @@ -0,0 +1,997 @@ +# vim: set et ts=4 sw=4: +package AdminPanel::Rpmdragora::pkg; +#***************************************************************************** +# +# Copyright (c) 2002 Guillaume Cottenceau +# Copyright (c) 2002-2007 Thierry Vignaud +# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA +# Copyright (c) 2005-2007 Mandriva SA +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** +# +# $Id: pkg.pm 270160 2010-06-22 19:55:40Z jvictor $ + +use strict; +use MDK::Common::Func 'any'; +use lib qw(/usr/lib/libDrakX); +use common; +use POSIX qw(_exit); +use URPM; +use utf8; +use AdminPanel::Rpmdragora::open_db; +use AdminPanel::Rpmdragora::gurpm; +use AdminPanel::Rpmdragora::formatting; +use AdminPanel::Rpmdragora::rpmnew; + +use AdminPanel::rpmdragora; +use urpm; +use urpm::lock; +use urpm::install; +use urpm::signature; +use urpm::get_pkgs; +use urpm::select; +use urpm::main_loop; +use urpm::args qw(); + + +use Exporter; +our @ISA = qw(Exporter); +our @EXPORT = qw( + $priority_up_alread_warned + download_callback + extract_header + find_installed_version + get_pkgs + perform_installation + perform_removal + run_rpm + sort_packages + ); + +#use mygtk2 qw(gtknew); +#use ugtk2 qw(:all); + +our $priority_up_alread_warned; + +sub sort_packages_biarch { + sort { + my ($na, $aa) = $a =~ /^(.*-[^-]+-[^-]+)\.([^.-]+)$/; + my ($nb, $ab) = $b =~ /^(.*-[^-]+-[^-]+)\.([^.-]+)$/; + $na cmp $nb || ($ab =~ /64$/) <=> ($aa =~ /64$/); + } @_; +} + +sub sort_packages_monoarch { + sort { uc($a) cmp uc($b) } @_; +} + +*sort_packages = arch() =~ /x86_64/ ? \&sort_packages_biarch : \&sort_packages_monoarch; + +sub run_rpm { + foreach (qw(LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT LC_IDENTIFICATION LC_ALL)) { + local $ENV{$_} = $ENV{$_} . '.UTF-8' if $ENV{$_} && $ENV{$_} !~ /UTF-8/; + } + my @l = map { ensure_utf8($_); $_ } run_program::get_stdout(@_); + wantarray() ? @l : join('', @l); +} + + +sub extract_header { + my ($pkg, $urpm, $xml_info, $o_installed_version) = @_; + my %fields = ( + info => 'description', + files => 'files', + changelog => 'changelog', + ); + # already extracted: + return if $pkg->{$fields{$xml_info}}; + + my $p = $pkg->{pkg}; + + if (!$p) { + warn ">> ghost package '$pkg' has no URPM object!!!\n"; + return; + } + + my $name = $p->fullname; + # fix extracting info for SRPMS and RPM GPG keys: + $name =~ s!\.src!!; + + if ($p->flag_installed && !$p->flag_upgrade) { + my @files = map { chomp_($_) } run_rpm("rpm -ql $name"); + add2hash($pkg, { files => [ @files ? @files : N("(none)") ], + description => rpm_description(scalar(run_rpm("rpm -q --qf '%{description}' $name"))), + changelog => format_changelog_string($o_installed_version, scalar(run_rpm("rpm -q --changelog $name"))) }); + } else { + my $medium = pkg2medium($p, $urpm); + my ($local_source, %xml_info_pkgs, $bar_id); + my $_statusbar_clean_guard = before_leaving { $bar_id and statusbar_msg_remove($bar_id) }; + my $dir = urpm::file_from_local_url($medium->{url}); + print "p->filename: ". $p->filename."\n"; + $local_source = "$dir/" . $p->filename if $dir; + print "local_source: $local_source\n"; + if (-e $local_source) { + $bar_id = statusbar_msg(N("Getting information from %s...", $dir), 0); + $urpm->{log}("getting information from rpms from $dir"); + } else { + my $gurpm; + $bar_id = statusbar_msg(N("Getting '%s' from XML meta-data...", $xml_info), 0); + my $_gurpm_clean_guard = before_leaving { undef $gurpm }; + if (my $xml_info_file = eval { urpm::media::any_xml_info($urpm, $medium, $xml_info, undef, sub { + $gurpm ||= Rpmdragora::gurpm->new(N("Please wait"), + '', # FIXME: add a real string after cooker + transient => $::main_window); + download_callback($gurpm, @_) + or goto header_non_available; + }) }) { + require urpm::xml_info; + require urpm::xml_info_pkg; + $urpm->{log}("getting information from $xml_info_file"); + my %nodes = eval { urpm::xml_info::get_nodes($xml_info, $xml_info_file, [ $name ]) }; + goto header_non_available if $@; + put_in_hash($xml_info_pkgs{$name} ||= {}, $nodes{$name}); + } else { + if ($xml_info eq 'info') { + $urpm->{info}(N("No xml info for medium \"%s\", only partial result for package %s", $medium->{name}, $name)); + } else { + $urpm->{error}(N("No xml info for medium \"%s\", unable to return any result for package %s", $medium->{name}, $name)); + } + } + } + + #- even if non-root, search for a header in the global cachedir + if (-s $local_source) { + $p->update_header($local_source) or do { + warn "Warning, could not extract header for $name from $medium!"; + goto header_non_available; + }; + my @files = $p->files; + @files = N("(none)") if !@files; + add2hash($pkg, { description => rpm_description($p->description), + files => \@files, + url => $p->url, + changelog => format_changelog_changelogs($o_installed_version, $p->changelogs) }); + $p->pack_header; # needed in order to call methods on objects outside ->traverse + } elsif ($xml_info_pkgs{$name}) { + if ($xml_info eq 'info') { + add2hash($pkg, { description => rpm_description($xml_info_pkgs{$name}{description}), + url => $xml_info_pkgs{$name}{url} + }); + } elsif ($xml_info eq 'files') { + my @files = map { chomp_(to_utf8($_)) } split("\n", $xml_info_pkgs{$name}{files}); + add2hash($pkg, { files => [ @files ? @files : N("(none)") ] }); + } elsif ($xml_info eq 'changelog') { + add2hash($pkg, { + changelog => format_changelog_changelogs($o_installed_version, + @{$xml_info_pkgs{$name}{changelogs}}) + }); + } + } else { + goto header_non_available; + } + return; + header_non_available: + add2hash($pkg, { summary => $p->summary || N("(Not available)"), description => undef }); + } +} + +sub find_installed_version { + my ($p) = @_; + my $version; + open_rpm_db()->traverse_tag_find('name', $p->name, sub { $version = $_[0]->EVR }); + $version || N("(none)"); +} + +my $canceled; +sub download_callback { + my ($gurpm, $mode, $file, $percent, $total, $eta, $speed) = @_; + $canceled = 0; + if ($mode eq 'start') { + $gurpm->label(N("Downloading package `%s'...", basename($file))); + $gurpm->validate_cancel(but(N("Cancel")), sub { $canceled = 1 }); + } elsif ($mode eq 'progress') { + $gurpm->label( + join("\n", + N("Downloading package `%s'...", basename($file)), + (defined $total && defined $eta ? + N(" %s%% of %s completed, ETA = %s, speed = %s", $percent, $total, $eta, $speed) + : N(" %s%% completed, speed = %s", $percent, $speed) + ) =~ /^\s*(.*)/ + ), + ); + #$gurpm->progress($percenti/100); + $gurpm->progress($percent); + } elsif ($mode eq 'end') { + $gurpm->progress(100); + $gurpm->invalidate_cancel; + } + !$canceled; +} + + +# -=-=-=---=-=-=---=-=-=-- install packages -=-=-=---=-=-=---=-=-=- + +my (@update_medias, $is_update_media_already_asked); + +sub warn_about_media { + my ($w, %options) = @_; + + return if $::MODE ne 'update'; + return if $::rpmdragora_options{'no-media-update'}; + + # we use our own instance of the urpmi db in order not to mess up with skip-list managment (#31092): + # and no need to fully configure urpmi since we may have to do it again anyway because of new media: + my $urpm = fast_open_urpmi_db(); + + my $_lock = urpm::lock::urpmi_db($urpm, undef, wait => $urpm->{options}{wait_lock}); + + # build media list: + @update_medias = get_update_medias($urpm); + + # do not update again media after installing/removing some packages: + $::rpmdragora_options{'no-media-update'} ||= 1; + + if (@update_medias > 0) { + if (!$options{skip_updating_mu} && !$is_update_media_already_asked) { + $is_update_media_already_asked = 1; + $::rpmdragora_options{'no-confirmation'} or interactive_msg(N("Confirmation"), +N("I need to contact the mirror to get latest update packages. +Please check that your network is currently running. + +Is it ok to continue?"), yesno => 1, + widget => gtknew('CheckButton', text => N("Do not ask me next time"), + active_ref => \$::rpmdragora_options{'no-confirmation'} + )) or myexit(-1); + writeconf(); + urpm::media::select_media($urpm, map { $_->{name} } @update_medias); + update_sources($urpm, noclean => 1, medialist => [ map { $_->{name} } @update_medias ]); + } + } else { + if (any { $_->{update} } @{$urpm->{media}}) { + interactive_msg(N("Already existing update media"), +N("You already have at least one update medium configured, but +all of them are currently disabled. You should run the Software +Media Manager to enable at least one (check it in the \"%s\" +column). + +Then, restart \"%s\".", N("Enabled"), $rpmdragora::myname_update)); + myexit(-1); + } + my ($mirror) = choose_mirror($urpm, transient => $w->{real_window} || $::main_window, + message => join("\n\n", + N("You have no configured update media. MageiaUpdate cannot operate without any update media."), + N("I need to contact the Mageia website to get the mirror list. +Please check that your network is currently running. + +Is it ok to continue?"), + ), + ); + my $m = ref($mirror) ? $mirror->{url} : ''; + $m or interactive_msg(N("How to choose manually your mirror"), +N("You may also choose your desired mirror manually: to do so, +launch the Software Media Manager, and then add a `Security +updates' medium. + +Then, restart %s.", $rpmdragora::myname_update)), myexit(-1); + add_distrib_update_media($urpm, $mirror, only_updates => 1); + } +} + + +sub get_parallel_group() { + $::rpmdragora_options{parallel} ? $::rpmdragora_options{parallel}[0] : undef; +} + +my ($count, $level, $limit, $new_stage, $prev_stage, $total); + +sub init_progress_bar { + my ($urpm) = @_; + undef $_ foreach $count, $prev_stage, $new_stage, $limit; + $level = 0.05; + $total = @{$urpm->{depslist}}; +} + +sub reset_pbar_count { + undef $prev_stage; + $count = 0; + $limit = $_[0]; +} + +sub update_pbar { + my ($gurpm) = @_; + return if !$total; # don't die if there's no source + $count++; + $new_stage = $level+($limit-$level)*$count/$total; + $prev_stage = 0 if(!defined($prev_stage)); + if ($prev_stage + 0.01*100 < $new_stage) { + $prev_stage = $new_stage; + $gurpm->progress($new_stage); + } +} + + +sub get_installed_packages { + my ($urpm, $db, $all_pkgs, $gurpm) = @_; + + $urpm->{global_config}{'prohibit-remove'} = '' if(!defined($urpm->{global_config}{'prohibit-remove'})); + my @base = ("basesystem", split /,\s*/, $urpm->{global_config}{'prohibit-remove'}); + my (%base, %basepackages, @installed_pkgs, @processed_base); + reset_pbar_count(0.33); + while (defined(local $_ = shift @base)) { + exists $basepackages{$_} and next; + $db->traverse_tag(m|^/| ? 'path' : 'whatprovides', [ $_ ], sub { + update_pbar($gurpm); + my $name = $_[0]->fullname; + # workaround looping in URPM: + return if member($name, @processed_base); + push @processed_base, $name; + push @{$basepackages{$_}}, $name; + push @base, $_[0]->requires_nosense; + }); + } + foreach (values %basepackages) { + my $n = @$_; #- count number of times it's provided + foreach (@$_) { + $base{$_} = \$n; + } + } + # costly: + $db->traverse(sub { + my ($pkg) = @_; + update_pbar($gurpm); + my $fullname = urpm_name($pkg); + return if $fullname =~ /@/; + $all_pkgs->{$fullname} = { + pkg => $pkg, urpm_name => $fullname, + } if !($all_pkgs->{$fullname} && $all_pkgs->{$fullname}{description}); + if (my $name = $base{$fullname}) { + $all_pkgs->{$fullname}{base} = \$name; + $pkg->set_flag_base(1) if $$name == 1; + } + push @installed_pkgs, $fullname; + $pkg->set_flag_installed; + $pkg->pack_header; # needed in order to call methods on objects outside ->traverse + }); + @installed_pkgs; +} + +urpm::select::add_packages_to_priority_upgrade_list('rpmdragora', 'perl-Glib', 'perl-Gtk2'); + +my ($priority_state, $priority_requested); +our $need_restart; + +our $probe_only_for_updates; + +sub get_updates_list { + my ($urpm, $db, $state, $requested, $requested_list, $requested_strict, $all_pkgs, %limit_preselect) = @_; + + $urpm->request_packages_to_upgrade( + $db, + $state, + $requested, + %limit_preselect + ); + + my %common_opts = ( + callback_choices => \&Rpmdragora::gui::callback_choices, + priority_upgrade => $urpm->{options}{'priority-upgrade'}, + ); + + if ($urpm->{options}{'priority-upgrade'}) { + $need_restart = + urpm::select::resolve_priority_upgrades_after_auto_select($urpm, $db, $state, + $requested, %common_opts); + } + + # list of updates (including those matching /etc/urpmi/skip.list): + @$requested_list = sort map { + my $name = urpm_name($_); + $all_pkgs->{$name} = { pkg => $_ }; + $name; + } @{$urpm->{depslist}}[keys %$requested]; + + # list of pure updates (w/o those matching /etc/urpmi/skip.list but with their deps): + if ($probe_only_for_updates && !$need_restart) { + @$requested_strict = sort map { + urpm_name($_); + } $urpm->resolve_requested($db, $state, $requested, callback_choices => \&Rpmdragora::gui::callback_choices); + + if (my @l = grep { $state->{selected}{$_->id} } + urpm::select::_priority_upgrade_pkgs($urpm, $urpm->{options}{'priority-upgrade'})) { + if (!$need_restart) { + $need_restart = + urpm::select::_resolve_priority_upgrades($urpm, $db, $state, $state->{selected}, + \@l, %common_opts); + } + } + } + + if ($need_restart) { + $requested_strict = [ map { scalar $_->fullname } @{$urpm->{depslist}}[keys %{$state->{selected}}] ]; + # drop non priority updates: + @$requested_list = (); + } + + # list updates including skiped ones + their deps in MageiaUpdate: + @$requested_list = uniq(@$requested_list, @$requested_strict); + + # do not pre select updates in rpmdragora: + @$requested_strict = () if !$probe_only_for_updates; +} + +sub get_pkgs { + my (%options) = @_; + my $w = $::main_window; + + my $gurpm = AdminPanel::Rpmdragora::gurpm->new(1 ? N("Please wait") : N("Package installation..."), N("Initializing..."), transient => $::main_window); + my $_gurpm_clean_guard = before_leaving { undef $gurpm }; + #my $_flush_guard = Gtk2::GUI_Update_Guard->new; + + warn_about_media($w, %options); + + my $urpm = open_urpmi_db(update => $probe_only_for_updates && !is_it_a_devel_distro()); + + my $_drop_lock = before_leaving { undef $urpm->{lock} }; + + $priority_up_alread_warned = 0; + + # update media list in case warn_about_media() added some: + @update_medias = get_update_medias($urpm); + + $gurpm->label(N("Reading updates description")); + $gurpm->progress(100); + + #- parse the description file + my $update_descr = urpm::get_updates_description($urpm, @update_medias); + + my $_unused = N("Please wait, finding available packages..."); + + # find out installed packages: + + init_progress_bar($urpm); + + $gurpm->label(N("Please wait, listing base packages...")); + $gurpm->progress($level*100); + + my $db = eval { open_rpm_db() }; + if (my $err = $@) { + interactive_msg(N("Error"), N("A fatal error occurred: %s.", $err)); + return; + } + + my $sig_handler = sub { undef $db; exit 3 }; + local $SIG{INT} = $sig_handler; + local $SIG{QUIT} = $sig_handler; + + $gurpm->label(N("Please wait, finding installed packages...")); + $gurpm->progress($level = 0.33*100); + reset_pbar_count(0.66*100); + my (@installed_pkgs, %all_pkgs); + if (!$probe_only_for_updates) { + @installed_pkgs = get_installed_packages($urpm, $db, \%all_pkgs, $gurpm); + } + + if (my $group = get_parallel_group()) { + urpm::media::configure($urpm, parallel => $group); + } + + # find out availlable packages: + + $urpm->{state} = {}; + + $gurpm->label(N("Please wait, finding available packages...")); + $gurpm->progress($level = 0.66*100); + + check_update_media_version($urpm, @update_medias); + + my $requested = {}; + my $state = {}; + my (@requested, @requested_strict); + + if ($compute_updates->[0] || $::MODE eq 'update') { + my %filter; + if ($options{pure_updates}) { + # limit to packages from update-media (dependencies can still come from other media) + %filter = (idlist => [ map { $_->{start} .. $_->{end} } @update_medias ]); + } + get_updates_list($urpm, $db, $state, $requested, \@requested, \@requested_strict, \%all_pkgs, %filter); + } + + if ($need_restart) { + $priority_state = $state; + $priority_requested = $requested; + } else { + ($priority_state, $priority_requested) = (); + } + + if (!$probe_only_for_updates) { + $urpm->compute_installed_flags($db); # TODO/FIXME: not for updates + $urpm->{depslist}[$_]->set_flag_installed foreach keys %$requested; #- pretend it's installed + } + $urpm->{rpmdragora_state} = $state; #- Don't forget it + $gurpm->progress($level = 0.7*100); + + my %l; + reset_pbar_count(1); + foreach my $pkg (@{$urpm->{depslist}}) { + update_pbar($gurpm); + $pkg->flag_upgrade or next; + my $key = $pkg->name . $pkg->arch; + $l{$key} = $pkg if !$l{$key} || $l{$key}->compare($pkg); + } + my @installable_pkgs = map { my $n = $_->fullname; $all_pkgs{$n} = { pkg => $_ }; $n } values %l; + undef %l; + + my @inactive_backports; + my @active_backports; + my @backport_medias = get_backport_media($urpm); + + foreach my $medium (@backport_medias) { + update_pbar($gurpm); + + # The 'searchmedia' flag differentiates inactive backport medias + # (because that option was passed to urpm::media::configure to + # temporarily enable them) + + my $backports = + $medium->{searchmedia} ? \@inactive_backports : \@active_backports; + + foreach my $pkg_id ($medium->{start} .. $medium->{end}) { + next if !$pkg_id; + my $pkg = $urpm->{depslist}[$pkg_id]; + $pkg->flag_upgrade or next; + my $name = $pkg->fullname; + push @$backports, $name; + $all_pkgs{$name} = { pkg => $pkg, is_backport => 1 }; + } + } + my @updates = @requested; + # selecting updates by default but skipped ones (MageiaUpdate only): + foreach (@requested_strict) { + $all_pkgs{$_}{selected} = 1; + } + + # urpmi only care about the first medium where it found the package, + # so there's no need to list the same package several time: + @installable_pkgs = uniq(difference2(\@installable_pkgs, \@updates)); + + my @meta_pkgs = grep { /^task-|^basesystem/ } keys %all_pkgs; + + my @gui_pkgs = map { chomp; $_ } cat_('/usr/share/rpmdrake/gui.lst'); + # add meta packages to GUI packages list (which expect basic names not fullnames): + push @gui_pkgs, map { (split_fullname($_))[0] } @meta_pkgs; + + +{ urpm => $urpm, + all_pkgs => \%all_pkgs, + installed => \@installed_pkgs, + installable => \@installable_pkgs, + updates => \@updates, + meta_pkgs => \@meta_pkgs, + gui_pkgs => [ grep { my $p = $all_pkgs{$_}{pkg}; $p && member(($p->fullname)[0], @gui_pkgs) } keys %all_pkgs ], + update_descr => $update_descr, + backports => [ @inactive_backports, @active_backports ], + inactive_backports => \@inactive_backports + }; +} + +sub display_READMEs_if_needed { + my ($urpm, $w) = @_; + return if !$urpm->{readmes}; + my %Readmes = %{$urpm->{readmes}}; + if (keys %Readmes) { #- display the README*.urpmi files + interactive_packtable( + N("Upgrade information"), + $w, + N("These packages come with upgrade information"), + [ map { + my $fullname = $_; + [ gtkpack__( + gtknew('HBox'), + gtkset_selectable(gtknew('Label', text => $Readmes{$fullname}),1), + ), + gtksignal_connect( + gtknew('Button', text => N("Upgrade information about this package")), + clicked => sub { + interactive_msg( + N("Upgrade information about package %s", $Readmes{$fullname}), + (join '' => map { s/$/\n/smg; $_ } formatAlaTeX(scalar cat_($fullname))), + scroll => 1, + ); + }, + ), + ] } keys %Readmes ], + [ gtknew('Button', text => N("Ok"), clicked => sub { Gtk2->main_quit }) ] + ); + } +} + +sub perform_parallel_install { + my ($urpm, $group, $w, $statusbar_msg_id) = @_; + my @pkgs = map { if_($_->flag_requested, urpm_name($_)) } @{$urpm->{depslist}}; + + my @error_msgs; + my $res = !run_program::run('urpmi', '2>', \@error_msgs, '-v', '--X', '--parallel', $group, @pkgs); + + if ($res) { + $$statusbar_msg_id = statusbar_msg( + #N("Everything installed successfully"), + N("All requested packages were installed successfully."), + ); + } else { + interactive_msg( + N("Problem during installation"), + N("There was a problem during the installation:\n\n%s", join("\n", @error_msgs)), + scroll => 1, + ); + } + open_rpm_db('force_sync'); + $w->set_sensitive(1); + return 0; +} + +sub perform_installation { #- (partially) duplicated from /usr/sbin/urpmi :-( + my ($urpm, $pkgs) = @_; + + my @error_msgs; + my $statusbar_msg_id; + my $gurpm; + local $urpm->{fatal} = sub { + my $fatal_msg = $_[1]; + printf STDERR "Fatal: %s\n", $fatal_msg; + undef $gurpm; + interactive_msg(N("Installation failed"), + N("There was a problem during the installation:\n\n%s", $fatal_msg)); + goto return_with_exit_code; + }; + local $urpm->{error} = sub { printf STDERR "Error: %s\n", $_[0]; push @error_msgs, $_[0] }; + + my $w = $::main_window; + #$w->set_sensitive(0); + #my $_restore_sensitive = before_leaving { $w->set_sensitive(1) }; + + # my $_flush_guard = Gtk2::GUI_Update_Guard->new; + + if (my $group = get_parallel_group()) { + return perform_parallel_install($urpm, $group, $w, \$statusbar_msg_id); + } + + my ($lock, $rpm_lock); + if (!$::env) { + $lock = urpm::lock::urpmi_db($urpm, undef, wait => $urpm->{options}{wait_lock}); + $rpm_lock = urpm::lock::rpm_db($urpm, 'exclusive'); + } + my $state = $priority_state || $probe_only_for_updates ? { } : $urpm->{rpmdragora_state}; + + my $bar_id = statusbar_msg(N("Checking validity of requested packages..."), 0); + + # FIXME: THIS SET flag_requested on all packages!!!! + # select packages to install / enssure selected pkg set is consistant: + my %saved_flags; + my $requested = { map { + $saved_flags{$_->id} = $_->flag_requested; + $_->id => undef; + } grep { $_->flag_selected } @{$urpm->{depslist}} }; + urpm::select::resolve_dependencies( + $urpm, $state, $requested, + rpmdb => $::env && "$::env/rpmdb.cz", + callback_choices => \&Rpmdragora::gui::callback_choices, + ); + statusbar_msg_remove($bar_id); + + my ($local_sources, $blist) = urpm::get_pkgs::selected2local_and_blists($urpm, $state->{selected}); + if (!$local_sources && (!$blist || !@$blist)) { + interactive_msg( + N("Unable to get source packages."), + N("Unable to get source packages, sorry. %s", + @error_msgs ? N("\n\nError(s) reported:\n%s", join("\n", @error_msgs)) : ''), + scroll => 1, + ); + goto return_with_exit_code; + } + + my @to_install = @{$urpm->{depslist}}[keys %{$state->{selected}}]; + my @pkgs = map { scalar($_->fullname) } sort(grep { $_->flag_selected } @to_install); + + @{$urpm->{ask_remove}} = sort(urpm::select::removed_packages($urpm->{state})); + my @to_remove = map { if_($pkgs->{$_}{selected} && !$pkgs->{$_}{pkg}->flag_upgrade, $pkgs->{$_}{urpm_name}) } keys %$pkgs; + + my $r = format_list(map { scalar(urpm::select::translate_why_removed_one($urpm, $urpm->{state}, $_)) } @to_remove); + + my ($size, $filesize) = $urpm->selected_size_filesize($state); + my $install_count = int(@pkgs); + my $to_install = $install_count == 0 ? '' : + ($priority_state ? '' . N("Rpmdragora or one of its priority dependencies needs to be updated first. Rpmdragora will then restart.") . '' . "\n\n" : '') . + (P("The following package is going to be installed:", "The following %d packages are going to be installed:", $install_count, $install_count) + . "\n\n" . format_list(map { s!.*/!!; $_ } @pkgs)); + my $remove_count = scalar(@to_remove); + interactive_msg(($to_install ? N("Confirmation") : N("Some packages need to be removed")), + join("\n\n", + ($r ? + (!$to_install ? (P("Remove one package?", "Remove %d packages?", $remove_count, $remove_count), $r) : + (($remove_count == 1 ? + N("The following package has to be removed for others to be upgraded:") + : N("The following packages have to be removed for others to be upgraded:")), $r), if_($to_install, $to_install)) + : $to_install), + format_size($size), + format_filesize($filesize), + N("Is it ok to continue?")), + scroll => 1, + yesno => 1) or return 1; + + my $_umount_guard = before_leaving { urpm::removable::try_umounting_removables($urpm) }; + + # select packages to uninstall for !update mode: + perform_removal($urpm, { map { $_ => $pkgs->{$_} } @to_remove }) if !$probe_only_for_updates; + + # $gurpm = Rpmdragora::gurpm->new(1 ? N("Please wait") : N("Package installation..."), N("Initializing..."), transient => $::main_window); + # my $_gurpm_clean_guard = before_leaving { undef $gurpm }; + my $something_installed; + + if (@to_install && $::rpmdragora_options{auto_orphans}) { + urpm::orphans::compute_future_unrequested_orphans($urpm, $state); + if (my @orphans = map { scalar $_->fullname } @{$state->{orphans_to_remove}}) { + interactive_msg(N("Orphan packages"), P("The following orphan package will be removed.", + "The following orphan packages will be removed.", scalar(@orphans)) + . "\n" . urpm::orphans::add_leading_spaces(join("\n", @orphans) . "\n"), scroll => 1); + } + } + + urpm::orphans::mark_as_requested($urpm, $state, 0); + + my ($progress, $total, @rpms_upgrade); + my $transaction; + my ($progress_nb, $transaction_progress_nb, $remaining, $done); + my $callback_inst = sub { + my ($urpm, $type, $id, $subtype, $amount, $total) = @_; + my $pkg = defined $id ? $urpm->{depslist}[$id] : undef; + if ($subtype eq 'start') { + if ($type eq 'trans') { + print(1 ? N("Preparing package installation...") : N("Preparing package installation transaction...")); + # $gurpm->label(1 ? N("Preparing package installation...") : N("Preparing package installation transaction...")); + } elsif (defined $pkg) { + $something_installed = 1; + print(N("Installing package `%s' (%s/%s)...", $pkg->name, ++$transaction_progress_nb, scalar(@{$transaction->{upgrade}}))."\n" . N("Total: %s/%s", ++$progress_nb, $install_count)); + # $gurpm->label(N("Installing package `%s' (%s/%s)...", $pkg->name, ++$transaction_progress_nb, scalar(@{$transaction->{upgrade}})) + # . "\n" . N("Total: %s/%s", ++$progress_nb, $install_count)); + } + } elsif ($subtype eq 'progress') { + $gurpm->progress($total ? ($amount/$total)*100 : 100); + print("Progress: ".($total ? ($amount/$total)*100 : 100)."\n"); + } + }; + + # FIXME: sometimes state is lost: + my @ask_unselect = urpm::select::unselected_packages($state); + + # fix flags for orphan computing: + foreach (keys %{$state->{selected}}) { + my $pkg = $urpm->{depslist}[$_]; + $pkg->set_flag_requested($saved_flags{$pkg->id}); + } + my $exit_code = + urpm::main_loop::run($urpm, $state, 1, \@ask_unselect, + { + completed => sub { + # explicitly destroy the progress window when it's over; we may + # have sg to display before returning (errors, rpmnew/rpmsave, ...): + undef $gurpm; + + undef $lock; + undef $rpm_lock; + }, + inst => $callback_inst, + trans => $callback_inst, + ask_yes_or_no => sub { + # handle 'allow-force' and 'allow-nodeps' options: + my ($title, $msg) = @_; + local $::main_window = $gurpm->{real_window}; + interactive_msg($title, $msg, yesno => 1, scroll => 1, + ); + }, + message => sub { + my ($title, $message) = @_; + interactive_msg($title, $message, scroll => 1); + }, + # cancel installation when 'cancel' button is pressed: + trans_log => sub { download_callback($gurpm, @_) or goto return_with_exit_code }, + post_extract => sub { + my ($set, $transaction_sources, $transaction_sources_install) = @_; + $transaction = $set; + $transaction_progress_nb = 0; + $done += grep { !/\.src\.rpm$/ } values %$transaction_sources; #updates + $total = keys(%$transaction_sources_install) + keys %$transaction_sources; + push @rpms_upgrade, keys %$transaction_sources; + $done += grep { !/\.src\.rpm$/ } values %$transaction_sources_install; # installs + }, + pre_removable => sub { + # Gtk2::GUI_Update_Guard->new use of alarm() kill us when + # running system(), thus making DVD being ejected and printing + # wrong error messages (#30463) + + local $SIG{ALRM} = sub { die "ALARM" }; + $remaining = alarm(0); + }, + + post_removable => sub { alarm $remaining }, + copy_removable => sub { + my ($medium) = @_; + interactive_msg( + N("Change medium"), + N("Please insert the medium named \"%s\"", $medium), + yesno => 1, text => { no => N("Cancel"), yes => N("Ok") }, + ); + }, + pre_check_sig => sub { $gurpm->label(N("Verifying package signatures...")) }, + check_sig => sub { $gurpm->progress((++$progress/$total)*100) }, + bad_signature => sub { + my ($msg, $msg2) = @_; + local $::main_window = $gurpm->{real_window}; + $msg =~ s/:$/\n\n/m; # FIXME: to be fixed in urpmi after 2008.0 + interactive_msg( + N("Warning"), "$msg\n\n$msg2", yesno => 1, if_(10 < ($msg =~ tr/\n/\n/), scroll => 1), + ); + }, + post_download => sub { + $canceled and goto return_with_exit_code; + $gurpm->invalidate_cancel_forever; + }, + need_restart => sub { + my ($need_restart_formatted) = @_; + # FIXME: offer to restart the system + interactive_msg(N("Warning"), join("\n", values %$need_restart_formatted), scroll => 1); + }, + trans_error_summary => sub { + my ($nok, $errors) = @_; + interactive_msg( + N("Problem during installation"), + if_($nok, N("%d installation transactions failed", $nok) . "\n\n") . + N("There was a problem during the installation:\n\n%s", + join("\n\n", @$errors, @error_msgs)), + scroll => 1, + ); + }, + need_restart => sub { + my ($need_restart_formatted) = @_; + interactive_msg(N("Warning"), + join("\n\n", values %$need_restart_formatted)); + }, + success_summary => sub { + if (!($done || @to_remove)) { + interactive_msg(N("Error"), + N("Unrecoverable error: no package found for installation, sorry.")); + return; + } + my $id = statusbar_msg(N("Inspecting configuration files..."), 0); + my %pkg2rpmnew; + foreach my $id (@rpms_upgrade) { + my $pkg = $urpm->{depslist}[$id]; + next if $pkg->arch eq 'src'; + $pkg2rpmnew{$pkg->fullname} = [ grep { -r "$_.rpmnew" || -r "$_.rpmsave" } $pkg->conf_files ]; + } + statusbar_msg_remove($id); + dialog_rpmnew(N("The installation is finished; everything was installed correctly. + +Some configuration files were created as `.rpmnew' or `.rpmsave', +you may now inspect some in order to take actions:"), + %pkg2rpmnew) + and statusbar_msg(N("All requested packages were installed successfully."), 1); + statusbar_msg(N("Looking for \"README\" files..."), 1); + display_READMEs_if_needed($urpm, $w); + }, + already_installed_or_not_installable => sub { + my ($msg1, $msg2) = @_; + my $msg = join("\n", @$msg1, @$msg2); + return if !$msg; # workaround missing state + interactive_msg(N("Error"), $msg); + }, + }, + ); + + #- restart rpmdragora if needed, keep command line for that. + if ($need_restart && !$exit_code && $something_installed) { + log::explanations("restarting rpmdragora"); + #- it seems to work correctly with exec instead of system, provided we stop timers + #- added --previous-priority-upgrade to allow checking if yet if + #- priority-upgrade list has changed. and make sure we don't uselessly restart + my @argv = ('--previous-priority-upgrade=' . $urpm->{options}{'priority-upgrade'}, + grep { !/^--no-priority-upgrade$|--previous-priority-upgrade=/ } @Rpmdragora::init::ARGV_copy); + # remove "--emmbedded " from argv: + my $i = 0; + foreach (@argv) { + splice @argv, $i, 2 if /^--embedded$/; + $i++; + } + alarm(0); + # remember not to ask again questions and the like: + writeconf(); + exec($0, @argv); + exit(0); + } + + my $_s1 = N("RPM transaction %d/%d", 0, 0); + my $_s2 = N("Unselect all"); + my $_s3 = N("Details"); + + statusbar_msg_remove($statusbar_msg_id); #- XXX maybe remove this + + if ($exit_code == 0 && !$::rpmdragora_options{auto_orphans}) { + if (urpm::orphans::check_unrequested_orphans_after_auto_select($urpm)) { + if (my $msg = urpm::orphans::get_now_orphans_gui_msg($urpm)) { + interactive_msg(N("Orphan packages"), $msg, scroll => 1); + } + } + } + + return_with_exit_code: + return !($something_installed || scalar(@to_remove)); +} + + +# -=-=-=---=-=-=---=-=-=-- remove packages -=-=-=---=-=-=---=-=-=- + +sub perform_removal { + my ($urpm, $pkgs) = @_; + my @toremove = map { if_($pkgs->{$_}{selected}, $pkgs->{$_}{urpm_name}) } keys %$pkgs; + return if !@toremove; + my $gurpm = Rpmdragora::gurpm->new(1 ? N("Please wait") : N("Please wait, removing packages..."), N("Initializing..."), transient => $::main_window); + my $_gurpm_clean_guard = before_leaving { undef $gurpm }; + + my $may_be_orphans = 1; + urpm::orphans::unrequested_orphans_after_remove($urpm, \@toremove) + or $may_be_orphans = 0; + + my $progress = -1; + local $urpm->{log} = sub { + my $str = $_[0]; + print $str; + $progress++; + return if $progress <= 0; # skip first "creating transaction..." message + $gurpm->label($str); # display "removing package %s" + $gurpm->progress(min(0.99*100, scalar($progress/@toremove)*100)); + #gtkflush(); + }; + + my @results; + slow_func_statusbar( + N("Please wait, removing packages..."), + $::main_window, + sub { + @results = $::rpmdragora_options{parallel} + ? urpm::parallel::remove($urpm, \@toremove) + : urpm::install::install($urpm, \@toremove, {}, {}, + callback_report_uninst => sub { $gurpm->label($_[0]) }, + ); + open_rpm_db('force_sync'); + }, + ); + if (@results) { + interactive_msg( + N("Problem during removal"), + N("There was a problem during the removal of packages:\n\n%s", join("\n", @results)), + if_(@results > 1, scroll => 1), + ); + return 1; + } else { + if ($may_be_orphans && !$::rpmdragora_options{auto_orphans}) { + if (my $msg = urpm::orphans::get_now_orphans_gui_msg($urpm)) { + interactive_msg(N("Information"), $msg, scroll => 1); + } + } + return 0; + } +} + +1; diff --git a/lib/AdminPanel/Rpmdragora/rpmnew.pm b/lib/AdminPanel/Rpmdragora/rpmnew.pm new file mode 100644 index 00000000..3c4335d0 --- /dev/null +++ b/lib/AdminPanel/Rpmdragora/rpmnew.pm @@ -0,0 +1,205 @@ +# vim: set et ts=4 sw=4: +package AdminPanel::Rpmdragora::rpmnew; +#***************************************************************************** +# +# Copyright (c) 2002 Guillaume Cottenceau +# Copyright (c) 2002-2007 Thierry Vignaud +# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA +# Copyright (c) 2005-2007 Mandriva SA +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** +# +# $Id: rpmnew.pm 263914 2009-12-03 17:41:02Z tv $ + +use strict; +use lib qw(/usr/lib/libDrakX); +use common; +use AdminPanel::rpmdragora; +use AdminPanel::Rpmdragora::init; +use AdminPanel::Rpmdragora::pkg; +use AdminPanel::Rpmdragora::open_db; +use AdminPanel::Rpmdragora::formatting; +use Exporter; +our @ISA = qw(Exporter); +our @EXPORT = qw(dialog_rpmnew do_merge_if_needed); + +# /var/lib/nfs/etab /var/lib/nfs/rmtab /var/lib/nfs/xtab /var/cache/man/whatis +my %ignores_rpmnew = map { $_ => 1 } qw( + /etc/adjtime + /etc/fstab + /etc/group + /etc/ld.so.conf + /etc/localtime + /etc/modules + /etc/passwd + /etc/security/fileshare.conf + /etc/shells + /etc/sudoers + /etc/sysconfig/alsa + /etc/sysconfig/autofsck + /etc/sysconfig/harddisks + /etc/sysconfig/harddrake2/previous_hw + /etc/sysconfig/init + /etc/sysconfig/installkernel + /etc/sysconfig/msec + /etc/sysconfig/nfs + /etc/sysconfig/pcmcia + /etc/sysconfig/rawdevices + /etc/sysconfig/saslauthd + /etc/sysconfig/syslog + /etc/sysconfig/usb + /etc/sysconfig/xinetd +); + +sub inspect { + my ($file) = @_; + my ($rpmnew, $rpmsave) = ("$file.rpmnew", "$file.rpmsave"); + my @inspect_wsize = ($typical_width*2.5, 500); + my $rpmfile = 'rpmnew'; + -r $rpmnew or $rpmfile = 'rpmsave'; + -r $rpmnew && -r $rpmsave && (stat $rpmsave)[9] > (stat $rpmnew)[9] and $rpmfile = 'rpmsave'; + $rpmfile eq 'rpmsave' and $rpmnew = $rpmsave; + + foreach (qw(LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT LC_IDENTIFICATION LC_ALL)) { + local $ENV{$_} = $ENV{$_} . '.UTF-8' if $ENV{$_} && $ENV{$_} !~ /UTF-8/; + } + my @diff = map { ensure_utf8($_); $_ } `/usr/bin/diff -u '$file' '$rpmnew'`; + @diff = N("(none)") if !@diff; + my $d = ugtk2->new(N("Inspecting %s", $file), grab => 1, transient => $::main_window); + my $save_wsize = sub { @inspect_wsize = $d->{rwindow}->get_size }; + my %texts; + require Gtk2::SourceView2; + my $lang_manager = Gtk2::SourceView2::LanguageManager->get_default; + gtkadd( + $d->{window}, + gtkpack_( + gtknew('VBox', spacing => 5), + 1, create_vpaned( + create_vpaned( + gtkpack_( + gtknew('VBox'), + 0, gtknew('Label', text_markup => qq($file:)), + 1, gtknew('ScrolledWindow', child => $texts{file} = Gtk2::SourceView2::View->new), + ), + gtkpack_( + gtknew('VBox'), + 0, gtknew('Label', text_markup => qq($rpmnew:)), + 1, gtknew('ScrolledWindow', child => $texts{rpmnew} = Gtk2::SourceView2::View->new), + ), + resize1 => 1, + ), + gtkpack_( + gtknew('VBox'), + 0, gtknew('Label', text => N("Changes:")), + 1, gtknew('ScrolledWindow', child => $texts{diff} = Gtk2::SourceView2::View->new), + ), + resize1 => 1, + ), + 0, Gtk2::HSeparator->new, + 0, gtknew('WrappedLabel', + # prevent bad sizing of Gtk2::WrappedLabel: + width => $inspect_wsize[0], + text => N("You can either remove the .%s file, use it as main file or do nothing. If unsure, keep the current file (\"%s\").", + $rpmfile, N("Remove .%s", $rpmfile)), + ), + 0, gtkpack__( + gtknew('HButtonBox'), + gtksignal_connect( + gtknew('Button', text => N("Remove .%s", $rpmfile)), + clicked => sub { $save_wsize->(); unlink $rpmnew; Gtk2->main_quit }, + ), + gtksignal_connect( + gtknew('Button', text => N("Use .%s as main file", $rpmfile)), + clicked => sub { $save_wsize->(); renamef($rpmnew, $file); Gtk2->main_quit }, + ), + gtksignal_connect( + gtknew('Button', text => N("Do nothing")), + clicked => sub { $save_wsize->(); Gtk2->main_quit }, + ), + ) + ) + ); + my %files = (file => $file, rpmnew => $rpmnew); + foreach (keys %files) { + gtktext_insert($texts{$_}, [ [ scalar(cat_($files{$_})), { 'font' => 'monospace' } ] ]); + my $lang = $lang_manager->guess_language($files{$_}); + $lang ||= $lang_manager->get_language('sh'); + my $buffer = $texts{$_}->get_buffer; + $buffer->set_language($lang) if $lang; + } + gtktext_insert($texts{diff}, [ [ join('', @diff), { 'font' => 'monospace' } ] ]); + my $buffer = $texts{diff}->get_buffer; + my $lang = $lang_manager->get_language('diff'); + $buffer->set_language($lang) if $lang; + $d->{rwindow}->set_default_size(@inspect_wsize); + $d->main; +} + +sub dialog_rpmnew { + my ($msg, %p2r) = @_; + @{$p2r{$_}} = grep { !$ignores_rpmnew{$_} } @{$p2r{$_}} foreach keys %p2r; + my $sum_rpmnew = sum(map { int @{$p2r{$_}} } keys %p2r); + $sum_rpmnew == 0 and return 1; + interactive_packtable( + N("Installation finished"), + $::main_window, + $msg, + [ map { my $pkg = $_; + map { + my $f = $_; + my $b; + [ gtkpack__( + gtknew('HBox'), + gtkset_markup( + gtkset_selectable(gtknew('Label'), 1), + qq($pkg:$f), + ) + ), + gtksignal_connect( + $b = gtknew('Button', text => N("Inspect...")), + clicked => sub { + inspect($f); + -r "$f.rpmnew" || -r "$f.rpmsave" or $b->set_sensitive(0); + }, + ) ]; + } @{$p2r{$pkg}}; + } keys %p2r ], + [ gtknew('Button', text => N("Ok"), + clicked => sub { Gtk2->main_quit }) ] + ); + return 0; +} + + +sub do_merge_if_needed() { + if ($rpmdragora_options{'merge-all-rpmnew'}) { + my %pkg2rpmnew; + my $wait = wait_msg(N("Please wait, searching...")); + print "Searching .rpmnew and .rpmsave files...\n"; + # costly: + open_rpm_db()->traverse(sub { + my $n = my_fullname($_[0]); + $pkg2rpmnew{$n} = [ grep { m|^/etc| && (-r "$_.rpmnew" || -r "$_.rpmsave") } map { chomp_($_) } $_[0]->conf_files ]; + }); + print "done.\n"; + undef $wait; + $typical_width = 330; + dialog_rpmnew('', %pkg2rpmnew) and print "Nothing to do.\n"; + myexit(0); + } +} + +1; diff --git a/lib/AdminPanel/Rpmdragora/widgets.pm b/lib/AdminPanel/Rpmdragora/widgets.pm new file mode 100644 index 00000000..84844069 --- /dev/null +++ b/lib/AdminPanel/Rpmdragora/widgets.pm @@ -0,0 +1,52 @@ +# vim: set et ts=4 sw=4: +package Gtk2::Mdv::TextView; +#***************************************************************************** +# +# Copyright (c) 2002 Guillaume Cottenceau +# Copyright (c) 2002-2007 Thierry Vignaud +# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA +# Copyright (c) 2005-2007 Mandriva SA +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** +# +# $Id: widgets.pm 233986 2008-02-06 14:14:06Z tv $ + +use strict; +use MDK::Common::Func 'any'; +use lib qw(/usr/lib/libDrakX); + +use Time::HiRes; +use feature 'state'; + + +sub new { + my ($_class) = @_; + my $w = gtknew('TextView', editable => 0); + state $time; + $w->signal_connect(size_allocate => sub { + my ($w, $requisition) = @_; + return if !ref($w->{anchors}); + return if Time::HiRes::clock_gettime() - $time < 0.200; + $time = Time::HiRes::clock_gettime(); + foreach my $anchor (@{$w->{anchors}}) { + $_->set_size_request($requisition->width-30, -1) foreach $anchor->get_widgets; + } + 1; + }); + $w; +} + +1; diff --git a/lib/AdminPanel/SettingsReader.pm b/lib/AdminPanel/SettingsReader.pm new file mode 100644 index 00000000..d93ebd57 --- /dev/null +++ b/lib/AdminPanel/SettingsReader.pm @@ -0,0 +1,45 @@ +# vim: set et ts=4 sw=4: +# Copyright 2012 Angelo Naselli +# +# This file is part of AdminPanel +# +# AdminPanel is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# AdminPanel is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with AdminPanel. If not, see . + + +#Class SettingsReader +package AdminPanel::SettingsReader; + +use strict; +use warnings; +use diagnostics; +use XML::Simple; +use Data::Dumper; + +sub new { + my ($class, $fileName) = @_; + + my $self = { + my $settings = 0, + my $justToGetRidOfERROR = 0 + }; + bless $self, 'AdminPanel::SettingsReader'; + + my $xml = new XML::Simple (KeyAttr=>[]); + $self->{settings} = $xml->XMLin($fileName); + + return $self->{settings}; +} + + +1; diff --git a/lib/AdminPanel/Shared.pm b/lib/AdminPanel/Shared.pm new file mode 100644 index 00000000..583b214c --- /dev/null +++ b/lib/AdminPanel/Shared.pm @@ -0,0 +1,712 @@ +#!/usr/bin/perl +# vim: set et ts=4 sw=4: +# Copyright 2012-2013 Angelo Naselli +# +# This file is part of AdminPanel +# +# AdminPanel is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# AdminPanel is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with AdminPanel. If not, see . + +package AdminPanel::Shared; + +=head1 NAME + +AdminPanel::Shared - AdminPanel::Shared contains all the shared routines + needed by AdminPanel and modules + +=head1 SYNOPSIS + + + +=head1 DESCRIPTION + +This module collects all the routines shared between AdminPanel and its modules. + +=head1 EXPORT + + warningMsgBox + msgBox + infoMsgBox + ask_YesOrNo + ask_OkCancel + AboutDialog + trim + + +=head1 SUPPORT + +You can find documentation for this module with the perldoc command: + + perldoc AdminPanel::Shared + +=head1 AUTHOR + +Angelo Naselli + +=head1 COPYRIGHT and LICENSE + +Copyright (C) 2013, Angelo Naselli. + +This file is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This file is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this file. If not, see . + +=head1 FUNCTIONS + +=cut + +use strict; +use warnings; +use diagnostics; + +use lib qw(/usr/lib/libDrakX); +use common qw(N + N_); +use yui; +use base qw(Exporter); + +# TODO move GUI dialogs to Shared::GUI +our @EXPORT = qw( + warningMsgBox + msgBox + infoMsgBox + ask_YesOrNo + ask_OkCancel + ask_fromList + AboutDialog + trim + member +); + + +=head1 VERSION + +Version 0.01 + +=cut + +our $VERSION = '0.01'; + +our $License = N_("This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +"); + + +#============================================================= + +=head2 warningMsgBox + +=head3 INPUT + + $st: string to be swhon into the dialog + +=head3 DESCRIPTION + +This function creates an Warning dialog and show the message +passed as input. + +=cut + +#============================================================= + +sub warningMsgBox { + my ($st) = @_; + my $factory = yui::YUI::widgetFactory; + my $msg_box = $factory->createPopupDialog($yui::YDialogWarnColor); + my $layout = $factory->createVBox($msg_box); + my $align = $factory->createAlignment($layout, 3, 0); + $factory->createLabel( $align, $st, 1, 0); + $align = $factory->createAlignment($layout, 3, 0); + $factory->createPushButton($align, N("Ok")); + $msg_box->waitForEvent(); + + destroy $msg_box; +} + +#============================================================= + +=head2 infoMsgBox + +=head3 INPUT + + $st: string to be swhon into the dialog + +=head3 DESCRIPTION + +This function creates an Info dialog and show the message +passed as input. + +=cut + +#============================================================= + +sub infoMsgBox { + my ($st) = @_; + my $factory = yui::YUI::widgetFactory; + my $msg_box = $factory->createPopupDialog($yui::YDialogInfoColor); + my $layout = $factory->createVBox($msg_box); + my $align = $factory->createAlignment($layout, 3, 0); + $factory->createLabel( $align, $st, 1, 0); + $align = $factory->createAlignment($layout, 3, 0); + $factory->createPushButton($align, N("Ok")); + $msg_box->waitForEvent(); + + destroy $msg_box; +} + +#============================================================= + +=head2 msgBox + +=head3 INPUT + + $st: string to be swhon into the dialog + +=head3 DESCRIPTION + +This function creates a dialog and show the message passed as input. + +=cut + +#============================================================= + +sub msgBox { + my ($st) = @_; + my $factory = yui::YUI::widgetFactory; + my $msg_box = $factory->createPopupDialog($yui::YDialogNormalColor); + my $layout = $factory->createVBox($msg_box); + my $align = $factory->createAlignment($layout, 3, 0); + $factory->createLabel( $align, $st, 1, 0); + $align = $factory->createAlignment($layout, 3, 0); + $factory->createPushButton($align, N("Ok")); + $msg_box->waitForEvent(); + + destroy $msg_box; +} + +#============================================================= + +=head2 ask_OkCancel + +=head3 INPUT + + $title: Title shown as heading + $text: text to be shown into the dialog + +=head3 OUTPUT + + 0: Cancel button has been pressed + 1: Ok button has been pressed + +=head3 DESCRIPTION + +This function create an OK-Cancel dialog with a 'title' and a +'text' passed as parameters. + +=cut + +#============================================================= + +sub ask_OkCancel { + my ($title, $text) = @_; + my $retVal = 0; + my $factory = yui::YUI::widgetFactory; + + my $msg_box = $factory->createPopupDialog($yui::YDialogNormalColor); + my $layout = $factory->createVBox($msg_box); + + my $align = $factory->createAlignment($layout, 3, 0); + ## title with headings true + $factory->createLabel( $align, $title, 1, 0); + $align = $factory->createLeft($layout); + $factory->createLabel( $align, $text, 0, 0); + + $align = $factory->createRight($layout); + my $hbox = $factory->createHBox($align); + my $okButton = $factory->createPushButton($hbox, N("Ok")); + my $cancelButton = $factory->createPushButton($hbox, N("Cancel")); + + my $event = $msg_box->waitForEvent(); + + my $eventType = $event->eventType(); + + if ($eventType == $yui::YEvent::WidgetEvent) { + # widget selected + my $widget = $event->widget(); + $retVal = ($widget == $okButton) ? 1 : 0; + } + + destroy $msg_box; + + return $retVal; +} + +#============================================================= + +=head2 ask_YesOrNo + +=head3 INPUT + + $title: Title shown as heading + $text: question text to be shown into the dialog + +=head3 OUTPUT + + 0: "No" button has been pressed + 1: "Yes" button has been pressed + +=head3 DESCRIPTION + +This function create a Yes-No dialog with a 'title' and a +question 'text' passed as parameters. + +=cut + +#============================================================= + +sub ask_YesOrNo { + my ($title, $text) = @_; + my $retVal = 0; + my $factory = yui::YUI::widgetFactory; + + my $msg_box = $factory->createPopupDialog($yui::YDialogNormalColor); + my $layout = $factory->createVBox($msg_box); + + my $align = $factory->createAlignment($layout, 3, 0); + ## title with headings true + $factory->createLabel( $align, $title, 1, 0); + $align = $factory->createLeft($layout); + $factory->createLabel( $align, $text, 0, 0); + + $align = $factory->createRight($layout); + my $hbox = $factory->createHBox($align); + my $yesButton = $factory->createPushButton($hbox, N("Yes")); + my $noButton = $factory->createPushButton($hbox, N("No")); + + my $event = $msg_box->waitForEvent(); + + my $eventType = $event->eventType(); + + if ($eventType == $yui::YEvent::WidgetEvent) { + # widget selected + my $widget = $event->widget(); + $retVal = ($widget == $yesButton) ? 1 : 0; + } + + destroy $msg_box; + + return $retVal; +} + + +#============================================================= + +=head2 ask_fromList + +=head3 INPUT + + $title: dialog title + $text: combobox heading + $list: item list + +=head3 OUTPUT + + undef: if Cancel button has been pressed + selected item: if Ok button has been pressed + +=head3 DESCRIPTION + +This function create a dialog with a combobox in which to +choose an item from a given list. + +=cut + +#============================================================= + +sub ask_fromList { + my ($title, $text, $list) = @_; + + die "Title is mandatory" if (! $title); + die "Heading is mandatory" if (! $text); + die "List is mandatory" if (! $list ); + die "At least one element is mandatory into list" if (scalar(@$list) < 1); + + my $choice = undef; + my $factory = yui::YUI::widgetFactory; + + ## push application title + my $appTitle = yui::YUI::app()->applicationTitle(); + ## set new title to get it in dialog + yui::YUI::app()->setApplicationTitle($title); + + my $dlg = $factory->createPopupDialog($yui::YDialogNormalColor); + my $layout = $factory->createVBox($dlg); + + my $combo = $factory->createComboBox($layout, $text, 0); + my $itemColl = new yui::YItemCollection; + foreach (@$list) { + my $item = new yui::YItem ($_, 0); + $itemColl->push($item); + $item->DISOWN(); + } + $combo->addItems($itemColl); + + my $align = $factory->createRight($layout); + my $hbox = $factory->createHBox($align); + my $okButton = $factory->createPushButton($hbox, N("Ok")); + my $cancelButton = $factory->createPushButton($hbox, N("Cancel")); + + while (1) { + my $event = $dlg->waitForEvent(); + + my $eventType = $event->eventType(); + #event type checking + if ($eventType == $yui::YEvent::CancelEvent) { + last; + } + elsif ($eventType == $yui::YEvent::WidgetEvent) { + # widget selected + my $widget = $event->widget(); + + if ($widget == $cancelButton) { + last; + } + elsif ($widget == $okButton) { + my $item = $combo->selectedItem(); + $choice = $item->label() if ($item); + last; + } + } + } + + destroy $dlg; + + #restore old application title + yui::YUI::app()->setApplicationTitle($appTitle); + + return $choice; +} + + +#============================================================= + +=head2 AboutDialog + +=head3 INPUT + + $opts: optional options needed to get info for dialog. + name => Application Name, + version => Application Version, + copyright => Copyright ususally like "Copyright (C) copyright-holder Year", + license => License text, + comments => A comment related to application to be shown, + website => Web site URL, + website_label => Label to hide previous link, + authors => Application authors, + translator_credits => Application translators + documenters => Application documenters + artists => Graphic applicaton designers + logo => picture path to be shown as application logo + +=head3 OUTPUT + + Output_Parameter: out_par_description + +=head3 DESCRIPTION + +About dialog implementation, this dialog can be used by +modules, to show authors, license, credits, etc. + +=cut + +#============================================================= + +sub AboutDialog { + my ($opts) = @_; + + # Credits dialog + sub Credits { + my ($opts) = @_; + + my $factory = yui::YUI::widgetFactory; + my $optional = yui::YUI::optionalWidgetFactory; + + my $creditsdlg = $factory->createPopupDialog(); + my $layout = $factory->createVBox($creditsdlg); + + # header + $factory->createHBox($layout); + my $hbox = $factory->createHBox($layout); + my $align = $factory->createHVCenter($hbox); + $hbox = $factory->createHBox($align); + $factory->createHeading($hbox, N("Credits")); + + # Credits tab widget + if ($optional->hasDumbTab()) { + $hbox = $factory->createHBox($layout); + $align = $factory->createAlignment($hbox, 3, 0); + my $dumptab = $optional->createDumbTab($align); + my $item = new yui::YItem(N("Written by")); + $item->setSelected(); + $dumptab->addItem( $item ); + $item->DISOWN(); + if (exists $opts->{documenters}) { + $item = new yui::YItem(N("Documented by")); + $dumptab->addItem( $item ); + $item->DISOWN(); + } + if (exists $opts->{translator_credits}) { + $item = new yui::YItem(N("Translated by")); + $dumptab->addItem( $item ); + $item->DISOWN(); + } + if (exists $opts->{artists}) { + $item = new yui::YItem(N("Artwork by")); + $dumptab->addItem( $item ); + $item->DISOWN(); + } + my $vbox = $factory->createVBox($dumptab); + $align = $factory->createLeft($vbox); + $factory->createVSpacing($vbox, 1.0); + my $label = $factory->createLabel( $align, "***", 0); + $factory->createVSpacing($vbox, 1.0); + + # start value for first Item + $label->setValue($opts->{authors}) if exists $opts->{authors}; + + # Close button + $align = $factory->createRight($layout); + my $closeButton = $factory->createPushButton($align, N("Close")); + + # manage Credits dialog events + while(1) { + my $event = $creditsdlg->waitForEvent(); + my $eventType = $event->eventType(); + + #event type checking + if ($eventType == $yui::YEvent::CancelEvent) { + last; + } + elsif ($eventType == $yui::YEvent::WidgetEvent) { + # widget selected + my $widget = $event->widget(); + + if ($widget == $closeButton) { + last; + } + } + elsif ($event->item() ) { + # $eventType MenuEvent!!! + my $itemLabel = $event->item()->label(); + $itemLabel =~ s/&//; #remove shortcut from label + if ($itemLabel eq N("Written by")) { + $label->setValue($opts->{authors}) if exists $opts->{authors}; + } + elsif ($itemLabel eq N("Documented by")) { + $label->setValue($opts->{documenters}) if exists $opts->{documenters}; + } + elsif ($itemLabel eq N("Translated by")) { + $label->setValue($opts->{translator_credits}) if exists $opts->{translator_credits}; + } + elsif ($itemLabel eq N("Artwork by")) { + $label->setValue($opts->{artists}) if exists $opts->{artists}; + } + } + } + } + else { + print "No tab widgets available!\n"; + } + destroy $creditsdlg; + } + + # License dialog + sub License { + my ($license) = @_; + + my $factory = yui::YUI::widgetFactory; + my $licensedlg = $factory->createPopupDialog(); + my $layout = $factory->createVBox($licensedlg); + + # header + $factory->createHBox($layout); + my $hbox = $factory->createHBox($layout); + my $align = $factory->createHVCenter($hbox); + $hbox = $factory->createHBox($align); + $factory->createHeading($hbox, N("License")); + + # license + $hbox = $factory->createHBox($layout); + $align = $factory->createAlignment($hbox, 3, 0); + $factory->createLabel( $align, $license); + + $align = $factory->createRight($layout); + my $closeButton = $factory->createPushButton($align, N("Close")); + + $licensedlg->waitForEvent(); + + destroy $licensedlg; + } + + my $website = "http://www.mageia.org"; + my $website_label = "Mageia"; + my $factory = yui::YUI::widgetFactory; + my $aboutdlg = $factory->createPopupDialog(); + my $layout = $factory->createVBox($aboutdlg); + + # header + $factory->createHBox($layout); + my $hbox_iconbar = $factory->createHBox($layout); + my $align = $factory->createHVCenter($hbox_iconbar); + $hbox_iconbar = $factory->createHBox($align); + $factory->createImage($hbox_iconbar, $opts->{logo}) if exists $opts->{logo}; + my $header = $opts->{name} . " " . $opts->{version}; + $factory->createHeading($hbox_iconbar, $header); + + # comments + my $hbox = $factory->createHBox($layout); + $align = $factory->createAlignment($hbox, 3, 0); + $factory->createLabel( $align, $opts->{comments}, 0, 0) if exists $opts->{comments}; + + # copyright + $hbox = $factory->createHBox($layout); + $align = $factory->createHVCenter($hbox); + $factory->createLabel( $align, $opts->{copyright}, 0, 0) if exists $opts->{copyright}; + + # website / website_label + $hbox = $factory->createHBox($layout); + $align = $factory->createHVCenter($hbox); + $website = $opts->{website} if exists $opts->{website}; + $website_label = $opts->{website_label} if exists $opts->{website_label}; + my $webref = "". $website_label .""; + $factory->createRichText( $align, $webref); + + # Credits, License and Close buttons + $hbox = $factory->createHBox($layout); + $align = $factory->createLeft($hbox); + my $hbox1 = $factory->createHBox($align); + my $creditsButton = $factory->createPushButton($hbox1, N("Credits")); + my $licenseButton = $factory->createPushButton($hbox1, N("License")); + $factory->createHSpacing($hbox, 2.0); + $align = $factory->createRight($hbox); + my $closeButton = $factory->createPushButton($align, N("Close")); + + # AboutDialog Events + while(1) { + my $event = $aboutdlg->waitForEvent(); + my $eventType = $event->eventType(); + + #event type checking + if ($eventType == $yui::YEvent::CancelEvent) { + last; + } + elsif ($eventType == $yui::YEvent::WidgetEvent) { + # widget selected + my $widget = $event->widget(); + + if($widget == $licenseButton) { + License($opts->{license}) if exists $opts->{license}; + } + elsif ($widget == $creditsButton) { + Credits($opts); + } + elsif ($widget == $closeButton) { + last; + } + } + elsif ($eventType == $yui::YEvent::MenuEvent) { + my $menuEvent = yui::YMGAWidgetFactory::getYMenuEvent($event); + #TODO check why is not working + run_program::raw({ detach => 1 }, 'www-browser', $menuEvent->id()); + } + } + + destroy $aboutdlg; +} + +#============================================================= + +=head2 trim + +=head3 INPUT + + $st: String to be trimmed + +=head3 OUTPUT + + $st: trimmed string + +=head3 DESCRIPTION + +This function trim the given string. + +=cut + +#============================================================= + +sub trim { + my ($st) = shift; + $st =~s /^\s+//g; + $st =~s /\s+$//g; + return $st; +} + +#============================================================= + +=head2 member + +=head3 INPUT + + $e: Array element to be found into array + @_: any array + +=head3 OUTPUT + + 1 or 0: if $e is a member of the given array + +=head3 DESCRIPTION + +This function look for an element into an array + +=cut + +#============================================================= +sub member { + my $e = shift; + foreach (@_) { + $e eq $_ and return 1; + } + 0; +} + +1; # End of AdminPanel::Shared diff --git a/lib/AdminPanel/Shared/Hosts.pm b/lib/AdminPanel/Shared/Hosts.pm new file mode 100644 index 00000000..3e1fb905 --- /dev/null +++ b/lib/AdminPanel/Shared/Hosts.pm @@ -0,0 +1,103 @@ +# vim: set et ts=4 sw=4: +#***************************************************************************** +# +# Copyright (c) 2013-2014 Matteo Pasotti +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** +package AdminPanel::Shared::Hosts; + +use Moose; +use diagnostics; +use local::lib; +use Config::Hosts; +use utf8; + +# costants by Config::Hosts +my $is_ip = 1; +my $is_host = -1; +my $is_none = 0; + +has 'configHosts' => ( + is => 'rw', + init_arg => undef, + builder => '_initialize' +); + +sub _initialize { + my $self = shift(); + $self->configHosts(Config::Hosts->new()); +} + +=pod + +=head2 _getHosts + +=head3 OUTPUT + + @result: array of hashes; each one of them represent a host definition from the hosts configuration file + + NOTE: the 'hosts' item into each hash is an array: it contains the hostname and -eventually- the aliases + +=head3 DESCRIPTION + +retrieve data from the hosts file (/etc/hosts) using the Config::Hosts module + +=cut + +sub _getHosts { + my $self = shift(); + # $self->configHosts(Config::Hosts->new()); + my $hosts = $self->configHosts->read_hosts(); + my @result = (); + while( my ($key, $value) = each($hosts)){ + if($self->configHosts->determine_ip_or_host($key) == $is_ip){ + my $tmp = {}; + $tmp = $self->configHosts->query_host($key); + $tmp->{'ip'} = $key; + push @result,$tmp; + } + } + return @result; +} + +sub _insertHost { + my $self = shift(); + # remember that the order matters! + my $ip = shift(); + my @host_definitions = @_; + # $self->configHosts = Config::Hosts->new(); + return $self->configHosts->insert_host(ip => $ip, hosts => @host_definitions); +} + +sub _dropHost { + my $self = shift(); + my $host_ip = shift(); + return $self->configHosts->delete_host($host_ip); +} + +sub _modifyHost { + my $self = shift(); + my $host_ip = shift(); + my @host_definitions = @_; + return $self->configHosts->update_host($host_ip, hosts => @host_definitions); +} + +sub _writeHosts { + my $self = shift(); + return $self->configHosts->write_hosts(); +} + +1; diff --git a/lib/AdminPanel/Shared/Services.pm b/lib/AdminPanel/Shared/Services.pm new file mode 100644 index 00000000..49937438 --- /dev/null +++ b/lib/AdminPanel/Shared/Services.pm @@ -0,0 +1,444 @@ +# vim: set et ts=4 sw=4: +#***************************************************************************** +# +# Copyright (c) 2013 Angelo Naselli +# from drakx services +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** + +package AdminPanel::Shared::Services; + + +#-###################################################################################### +#- misc imports +#-###################################################################################### + +use strict; +use common; +use run_program; + +use File::Basename qw( basename ); +use base qw(Exporter); + +our @EXPORT = qw( + services + xinetd_services + is_service_running + restart_or_start + stop + start + set_service + ); + +sub description { + my %services = ( +acpid => N_("Listen and dispatch ACPI events from the kernel"), +alsa => N_("Launch the ALSA (Advanced Linux Sound Architecture) sound system"), +anacron => N_("Anacron is a periodic command scheduler."), +apmd => N_("apmd is used for monitoring battery status and logging it via syslog. +It can also be used for shutting down the machine when the battery is low."), +atd => N_("Runs commands scheduled by the at command at the time specified when +at was run, and runs batch commands when the load average is low enough."), +'avahi-deamon' => N_("Avahi is a ZeroConf daemon which implements an mDNS stack"), +chronyd => N_("An NTP client/server"), +cpufreq => N_("Set CPU frequency settings"), +crond => N_("cron is a standard UNIX program that runs user-specified programs +at periodic scheduled times. vixie cron adds a number of features to the basic +UNIX cron, including better security and more powerful configuration options."), +cups => N_("Common UNIX Printing System (CUPS) is an advanced printer spooling system"), +dm => N_("Launches the graphical display manager"), +fam => N_("FAM is a file monitoring daemon. It is used to get reports when files change. +It is used by GNOME and KDE"), +g15daemon => N_("G15Daemon allows users access to all extra keys by decoding them and +pushing them back into the kernel via the linux UINPUT driver. This driver must be loaded +before g15daemon can be used for keyboard access. The G15 LCD is also supported. By default, +with no other clients active, g15daemon will display a clock. Client applications and +scripts can access the LCD via a simple API."), +gpm => N_("GPM adds mouse support to text-based Linux applications such the +Midnight Commander. It also allows mouse-based console cut-and-paste operations, +and includes support for pop-up menus on the console."), +haldaemon => N_("HAL is a daemon that collects and maintains information about hardware"), +harddrake => N_("HardDrake runs a hardware probe, and optionally configures +new/changed hardware."), +httpd => N_("Apache is a World Wide Web server. It is used to serve HTML files and CGI."), +inet => N_("The internet superserver daemon (commonly called inetd) starts a +variety of other internet services as needed. It is responsible for starting +many services, including telnet, ftp, rsh, and rlogin. Disabling inetd disables +all of the services it is responsible for."), +ip6tables => N_("Automates a packet filtering firewall with ip6tables"), +iptables => N_("Automates a packet filtering firewall with iptables"), +irqbalance => N_("Evenly distributes IRQ load across multiple CPUs for enhanced performance"), +keytable => N_("This package loads the selected keyboard map as set in +/etc/sysconfig/keyboard. This can be selected using the kbdconfig utility. +You should leave this enabled for most machines."), +kheader => N_("Automatic regeneration of kernel header in /boot for +/usr/include/linux/{autoconf,version}.h"), +kudzu => N_("Automatic detection and configuration of hardware at boot."), +'laptop-mode' => N_("Tweaks system behavior to extend battery life"), +linuxconf => N_("Linuxconf will sometimes arrange to perform various tasks +at boot-time to maintain the system configuration."), +lpd => N_("lpd is the print daemon required for lpr to work properly. It is +basically a server that arbitrates print jobs to printer(s)."), +lvs => N_("Linux Virtual Server, used to build a high-performance and highly +available server."), +mandi => N_("Monitors the network (Interactive Firewall and wireless"), +mdadm => N_("Software RAID monitoring and management"), +messagebus => N_("DBUS is a daemon which broadcasts notifications of system events and other messages"), +msec => N_("Enables MSEC security policy on system startup"), +named => N_("named (BIND) is a Domain Name Server (DNS) that is used to resolve host names to IP addresses."), +netconsole => N_("Initializes network console logging"), +netfs => N_("Mounts and unmounts all Network File System (NFS), SMB (Lan +Manager/Windows), and NCP (NetWare) mount points."), +network => N_("Activates/Deactivates all network interfaces configured to start +at boot time."), +'network-auth' => N_("Requires network to be up if enabled"), +'network-up' => N_("Wait for the hotplugged network to be up"), +nfs => N_("NFS is a popular protocol for file sharing across TCP/IP networks. +This service provides NFS server functionality, which is configured via the +/etc/exports file."), +nfslock => N_("NFS is a popular protocol for file sharing across TCP/IP +networks. This service provides NFS file locking functionality."), +ntpd => N_("Synchronizes system time using the Network Time Protocol (NTP)"), +numlock => N_("Automatically switch on numlock key locker under console +and Xorg at boot."), +oki4daemon => N_("Support the OKI 4w and compatible winprinters."), +partmon => N_("Checks if a partition is close to full up"), +pcmcia => N_("PCMCIA support is usually to support things like ethernet and +modems in laptops. It will not get started unless configured so it is safe to have +it installed on machines that do not need it."), +portmap => N_("The portmapper manages RPC connections, which are used by +protocols such as NFS and NIS. The portmap server must be running on machines +which act as servers for protocols which make use of the RPC mechanism."), +portreserve => N_("Reserves some TCP ports"), +postfix => N_("Postfix is a Mail Transport Agent, which is the program that moves mail from one machine to another."), +random => N_("Saves and restores system entropy pool for higher quality random +number generation."), +rawdevices => N_("Assign raw devices to block devices (such as hard disk drive +partitions), for the use of applications such as Oracle or DVD players"), +resolvconf => N_("Nameserver information manager"), +routed => N_("The routed daemon allows for automatic IP router table updated via +the RIP protocol. While RIP is widely used on small networks, more complex +routing protocols are needed for complex networks."), +rstatd => N_("The rstat protocol allows users on a network to retrieve +performance metrics for any machine on that network."), +rsyslog => N_("Syslog is the facility by which many daemons use to log messages to various system log files. It is a good idea to always run rsyslog."), +rusersd => N_("The rusers protocol allows users on a network to identify who is +logged in on other responding machines."), +rwhod => N_("The rwho protocol lets remote users get a list of all of the users +logged into a machine running the rwho daemon (similar to finger)."), +saned => N_("SANE (Scanner Access Now Easy) enables to access scanners, video cameras, ..."), +shorewall => N_("Packet filtering firewall"), +smb => N_("The SMB/CIFS protocol enables to share access to files & printers and also integrates with a Windows Server domain"), +sound => N_("Launch the sound system on your machine"), +'speech-dispatcherd' => N_("layer for speech analysis"), +sshd => N_("Secure Shell is a network protocol that allows data to be exchanged over a secure channel between two computers"), +syslog => N_("Syslog is the facility by which many daemons use to log messages +to various system log files. It is a good idea to always run syslog."), +'udev-post' => N_("Moves the generated persistent udev rules to /etc/udev/rules.d"), +usb => N_("Load the drivers for your usb devices."), +vnStat => N_("A lightweight network traffic monitor"), +xfs => N_("Starts the X Font Server."), +xinetd => N_("Starts other deamons on demand."), + ); + my ($name) = @_; + my $s = $services{$name}; + if ($s) { + $s = translate($s); + } else { + my $file = "$::prefix/usr/lib/systemd/system/$name.service"; + if (-e $file) { + $s = cat_($file); + $s = $s =~ /^Description=(.*)/mg ? $1 : ''; + } else { + $file = find { -e $_ } map { "$::prefix$_/$name" } '/etc/rc.d/init.d', '/etc/init.d', '/etc/xinetd.d'; + $s = cat_($file); + $s =~ s/\\\s*\n#\s*//mg; + $s = + $s =~ /^#\s+(?:Short-)?[dD]escription:\s+(.*?)^(?:[^#]|# {0,2}\S)/sm ? $1 : + $s =~ /^#\s*(.*?)^[^#]/sm ? $1 : ''; + + $s =~ s/#\s*//mg; + } + } + $s =~ s/\n/ /gm; $s =~ s/\s+$//; + $s; +} + + +sub set_service { + my ($service, $enable) = @_; + + my @xinetd_services = map { $_->[0] } xinetd_services(); + + if (member($service, @xinetd_services)) { + run_program::rooted($::prefix, "chkconfig", $enable ? "--add" : "--del", $service); + } elsif (running_systemd() || has_systemd()) { + # systemctl rejects any symlinked units. You have to enabled the real file + if (-l "/lib/systemd/system/$service.service") { + my $name = readlink("/lib/systemd/system/$service.service"); + $service = File::Basename::basename($name); + } else { + $service = $service . ".service"; + } + run_program::rooted($::prefix, "/bin/systemctl", $enable ? "enable" : "disable", $service); + } else { + my $script = "/etc/rc.d/init.d/$service"; + run_program::rooted($::prefix, "chkconfig", $enable ? "--add" : "--del", $service); + #- FIXME: handle services with no chkconfig line and with no Default-Start levels in LSB header + if ($enable && cat_("$::prefix$script") =~ /^#\s+chkconfig:\s+-/m) { + run_program::rooted($::prefix, "chkconfig", "--level", "35", $service, "on"); + } + } +} + +sub _run_action { + my ($service, $action) = @_; + if (running_systemd()) { + run_program::rooted($::prefix, '/bin/systemctl', '--no-block', $action, "$service.service"); + } else { + run_program::rooted($::prefix, "/etc/rc.d/init.d/$service", $action); + } +} + +sub running_systemd() { + run_program::rooted($::prefix, '/bin/mountpoint', '-q', '/sys/fs/cgroup/systemd'); +} + +sub has_systemd() { + run_program::rooted($::prefix, '/bin/rpm', '-q', 'systemd'); +} + +sub xinetd_services() { + local $ENV{LANGUAGE} = 'C'; + my @xinetd_services; + foreach (run_program::rooted_get_stdout($::prefix, '/sbin/chkconfig', '--list', '--type', 'xinetd')) { + if (my ($xinetd_name, $on_off) = m!^\t(\S+):\s*(on|off)!) { + push @xinetd_services, [ $xinetd_name, $on_off eq 'on' ]; + } + } + @xinetd_services; +} + +sub _systemd_services() { + local $ENV{LANGUAGE} = 'C'; + my @services; + my %loaded; + # Running system using systemd + log::explanations("Detected systemd running. Using systemctl introspection."); + foreach (run_program::rooted_get_stdout($::prefix, '/bin/systemctl', '--full', '--all', 'list-units')) { + if (my ($name) = m!^(\S+)\.service\s+loaded!) { + # We only look at non-template, non-linked service files in /lib + # We also check for any non-masked sysvinit files as these are + # also handled by systemd + if ($name !~ /.*\@$/g && (-e "$::prefix/lib/systemd/system/$name.service" or -e "$::prefix/etc/rc.d/init.d/$name") && ! -l "$::prefix/lib/systemd/system/$name.service") { + push @services, [ $name, !!run_program::rooted($::prefix, '/bin/systemctl', '--quiet', 'is-enabled', "$name.service") ]; + $loaded{$name} = 1; + } + } + } + # list-units will not list disabled units that can be enabled + foreach (run_program::rooted_get_stdout($::prefix, '/bin/systemctl', '--full', 'list-unit-files')) { + if (my ($name) = m!^(\S+)\.service\s+disabled!) { + # We only look at non-template, non-linked service files in /lib + # We also check for any non-masked sysvinit files as these are + # also handled by systemd + if (!exists $loaded{$name} && $name !~ /.*\@$/g && (-e "$::prefix/lib/systemd/system/$name.service" or -e "$::prefix/etc/rc.d/init.d/$name") && ! -l "$::prefix/lib/systemd/system/$name.service") { + # Limit ourselves to "standard" targets which can be enabled + my $wantedby = cat_("$::prefix/lib/systemd/system/$name.service") =~ /^WantedBy=(graphical|multi-user).target$/sm ? $1 : ''; + if ($wantedby) { + push @services, [ $name, 0 ]; + } + } + } + } + + @services; +} + +sub _legacy_services() { + local $ENV{LANGUAGE} = 'C'; + my @services; + my $has_systemd = has_systemd(); + if ($has_systemd) { + # The system not using systemd but will be at next boot. This is + # is typically the case in the installer. In this mode we must read + # as much as is practicable from the native systemd unit files and + # combine that with information from chkconfig regarding legacy sysvinit + # scripts (which systemd will parse and include when running) + log::explanations("Detected systemd installed. Using fake service+chkconfig introspection."); + foreach (glob_("$::prefix/lib/systemd/system/*.service")) { + my ($name) = m!([^/]*).service$!; + + # We only look at non-template, non-symlinked service files + if (!(/.*\@\.service$/g) && ! -l $_) { + # Limit ourselves to "standard" targets + my $wantedby = cat_($_) =~ /^WantedBy=(graphical|multi-user).target$/sm ? $1 : ''; + if ($wantedby) { + # Exclude if enabled statically + # Note DO NOT use -e when testing for files that could + # be symbolic links as this will fail under a chroot + # setup where -e will fail if the symlink target does + # exist which is typically the case when viewed outside + # of the chroot. + if (!-l "$::prefix/lib/systemd/system/$wantedby.target.wants/$name.service") { + push @services, [ $name, !!-l "$::prefix/etc/systemd/system/$wantedby.target.wants/$name.service" ]; + } + } + } + } + } else { + log::explanations("Could not detect systemd. Using chkconfig service introspection."); + } + + # Regardless of whether we expect to use systemd on next boot, we still + # need to instrospect information about non-systemd native services. + my $runlevel; + my $on_off; + if (!$::isInstall) { + $runlevel = (split " ", `/sbin/runlevel`)[1]; + } + foreach (run_program::rooted_get_stdout($::prefix, '/sbin/chkconfig', '--list', '--type', 'sysv')) { + if (my ($name, $l) = m!^(\S+)\s+(0:(on|off).*)!) { + # If we expect to use systemd (i.e. installer) only show those + # sysvinit scripts which are not masked by a native systemd unit. + my $has_systemd_unit = systemd_unit_exists($name); + if (!$has_systemd || !$has_systemd_unit) { + if ($::isInstall) { + $on_off = $l =~ /\d+:on/g; + } else { + $on_off = $l =~ /$runlevel:on/g; + } + push @services, [ $name, $on_off ]; + } + } + } + @services; +} + +#- returns: +#--- the listref of installed services +#--- the listref of "on" services +sub services() { + my @services; + if (running_systemd()) { + @services = _systemd_services(); + } else { + @services = _legacy_services(); + } + + my @l = xinetd_services(); + push @l, @services; + @l = sort { $a->[0] cmp $b->[0] } @l; + [ map { $_->[0] } @l ], [ map { $_->[0] } grep { $_->[1] } @l ]; +} + + + +sub systemd_unit_exists { + my ($name) = @_; + # we test with -l as symlinks are not valid when the system is chrooted: + -e "$::prefix/lib/systemd/system/$name.service" or -l "$::prefix/lib/systemd/system/$name.service"; +} + +sub service_exists { + my ($service) = @_; + -x "$::prefix/etc/rc.d/init.d/$service" or systemd_unit_exists($service); +} + +sub restart ($) { + my ($service) = @_; + # Exit silently if the service is not installed + service_exists($service) or return 1; + _run_action($service, "restart"); +} + +sub restart_or_start ($) { + my ($service) = @_; + # Exit silently if the service is not installed + service_exists($service) or return 1; + _run_action($service, is_service_running($service) ? "restart" : "start"); +} + +sub start ($) { + my ($service) = @_; + # Exit silently if the service is not installed + service_exists($service) or return 1; + _run_action($service, "start"); +} + +sub start_not_running_service ($) { + my ($service) = @_; + # Exit silently if the service is not installed + service_exists($service) or return 1; + is_service_running($service) || _run_action($service, "start"); +} + +sub stop ($) { + my ($service) = @_; + # Exit silently if the service is not installed + service_exists($service) or return 1; + _run_action($service, "stop"); +} + +sub is_service_running ($) { + my ($service) = @_; + # Exit silently if the service is not installed + service_exists($service) or return 1; + if (running_systemd()) { + run_program::rooted($::prefix, '/bin/systemctl', '--quiet', 'is-active', "$service.service"); + } else { + run_program::rooted($::prefix, '/sbin/service', $service, 'status'); + } +} + +sub starts_on_boot { + my ($service) = @_; + my (undef, $on_services) = services(); + member($service, @$on_services); +} + +sub start_service_on_boot ($) { + my ($service) = @_; + set_service($service, 1); +} + +sub do_not_start_service_on_boot ($) { + my ($service) = @_; + set_service($service, 0); +} + +sub enable { + my ($service, $o_dont_apply) = @_; + start_service_on_boot($service); + restart_or_start($service) unless $o_dont_apply; +} + +sub disable { + my ($service, $o_dont_apply) = @_; + do_not_start_service_on_boot($service); + stop($service) unless $o_dont_apply; +} + +sub set_status { + my ($service, $enable, $o_dont_apply) = @_; + if ($enable) { + enable($service, $o_dont_apply); + } else { + disable($service, $o_dont_apply); + } +} + +1; diff --git a/lib/AdminPanel/Shared/Users.pm b/lib/AdminPanel/Shared/Users.pm new file mode 100644 index 00000000..9dcc5bd1 --- /dev/null +++ b/lib/AdminPanel/Shared/Users.pm @@ -0,0 +1,126 @@ +package AdminPanel::Shared::Users; + +use diagnostics; +use strict; + +#-###################################################################################### +#- misc imports +#-###################################################################################### +use common; + +use run_program; + +use base qw(Exporter); + +our @EXPORT = qw( + facesdir + face2png + facenames + addKdmIcon + valid_username + valid_groupname + GetFaceIcon + Add2UsersGroup + ); + +sub facesdir() { + "$::prefix/usr/share/mga/faces/"; +} +sub face2png { + my ($face) = @_; + facesdir() . $face . ".png"; +} +sub facenames() { + my $dir = facesdir(); + my @l = grep { /^[A-Z]/ } all($dir); + map { if_(/(.*)\.png/, $1) } (@l ? @l : all($dir)); +} + +sub addKdmIcon { + my ($user, $icon) = @_; + my $dest = "$::prefix/usr/share/faces/$user.png"; + eval { cp_af(facesdir() . $icon . ".png", $dest) } if $icon; +} + + +sub valid { + return (0, N("Name field is empty please provide a name")) if (!$_[0] ); + + $_[0] =~ /^[a-z]+?[a-z0-9_\-\.]*?$/ or do { + return (0, N("The name must contain only lower cased latin letters, numbers, `.', `-' and `_'")); + }; + return (0, N("Name is too long")) if (! (length($_[0]) <= $_[1])); + return (1, N("Ok")); +} + +sub valid_username { + return valid($_[0], 32); +} + +sub valid_groupname { + return valid($_[0], 16); +} + +################################################## +## GetFaceIcon +## params +## +## 'name' icon name for the given name +## 'next' get next icon from the given 'name' +## +## return +## 'user_icon' icon name +## +sub GetFaceIcon { + my ($name, $next) = @_; + my @icons = facenames(); + my $i; + my $current_icon; + # remove shortcut "&" from label + $name =~ s/&// if ($name); + my $user_icon = "$::prefix/usr/share/faces/$name.png" if ($name); + if ($name) { + $user_icon = face2png($name) unless(-e $user_icon); + } + if ($name && -e $user_icon) { + my $current_md5 = common::md5file($user_icon); + eval { $i = find_index { common::md5file(face2png($_)) eq $current_md5 } @icons }; + if (!$@) { #- current icon found in @icons, select it + $current_icon = $icons[$i]; + } else { #- add and select current icon in @icons + push @icons, $user_icon; + $current_icon = $user_icon; + $i = @icons - 1; + } + } else { + #- no icon yet, select a random one + $current_icon = $icons[$i = rand(@icons)]; + } + + if ($next) { + $current_icon = $icons[$i = defined $icons[$i+1] ? $i+1 : 0]; + } + return $current_icon; +} + +################################################## +## Add2UsersGroup +## params +## +## 'name' username +## 'ctx' USER::ADMIN object +## +## return +## gid group id +## +sub Add2UsersGroup { + my ($name, $ctx) = @_; + my $GetValue = -65533; ## Used by USER (for getting values? TODO need explanations, where?) + + my $usersgroup = $ctx->LookupGroupByName('users'); + $usersgroup->MemberName($name, 1); + return $usersgroup->Gid($GetValue); +} + + +1; diff --git a/lib/AdminPanel/rpmdragora.pm b/lib/AdminPanel/rpmdragora.pm new file mode 100644 index 00000000..b96ed53d --- /dev/null +++ b/lib/AdminPanel/rpmdragora.pm @@ -0,0 +1,984 @@ +# vim: set et ts=4 sw=4: +#***************************************************************************** +# +# Copyright (c) 2002 Guillaume Cottenceau +# Copyright (c) 2002-2007 Thierry Vignaud +# Copyright (c) 2003, 2004, 2005 MandrakeSoft SA +# Copyright (c) 2005, 2007 Mandriva SA +# Copyright (c) 2013 Matteo Pasotti +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** +# +# $Id: rpmdragora.pm 267936 2010-04-26 16:40:21Z jvictor $ + +package AdminPanel::rpmdragora; + +use lib qw(/usr/lib/libDrakX); +use urpm::download (); +use urpm::prompt; +use urpm::media; + +use MDK::Common; +use MDK::Common::System; +use urpm; +use urpm::cfg; +use URPM; +use URPM::Resolve; +use strict; +use c; +use POSIX qw(_exit); +use common; +use Locale::gettext; +use feature 'state'; + +use AdminPanel::Shared; + +our @ISA = qw(Exporter); +our $VERSION = '2.27'; +our @EXPORT = qw( + $changelog_first_config + $compute_updates + $filter + $dont_show_selections + $ignore_debug_media + $mandrakeupdate_wanted_categories + $mandrivaupdate_height + $mandrivaupdate_width + $max_info_in_descr + $mode + $NVR_searches + $offered_to_add_sources + $rpmdragora_height + $rpmdragora_width + $tree_flat + $tree_mode + $use_regexp + $typical_width + $clean_cache + $auto_select + add_distrib_update_media + add_medium_and_check + but + but_ + check_update_media_version + choose_mirror + distro_type + fatal_msg + getbanner + get_icon + interactive_list + interactive_list_ + interactive_msg + interactive_packtable + myexit + readconf + remove_wait_msg + run_drakbug + show_urpm_progress + slow_func + slow_func_statusbar + statusbar_msg + statusbar_msg_remove + strip_first_underscore + update_sources + update_sources_check + update_sources_interactive + update_sources_noninteractive + wait_msg + warn_for_network_need + writeconf +); +our $typical_width = 280; + +our $dont_show_selections; + +# i18n: IMPORTANT: to get correct namespace (rpmdragora instead of libDrakX) +BEGIN { unshift @::textdomains, qw(rpmdragora urpmi rpm-summary-main rpm-summary-contrib rpm-summary-devel rpm-summary-non-free) } + +use yui; +use Glib; +#ugtk2::add_icon_path('/usr/share/rpmdragora/icons'); + +Locale::gettext::bind_textdomain_codeset('rpmdragora', 'UTF8'); + +our $mageia_release = cat_( + -e '/etc/mageia-release' ? '/etc/mageia-release' : '/etc/release' +) || ''; +chomp $mageia_release; +our ($distro_version) = $mageia_release =~ /(\d+\.\d+)/; +our ($branded, %distrib); +$branded = -f '/etc/sysconfig/oem' + and %distrib = MDK::Common::System::distrib(); +our $myname_update = $branded ? N_("Software Update") : N_("Mageia Update"); + +@rpmdragora::prompt::ISA = 'urpm::prompt'; + +sub rpmdragora::prompt::prompt { + my ($self) = @_; + my @answers; + my $d = ugtk2->new("", grab => 1, if_($::main_window, transient => $::main_window)); + $d->{rwindow}->set_position('center_on_parent'); + gtkadd( + $d->{window}, + gtkpack( + Gtk2::VBox->new(0, 5), + Gtk2::WrappedLabel->new($self->{title}), + (map { gtkpack( + Gtk2::HBox->new(0, 5), + Gtk2::Label->new($self->{prompts}[$_]), + $answers[$_] = gtkset_visibility(gtkentry(), !$self->{hidden}[$_]), + ) } 0 .. $#{$self->{prompts}}), + gtksignal_connect(Gtk2::Button->new(N("Ok")), clicked => sub { Gtk2->main_quit }), + ), + ); + $d->main; + map { $_->get_text } @answers; +} + +$urpm::download::PROMPT_PROXY = new rpmdragora::prompt( + N_("Please enter your credentials for accessing proxy\n"), + [ N_("User name:"), N_("Password:") ], + undef, + [ 0, 1 ], +); + +sub myexit { + writeconf(); + #ugtk2::exit(undef, @_); +} + +my ($root) = grep { $_->[2] == 0 } list_passwd(); +$ENV{HOME} = $> == 0 ? $root->[7] : $ENV{HOME} || '/root'; +$ENV{HOME} = $::env if $::env = $Rpmdragora::init::rpmdragora_options{env}[0]; + +our $configfile = "$ENV{HOME}/.rpmdragora"; + +# +# Configuration File Options +# + +# clear download cache after successfull installation of packages +our $clean_cache; + +# automatic select dependencies without user intervention +our $auto_select; + +our ($changelog_first_config, $compute_updates, $filter, $max_info_in_descr, $mode, $NVR_searches, $tree_flat, $tree_mode, $use_regexp); +our ($mandrakeupdate_wanted_categories, $ignore_debug_media, $offered_to_add_sources, $no_confirmation); +our ($rpmdragora_height, $rpmdragora_width, $mandrivaupdate_height, $mandrivaupdate_width); + +our %config = ( + clean_cache => { + var => \$clean_cache, + default => [ 0 ] + }, + auto_select => { + var => \$auto_select, + default => [ 0 ] + }, + changelog_first_config => { var => \$changelog_first_config, default => [ 0 ] }, + compute_updates => { var => \$compute_updates, default => [ 1 ] }, + dont_show_selections => { var => \$dont_show_selections, default => [ $> ? 1 : 0 ] }, + filter => { var => \$filter, default => [ 'all' ] }, + ignore_debug_media => { var => \$ignore_debug_media, default => [ 0 ] }, + mandrakeupdate_wanted_categories => { var => \$mandrakeupdate_wanted_categories, default => [ qw(security) ] }, + mandrivaupdate_height => { var => \$mandrivaupdate_height, default => [ 0 ] }, + mandrivaupdate_width => { var => \$mandrivaupdate_width, default => [ 0 ] }, + max_info_in_descr => { var => \$max_info_in_descr, default => [] }, + mode => { var => \$mode, default => [ 'by_group' ] }, + NVR_searches => { var => \$NVR_searches, default => [ 0 ] }, + 'no-confirmation' => { var => \$no_confirmation, default => [ 0 ] }, + offered_to_add_sources => { var => \$offered_to_add_sources, default => [ 0 ] }, + rpmdragora_height => { var => \$rpmdragora_height, default => [ 0 ] }, + rpmdragora_width => { var => \$rpmdragora_width, default => [ 0 ] }, + tree_flat => { var => \$tree_flat, default => [ 0 ] }, + tree_mode => { var => \$tree_mode, default => [ qw(gui_pkgs) ] }, + use_regexp => { var => \$use_regexp, default => [ 0 ] }, +); + +sub readconf() { + ${$config{$_}{var}} = $config{$_}{default} foreach keys %config; + foreach my $l (cat_($configfile)) { + foreach (keys %config) { + ${$config{$_}{var}} = [ split ' ', $1 ] if $l =~ /^\Q$_\E(.*)/; + } + } + # special cases: + $::rpmdragora_options{'no-confirmation'} = $no_confirmation->[0] if !defined $::rpmdragora_options{'no-confirmation'}; + $Rpmdragora::init::default_list_mode = $tree_mode->[0] if ref $tree_mode && !$Rpmdragora::init::overriding_config; +} + +sub writeconf() { + return if $::env; + unlink $configfile; + + # special case: + $no_confirmation->[0] = $::rpmdragora_options{'no-confirmation'}; + + output($configfile, map { "$_ " . (ref ${$config{$_}{var}} ? join(' ', @${$config{$_}{var}}) : undef) . "\n" } keys %config); +} + +sub getbanner() { + $::MODE or return undef; + if (0) { + +{ + remove => N("Software Packages Removal"), + update => N("Software Packages Update"), + install => N("Software Packages Installation"), + }; + } +# Gtk2::Banner->new($ugtk2::wm_icon, $::MODE eq 'update' ? N("Software Packages Update") : N("Software Management")); +} + +# return value: +# - undef if if closed (aka really canceled) +# - 0 if if No/Cancel +# - 1 if if Yes/Ok +sub interactive_msg { + my ($title, $contents, %options) = @_; + return ask_YesOrNo($title, $contents); +=comment + $options{transient} ||= $::main_window if $::main_window; + local $::isEmbedded; + my $factory = yui::YUI::widgetFactory; + my $d = $factory->createPopupDialog(); + + my $d = ugtk2->new($title, grab => 1, if_(exists $options{transient}, transient => $options{transient})); + $d->{rwindow}->set_position($options{transient} ? 'center_on_parent' : 'center_always'); + if ($options{scroll}) { + $contents = ugtk2::markup_to_TextView_format($contents) if !ref $contents; + } else { #- because we'll use a WrappedLabel + $contents = formatAlaTeX($contents) if !ref $contents; + } + + my $button_yes; + my $vbox = $factory->createVBox($d); + my $text_w = $factory->createMultiLineEdit($vbox, ""); + my $hbox = $factory->createHBox($vbox); + + ref($options{yesno}) eq 'ARRAY' ? map {ss + my $label = $_; + my $button_yes = $factory->createIconButton($hbox,"",$label); + } @{$options{yesno}} + : ( + $options{yesno} ? ( + my $button_no = $factory->createIconButton($hbox, "", $options{text}{no} || N("No")); + $button_yes = $factory->createIconButton($hbox,"", $options{text}{yes} || N("Yes")); + ) + : $button_yes = $factory->createIconButton($hbox,"",N("Ok")); + ) + + #$d->{window}->set_focus($button_yes); + #$text_w->set_size_request($typical_width*2, $options{scroll} ? 300 : -1); + #$d->main; + return $d->{retval}; +=cut +} + +sub interactive_packtable { + my ($title, $parent_window, $top_label, $lines, $action_buttons) = @_; + + my $w = ugtk2->new($title, grab => 1, transient => $parent_window); + local $::main_window = $w->{real_window}; + $w->{rwindow}->set_position($parent_window ? 'center_on_parent' : 'center'); + my $packtable = create_packtable({}, @$lines); + + gtkadd($w->{window}, + gtkpack_(Gtk2::VBox->new(0, 5), + if_($top_label, 0, Gtk2::Label->new($top_label)), + 1, create_scrolled_window($packtable), + 0, gtkpack__(create_hbox(), @$action_buttons))); + my $preq = $packtable->size_request; + my ($xpreq, $ypreq) = ($preq->width, $preq->height); + my $wreq = $w->{rwindow}->size_request; + my ($xwreq, $ywreq) = ($wreq->width, $wreq->height); + $w->{rwindow}->set_default_size(max($typical_width, min($typical_width*2.5, $xpreq+$xwreq)), + max(200, min(450, $ypreq+$ywreq))); + $w->main; +} + +sub interactive_list { + my ($title, $contents, $list, $callback, %options) = @_; + + my $factory = yui::YUI::widgetFactory; + my $mainw = $factory->createPopupDialog(); + my $vbox = $factory->createVBox($mainw); + my $lbltitle = $factory->createLabel($vbox, N("Dependencies")); + my $radiobuttongroup = $factory->createRadioButtonGroup($vbox); + my $rbbox = $factory->createVBox($radiobuttongroup); + foreach my $item(@$list){ + my $radiobutton = $factory->createRadioButton($rbbox,$item); + $radiobutton->setNotify(0); + $radiobuttongroup->addRadioButton($radiobutton); + } + my $submitButton = $factory->createIconButton($vbox,"", N("OK")); + my $choice; + + while(1) { + my $event = $mainw->waitForEvent(); + my $eventType = $event->eventType(); + #event type checking + if ($eventType == $yui::YEvent::CancelEvent) { + $mainw->destroy(); + last; + } + elsif ($eventType == $yui::YEvent::WidgetEvent) { + # widget selected + my $widget = $event->widget(); + + if($widget == $submitButton) { + $choice = $radiobuttongroup->currentButton->label(); + $choice =~s/\&//g; + last; + } + } + } + $mainw->destroy(); + return $choice; +} + +sub interactive_list_ { interactive_list(@_, if_($::main_window, transient => $::main_window)) } + +sub fatal_msg { + interactive_msg @_; + myexit -1; +} + +sub wait_msg { + my ($msg, %options) = @_; + #OLD my $mainw = ugtk2->new(N("Please wait"), grab => 1, if_(exists $options{transient}, transient => $options{transient})); + #$mainw->{real_window}->set_position($options{transient} ? 'center_on_parent' : 'center_always'); + #my $label = $factory->createLabel($vbox, $msg); + #OLD my $label = ref($msg) =~ /^Gtk/ ? $msg : Gtk2::WrappedLabel->new($msg); + #gtkadd( + #$mainw->{window}, + #gtkpack__( + # gtkset_border_width(Gtk2::VBox->new(0, 5), 6), + # $label, + # if_(exists $options{widgets}, @{$options{widgets}}), + #) + #); + my $factory = yui::YUI::widgetFactory; + my $mainw = $factory->createPopupDialog(); + my $vbox = $factory->createVBox($mainw); + my $title = $factory->createLabel($vbox, N("Please wait")); + #$mainw->recalcLayout(); + #$mainw->doneMultipleChanges(); + $mainw->pollEvent(); + #$mainw->recalcLayout(); + #$mainw->doneMultipleChanges(); + $mainw; +} + +sub remove_wait_msg { + my $w = shift; + #gtkset_mousecursor_normal($w->{rwindow}->window); + $w->destroy; +} + +sub but { " $_[0] " } +sub but_ { " $_[0] " } + +sub slow_func ($&) { + my ($param, $func) = @_; + if (ref($param) =~ /^Gtk/) { + #gtkset_mousecursor_wait($param); + #ugtk2::flush(); + #$func->(); + #gtkset_mousecursor_normal($param); + } else { + my $w = wait_msg($param); + $func->(); + remove_wait_msg($w); + } +} + +sub statusbar_msg { + unless ($::statusbar) { #- fallback if no status bar + if (defined &::wait_msg_) { goto &::wait_msg_ } else { goto &wait_msg } + } + my ($msg, $o_timeout) = @_; + $::statusbar->setText($msg); + #- always use the same context description for now + #my $cx = $::statusbar->get_context_id("foo"); + #$::w and $::w->{rwindow} and gtkset_mousecursor_wait($::w->{rwindow}->window); + #- returns a msg_id to be passed optionnally to statusbar_msg_remove + #my $id = $::statusbar->push($cx, $msg); + #gtkflush(); + #Glib::Timeout->add(5000, sub { statusbar_msg_remove($id); 0 }) if $o_timeout; + Glib::Timeout->add(5000, sub { statusbar_msg_remove(); 0 }) if $o_timeout; + #$id; +} + +sub statusbar_msg_remove { + #my ($msg_id) = @_; + #if (!$::statusbar || ref $msg_id) { #- fallback if no status bar + #goto &remove_wait_msg; + #} + #my $cx = $::statusbar->get_context_id("foo"); + #if (defined $msg_id) { + #$::statusbar->remove($cx, $msg_id); + #} else { + #$::statusbar->pop($cx); + #} + #$::w and $::w->{rwindow} and gtkset_mousecursor_normal($::w->{rwindow}->window); + $::statusbar->setValue(""); +} + +sub slow_func_statusbar ($$&) { + my ($msg, $w, $func) = @_; + gtkset_mousecursor_wait($w->window); + my $msg_id = statusbar_msg($msg); + gtkflush(); + $func->(); + statusbar_msg_remove($msg_id); + gtkset_mousecursor_normal($w->window); +} + +my %u2l = ( + at => N_("Austria"), + au => N_("Australia"), + be => N_("Belgium"), + br => N_("Brazil"), + ca => N_("Canada"), + ch => N_("Switzerland"), + cr => N_("Costa Rica"), + cz => N_("Czech Republic"), + de => N_("Germany"), + dk => N_("Danmark"), + el => N_("Greece"), + es => N_("Spain"), + fi => N_("Finland"), + fr => N_("France"), + gr => N_("Greece"), + hu => N_("Hungary"), + il => N_("Israel"), + it => N_("Italy"), + jp => N_("Japan"), + ko => N_("Korea"), + nl => N_("Netherlands"), + no => N_("Norway"), + pl => N_("Poland"), + pt => N_("Portugal"), + ru => N_("Russia"), + se => N_("Sweden"), + sg => N_("Singapore"), + sk => N_("Slovakia"), + tw => N_("Taiwan"), + uk => N_("United Kingdom"), + cn => N_("China"), + com => N_("United States"), + org => N_("United States"), + net => N_("United States"), + edu => N_("United States"), + ); +my $us = [ qw(com org net edu) ]; +my %t2l = ( + 'America/\w+' => $us, + 'Asia/Tel_Aviv' => [ qw(il ru it cz at de fr se) ], + 'Asia/Tokyo' => [ qw(jp ko tw), @$us ], + 'Asia/Seoul' => [ qw(ko jp tw), @$us ], + 'Asia/Taipei' => [ qw(tw jp), @$us ], + 'Asia/(Shanghai|Beijing)' => [ qw(cn tw sg), @$us ], + 'Asia/Singapore' => [ qw(cn sg), @$us ], + 'Atlantic/Reykjavik' => [ qw(uk no se fi dk), @$us, qw(nl de fr at cz it) ], + 'Australia/\w+' => [ qw(au jp ko tw), @$us ], + 'Brazil/\w+' => [ 'br', @$us ], + 'Canada/\w+' => [ 'ca', @$us ], + 'Europe/Amsterdam' => [ qw(nl be de at cz fr se dk it) ], + 'Europe/Athens' => [ qw(gr pl cz de it nl at fr) ], + 'Europe/Berlin' => [ qw(de be at nl cz it fr se) ], + 'Europe/Brussels' => [ qw(be de nl fr cz at it se) ], + 'Europe/Budapest' => [ qw(cz it at de fr nl se) ], + 'Europe/Copenhagen' => [ qw(dk nl de be se at cz it) ], + 'Europe/Dublin' => [ qw(uk fr be nl dk se cz it) ], + 'Europe/Helsinki' => [ qw(fi se no nl be de fr at it) ], + 'Europe/Istanbul' => [ qw(il ru it cz it at de fr nl se) ], + 'Europe/Lisbon' => [ qw(pt es fr it cz at de se) ], + 'Europe/London' => [ qw(uk fr be nl de at cz se it) ], + 'Europe/Madrid' => [ qw(es fr pt it cz at de se) ], + 'Europe/Moscow' => [ qw(ru de pl cz at se be fr it) ], + 'Europe/Oslo' => [ qw(no se fi dk de be at cz it) ], + 'Europe/Paris' => [ qw(fr be de at cz nl it se) ], + 'Europe/Prague' => [ qw(cz it at de fr nl se) ], + 'Europe/Rome' => [ qw(it fr cz de at nl se) ], + 'Europe/Stockholm' => [ qw(se no dk fi nl de at cz fr it) ], + 'Europe/Vienna' => [ qw(at de cz it fr nl se) ], + ); + +#- get distrib release number (2006.0, etc) +sub etc_version() { + (my $v) = split / /, cat_('/etc/version'); + return $v; +} + +#- returns the keyword describing the type of the distribution. +#- the parameter indicates whether we want base or update sources +sub distro_type { + my ($want_base_distro) = @_; + return 'cauldron' if $mageia_release =~ /cauldron/i; + #- we can't use updates for community while official is not out (release ends in ".0") + if ($want_base_distro || $mageia_release =~ /community/i && etc_version() =~ /\.0$/) { + return 'official' if $mageia_release =~ /official|limited/i; + return 'community' if $mageia_release =~ /community/i; + #- unknown: fallback to updates + } + return 'updates'; +} + +sub compat_arch_for_updates($) { + # FIXME: We prefer 64-bit packages to update on biarch platforms, + # since the system is populated with 64-bit packages anyway. + my ($arch) = @_; + return $arch =~ /x86_64|amd64/ if arch() eq 'x86_64'; + MDK::Common::System::compat_arch($arch); +} + +sub mirrors { + my ($urpm, $want_base_distro) = @_; + my $cachedir = $urpm->{cachedir} || '/root'; + require mirror; + mirror::register_downloader( + sub { + my ($url) = @_; + my $file = $url; + $file =~ s!.*/!$cachedir/!; + unlink $file; # prevent "partial file" errors + before_leaving(sub { unlink $file }); + + my ($gurpm, $id, $canceled); + # display a message in statusbar (if availlable): + $::statusbar and $id = statusbar_msg( + $branded + ? N("Please wait, downloading mirror addresses.") + : N("Please wait, downloading mirror addresses from the Mageia website."), + 0); + my $_clean_guard = before_leaving { + undef $gurpm; + $id and statusbar_msg_remove($id); + }; + + require Rpmdragora::gurpm; + require Rpmdragora::pkg; + + my $res = urpm::download::sync_url($urpm, $url, + dir => $cachedir, + callback => sub { + $gurpm ||= + Rpmdragora::gurpm->new(N("Please wait"), + transient => $::main_window); + $canceled ||= + !Rpmdragora::pkg::download_callback($gurpm, @_); + gtkflush(); + }, + ); + $res or die N("retrieval of [%s] failed", $file) . "\n"; + return $canceled ? () : cat_($file); + }); + my @mirrors = @{ mirror::list(common::parse_LDAP_namespace_structure(cat_('/etc/product.id')), 'distrib') || [] }; + require timezone; + my $tz = ${timezone::read()}{timezone}; + foreach my $mirror (@mirrors) { + my $goodness; + each_index { $_ = $u2l{$_} || $_; $_ eq $mirror->{country} and $goodness ||= 100-$::i } (map { if_($tz =~ /^$_$/, @{$t2l{$_}}) } keys %t2l), @$us; + $mirror->{goodness} = $goodness + rand(); + $mirror->{country} = translate($mirror->{country}); + } + unless (-x '/usr/bin/rsync') { + @mirrors = grep { $_->{url} !~ /^rsync:/ } @mirrors; + } + return sort { $b->{goodness} <=> $a->{goodness} } @mirrors; +} + +sub warn_for_network_need { + my ($message, %options) = @_; + $message ||= +$branded +? N("I need to access internet to get the mirror list. +Please check that your network is currently running. + +Is it ok to continue?") +: N("I need to contact the Mageia website to get the mirror list. +Please check that your network is currently running. + +Is it ok to continue?"); + interactive_msg(N("Mirror choice"), $message, yesno => 1, %options) or return ''; +} + +sub choose_mirror { + my ($urpm, %options) = @_; + delete $options{message}; + my @transient_options = exists $options{transient} ? (transient => $options{transient}) : (); + warn_for_network_need($options{message}, %options) or return; + my @mirrors = eval { mirrors($urpm, $options{want_base_distro}) }; + my $error = $@; + if ($error) { + $error = "\n$error\n"; + interactive_msg(N("Error during download"), +($branded +? N("There was an error downloading the mirror list: + +%s +The network, or the website, may be unavailable. +Please try again later.", $error) +: N("There was an error downloading the mirror list: + +%s +The network, or the Mageia website, may be unavailable. +Please try again later.", $error)), %options + + ); + return ''; + } + + !@mirrors and interactive_msg(N("No mirror"), +($branded +? N("I can't find any suitable mirror.") +: N("I can't find any suitable mirror. + +There can be many reasons for this problem; the most frequent is +the case when the architecture of your processor is not supported +by Mageia Official Updates.")), %options + ), return ''; + + my $w = ugtk2->new(N("Mirror choice"), grab => 1, @transient_options); + $w->{rwindow}->set_position($options{transient} ? 'center_on_parent' : 'center_always'); + my $tree_model = Gtk2::TreeStore->new("Glib::String"); + my $tree = Gtk2::TreeView->new_with_model($tree_model); + $tree->get_selection->set_mode('browse'); + $tree->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, text => 0)); + $tree->set_headers_visible(0); + + gtkadd( + $w->{window}, + gtkpack_( + Gtk2::VBox->new(0,5), + 0, N("Please choose the desired mirror."), + 1, create_scrolled_window($tree), + 0, gtkpack( + create_hbox('edge'), + map { + my $retv = $_->[1]; + gtksignal_connect( + Gtk2::Button->new(but($_->[0])), + clicked => sub { + if ($retv) { + my ($model, $iter) = $tree->get_selection->get_selected; + $model and $w->{retval} = { sel => $model->get($iter, 0) }; + } + Gtk2->main_quit; + }, + ); + } [ N("Cancel"), 0 ], [ N("Ok"), 1 ] + ), + ) + ); + my %roots; + $tree_model->append_set($roots{$_->{country}} ||= $tree_model->append_set(undef, [ 0 => $_->{country} ]), + [ 0 => $_->{url} ]) foreach @mirrors; + + $w->{window}->set_size_request(500, 400); + $w->{rwindow}->show_all; + + my $path = Gtk2::TreePath->new_first; + $tree->expand_row($path, 0); + $path->down; + $tree->get_selection->select_path($path); + + $w->main && return grep { $w->{retval}{sel} eq $_->{url} } @mirrors; +} + +sub show_urpm_progress { + my ($label, $pb, $mode, $file, $percent, $total, $eta, $speed) = @_; + $file =~ s|([^:]*://[^/:\@]*:)[^/:\@]*(\@.*)|$1xxxx$2|; #- if needed... + state $medium; + if ($mode eq 'copy') { + $pb->set_fraction(0); + $label->set_label(N("Copying file for medium `%s'...", $file)); + } elsif ($mode eq 'parse') { + $pb->set_fraction(0); + $label->set_label(N("Examining file of medium `%s'...", $file)); + } elsif ($mode eq 'retrieve') { + $pb->set_fraction(0); + $label->set_label(N("Examining remote file of medium `%s'...", $file)); + $medium = $file; + } elsif ($mode eq 'done') { + $pb->set_fraction(1.0); + $label->set_label($label->get_label . N(" done.")); + $medium = undef; + } elsif ($mode eq 'failed') { + $pb->set_fraction(1.0); + $label->set_label($label->get_label . N(" failed!")); + $medium = undef; + } else { + # FIXME: we're displaying misplaced quotes such as "downloading `foobar from 'medium Main Updates'ยด" + $file = $medium && length($file) < 40 ? #-PO: We're downloading the said file from the said medium + N("%s from medium %s", basename($file), $medium) + : basename($file); + if ($mode eq 'start') { + $pb->set_fraction(0); + $label->set_label(N("Starting download of `%s'...", $file)); + } elsif ($mode eq 'progress') { + if (defined $total && defined $eta) { + $pb->set_fraction($percent/100); + $label->set_label(N("Download of `%s'\ntime to go:%s, speed:%s", $file, $eta, $speed)); + } else { + $pb->set_fraction($percent/100); + $label->set_label(N("Download of `%s'\nspeed:%s", $file, $speed)); + } + } + } + Gtk2->main_iteration while Gtk2->events_pending; +} + +sub update_sources { + my ($urpm, %options) = @_; + my $cancel = 0; + my $w; my $label; $w = wait_msg( + $label = Gtk2::Label->new(N("Please wait, updating media...")), + no_wait_cursor => 1, + widgets => [ + my $pb = gtkset_size_request(Gtk2::ProgressBar->new, 300, -1), + gtkpack( + create_hbox(), + gtksignal_connect( + Gtk2::Button->new(N("Cancel")), + clicked => sub { + $cancel = 1; + $urpm->{error}->(N("Canceled")); + $w and $w->destroy; + }, + ), + ), + ], + ); + my @media; @media = @{$options{medialist}} if ref $options{medialist}; + my $outerfatal = $urpm->{fatal}; + local $urpm->{fatal} = sub { $w->destroy; $outerfatal->(@_) }; + urpm::media::update_those_media($urpm, [ urpm::media::select_media_by_name($urpm, \@media) ], + %options, allow_failures => 1, + callback => sub { + $cancel and goto cancel_update; + my ($type, $media) = @_; + return if $type !~ /^(?:start|progress|end)$/ && @media && !member($media, @media); + if ($type eq 'failed') { + $urpm->{fatal}->(N("Error retrieving packages"), +N("It's impossible to retrieve the list of new packages from the media +`%s'. Either this update media is misconfigured, and in this case +you should use the Software Media Manager to remove it and re-add it in order +to reconfigure it, either it is currently unreachable and you should retry +later.", + $media)); + } else { + show_urpm_progress($label, $pb, @_); + } + }, + ); + $w->destroy; + cancel_update: +} + +sub update_sources_check { + my ($urpm, $options, $error_msg, @media) = @_; + my @error_msgs; + local $urpm->{fatal} = sub { push @error_msgs, $_[1]; goto fatal_error }; + local $urpm->{error} = sub { push @error_msgs, $_[0] }; + update_sources($urpm, %$options, noclean => 1, medialist => \@media); + fatal_error: + if (@error_msgs) { + interactive_msg(N("Error"), sprintf(translate($error_msg), join("\n", map { formatAlaTeX($_) } @error_msgs)), scroll => 1); + return 0; + } + return 1; +} + +sub update_sources_interactive { + my ($urpm, %options) = @_; + my $w = ugtk2->new(N("Update media"), grab => 1, center => 1, %options); + $w->{rwindow}->set_position($options{transient} ? 'center_on_parent' : 'center_always'); + my @buttons; + my @media = grep { ! $_->{ignore} } @{$urpm->{media}}; + unless (@media) { + interactive_msg(N("Warning"), N("No active medium found. You must enable some media to be able to update them.")); + return 0; + } + gtkadd( + $w->{window}, + gtkpack_( + 0, Gtk2::VBox->new(0,5), + 0, Gtk2::Label->new(N("Select the media you wish to update:")), + 1, gtknew('ScrolledWindow', height => 300, child => + # FIXME: using a listview would be just better: + gtknew('VBox', spacing => 5, children_tight => [ + @buttons = map { + Gtk2::CheckButton->new_with_label($_->{name}); + } @media + ]) + ), + 0, Gtk2::HSeparator->new, + 0, gtkpack( + create_hbox(), + gtksignal_connect( + Gtk2::Button->new(N("Cancel")), + clicked => sub { $w->{retval} = 0; Gtk2->main_quit }, + ), + gtksignal_connect( + Gtk2::Button->new(N("Select all")), + clicked => sub { $_->set_active(1) foreach @buttons }, + ), + gtksignal_connect( + Gtk2::Button->new(N("Update")), + clicked => sub { + $w->{retval} = any { $_->get_active } @buttons; + # list of media listed in the checkbox panel + my @buttonmedia = grep { !$_->{ignore} } @{$urpm->{media}}; + @media = map_index { if_($_->get_active, $buttonmedia[$::i]{name}) } @buttons; + Gtk2->main_quit; + }, + ), + ) + ) + ); + if ($w->main) { + return update_sources_noninteractive($urpm, \@media, %options); + } + return 0; +} + +sub update_sources_noninteractive { + my ($urpm, $media, %options) = @_; + + urpm::media::select_media($urpm, @$media); + update_sources_check( + $urpm, + {}, + N_("Unable to update medium; it will be automatically disabled.\n\nErrors:\n%s"), + @$media, + ); + return 1; +} + +sub add_medium_and_check { + my ($urpm, $options) = splice @_, 0, 2; + my @newnames = ($_[0]); #- names of added media + my $fatal_msg; + my @error_msgs; + local $urpm->{fatal} = sub { printf STDERR "Fatal: %s\n", $_[1]; $fatal_msg = $_[1]; goto fatal_error }; + local $urpm->{error} = sub { printf STDERR "Error: %s\n", $_[0]; push @error_msgs, $_[0] }; + if ($options->{distrib}) { + @newnames = urpm::media::add_distrib_media($urpm, @_); + } else { + urpm::media::add_medium($urpm, @_); + } + if (@error_msgs) { + interactive_msg( + N("Error"), + N("Unable to add medium, errors reported:\n\n%s", + join("\n", map { formatAlaTeX($_) } @error_msgs)) . "\n\n" . N("Medium: ") . "$_[0] ($_[1])", + scroll => 1, + ); + return 0; + } + + foreach my $name (@newnames) { + urpm::download::set_proxy_config($_, $options->{proxy}{$_}, $name) foreach keys %{$options->{proxy} || {}}; + } + + if (update_sources_check($urpm, $options, N_("Unable to add medium, errors reported:\n\n%s"), @newnames)) { + urpm::media::write_config($urpm); + $options->{proxy} and urpm::download::dump_proxy_config(); + } else { + urpm::media::read_config($urpm, 0); + return 0; + } + + my %newnames; @newnames{@newnames} = (); + if (any { exists $newnames{$_->{name}} } @{$urpm->{media}}) { + return 1; + } else { + interactive_msg(N("Error"), N("Unable to create medium.")); + return 0; + } + + fatal_error: + interactive_msg(N("Failure when adding medium"), + N("There was a problem adding medium:\n\n%s", $fatal_msg)); + return 0; +} + +#- Check whether the default update media (added by installation) +#- matches the current mdk version +sub check_update_media_version { + my $urpm = shift; + foreach (@_) { + if ($_->{name} =~ /(\d+\.\d+).*\bftp\du\b/ && $1 ne $distro_version) { + interactive_msg( + N("Warning"), + $branded + ? N("Your medium `%s', used for updates, does not match the version of %s you're running (%s). +It will be disabled.", + $_->{name}, $distrib{system}, $distrib{product}) + : N("Your medium `%s', used for updates, does not match the version of Mageia you're running (%s). +It will be disabled.", + $_->{name}, $distro_version) + ); + $_->{ignore} = 1; + urpm::media::write_config($urpm) if -w $urpm->{config}; + return 0; + } + } + 1; +} + +sub add_distrib_update_media { + my ($urpm, $mirror, %options) = @_; + #- ensure a unique medium name + my $medium_name = $rpmdragora::mageia_release =~ /(\d+\.\d+) \((\w+)\)/ ? $2 . $1 . '-' : 'distrib'; + my $initial_number = 1 + max map { $_->{name} =~ /\(\Q$medium_name\E(\d+)\b/ ? $1 : 0 } @{$urpm->{media}}; + add_medium_and_check( + $urpm, + { nolock => 1, distrib => 1 }, + $medium_name, + ($mirror ? $mirror->{url} : (undef, mirrorlist => '$MIRRORLIST')), + probe_with => 'synthesis', initial_number => $initial_number, %options, + usedistrib => 1, + ); +} + +sub open_help { + my ($mode) = @_; + use run_program; + run_program::raw({ detach => 1, as_user => 1 }, 'drakhelp', '--id', $mode ? "software-management-$mode" : 'software-management'); + my $_s = N("Help launched in background"); + statusbar_msg(N("The help window has been started, it should appear shortly on your desktop."), 1); +} + +sub run_drakbug { + my ($id) = @_; + run_program::raw({ detach => 1, as_user => 1 }, 'drakbug', '--report', $id); +} + +#mygtk2::add_icon_path('/usr/share/mcc/themes/default/'); +sub get_icon { + my ($mcc_icon, $fallback_icon) = @_; + my $icon = eval { mygtk2::_find_imgfile($mcc_icon) }; + $icon ||= eval { mygtk2::_find_imgfile($fallback_icon) }; + $icon; +} + +sub strip_first_underscore { join '', map { s/_//; $_ } @_ } + +1; diff --git a/modules/adminMouse b/modules/adminMouse deleted file mode 100755 index 6af17135..00000000 --- a/modules/adminMouse +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/perl - -use lib qw(/usr/lib/libDrakX); - -use common qw(N); - -use AdminPanel::AdminMouse; - -my $mouseMan = AdminPanel::AdminMouse->new(); - -$mouseMan->start(); - -1; diff --git a/modules/hostmanager/hostmanager b/modules/hostmanager/hostmanager deleted file mode 100755 index 360387cf..00000000 --- a/modules/hostmanager/hostmanager +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/perl -# Copyright 2013 Matteo Pasotti -# -# This file is part of hostmanager -# -# hostmanager is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 2 of the License, or -# (at your option) any later version. -# -# hostmanager is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with AdminPanel. If not, see . -use Modern::Perl 2011; -use autodie; -use AdminPanel::Hosts::GHosts; - -use yui; - -my $wm_icon = "/usr/lib/libDrakX/icons/IC-Dhost-48.png"; -my $wm_name = "Manage hosts definitions"; - -yui::YUI::app()->setApplicationTitle($wm_name); -yui::YUI::app()->setApplicationIcon($wm_icon); - -my $hostMan = AdminPanel::Hosts::GHosts->new({ - icon => $wm_icon, - name => $wm_name - }); -$hostMan->start(); - -1; diff --git a/modules/services/adminService b/modules/services/adminService deleted file mode 100755 index 953b2ccd..00000000 --- a/modules/services/adminService +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/perl - -use strict; -use lib qw(/usr/lib/libDrakX); - -use common qw(N); -use AdminPanel::Services::AdminService; - -my $serviceMan = AdminPanel::Services::AdminService->new({icon => "/usr/share/mcc/themes/default/service-mdk.png", - name => N("Services and daemons"),}); -$serviceMan->start(); - -1; diff --git a/modules/usermanager/adminUser b/modules/usermanager/adminUser deleted file mode 100755 index c7f5b23a..00000000 --- a/modules/usermanager/adminUser +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/perl - -use lib qw(/usr/lib/libDrakX); - -use common qw(N); - -use AdminPanel::Users::GUsers; - -my $userMan = AdminPanel::Users::GUsers->new({icon => "/usr/share/icons/userdrake.png", - name => N("Mageia Users Management Tool"),}); -$userMan->start(); - -1; diff --git a/modules/usermanager/mgaAddUser b/modules/usermanager/mgaAddUser deleted file mode 100755 index f1af4bd3..00000000 --- a/modules/usermanager/mgaAddUser +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/perl - -use lib qw(/usr/lib/libDrakX); - -use common qw(N); - -use AdminPanel::Users::GUsers; - -my $userMan = AdminPanel::Users::GUsers->new({icon => "/usr/share/icons/userdrake.png", - name => N("Mageia Add Users Tool"),}); -$userMan->addUserDialog(1); - -1; diff --git a/scripts/adminMouse b/scripts/adminMouse new file mode 100755 index 00000000..40b86f4f --- /dev/null +++ b/scripts/adminMouse @@ -0,0 +1,13 @@ +#!/usr/bin/perl + +use lib qw(/usr/lib/libDrakX); + +use common qw(N); + +use AdminPanel::Module::AdminMouse; + +my $mouseMan = AdminPanel::Module::AdminMouse->new(); + +$mouseMan->start(); + +1; diff --git a/scripts/adminService b/scripts/adminService new file mode 100755 index 00000000..e46942e9 --- /dev/null +++ b/scripts/adminService @@ -0,0 +1,13 @@ +#!/usr/bin/perl + +use strict; +use lib qw(/usr/lib/libDrakX); + +use common qw(N); +use AdminPanel::Module::Services; + +my $serviceMan = AdminPanel::Module::Services->new({icon => "/usr/share/mcc/themes/default/service-mdk.png", + name => N("Services and daemons"),}); +$serviceMan->start(); + +1; diff --git a/scripts/adminUser b/scripts/adminUser new file mode 100755 index 00000000..2e72b5fc --- /dev/null +++ b/scripts/adminUser @@ -0,0 +1,13 @@ +#!/usr/bin/perl + +use lib qw(/usr/lib/libDrakX); + +use common qw(N); + +use AdminPanel::Module::Users; + +my $userMan = AdminPanel::Module::Users->new({icon => "/usr/share/icons/userdrake.png", + name => N("Mageia Users Management Tool"),}); +$userMan->start(); + +1; diff --git a/scripts/apanel.pl b/scripts/apanel.pl new file mode 100755 index 00000000..750f3f13 --- /dev/null +++ b/scripts/apanel.pl @@ -0,0 +1,95 @@ +#!/usr/bin/perl +# vim: set et ts=4 sw=4: +# Copyright 2012 Steven Tucker +# Copyright 2013 Matteo Pasotti +# Copyright 2014 Angelo Naselli +# +# This file is part of AdminPanel +# +# AdminPanel is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# AdminPanel is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with AdminPanel. If not, see . + +use strict; +use warnings; +use diagnostics; +use AdminPanel::Privileges; +use FindBin; +use lib "$FindBin::RealBin"; +use AdminPanel::SettingsReader; +use AdminPanel::MainDisplay; +use yui; + +my $cmdline = new yui::YCommandLine; + +usage() if($cmdline->find("--help") > 0 || $cmdline->find("-h") > 0); + +my $settings = getSettings(); + +ask_for_authentication($settings->{priv_method}) if(require_root_capability()); + + my $mainWin = new AdminPanel::MainDisplay(); +while (1) { + my $launch = $mainWin->start(); + + if ($launch) { + $mainWin->destroy(); + $launch->start(); + } + else { + $mainWin->destroy(); + last; + } + $mainWin->setupGui(); +} + + +sub usage { + print "\n"; + print "Usage apanel [options...]\n\n"; + print "Options:\n"; + print "\t--help | -h print this help\n"; +## anaselli: --name now is used only to add a path to /etc (e.g. --name mcc2 means /etc/mcc2) + # and it is overriden by --conf_dir, so it should be discussed better to understand + # if it is really needed any more. + # Window title is got from settings.conf (key title) + print "\t--name string specify the window title of the administration panel\n"; + print "\t--conf_dir path specify the settings.conf file directory\n"; + print "\n"; + exit(0); +} + +# adpanel settings +sub getSettings { + my ($self) = @_; + # yui commandline parser + my $pos = $cmdline->find("--conf_dir"); + my $confDir = "/etc/apanel"; + if($pos > 0){ + $confDir = $cmdline->arg($pos + 1); + }else{ + $confDir = "/etc/apanel"; + } + # configuration file name + my $fileName = "$confDir/settings.conf"; + return new AdminPanel::SettingsReader($fileName); +} + +=pod + +=head1 main + + main launcher + +=cut + +1; diff --git a/scripts/hostmanager b/scripts/hostmanager new file mode 100755 index 00000000..006f5efd --- /dev/null +++ b/scripts/hostmanager @@ -0,0 +1,36 @@ +#!/usr/bin/perl +# Copyright 2013 Matteo Pasotti +# +# This file is part of hostmanager +# +# hostmanager is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# hostmanager is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with AdminPanel. If not, see . +use Modern::Perl 2011; +use autodie; +use AdminPanel::Module::Hosts; + +use yui; + +my $wm_icon = "/usr/lib/libDrakX/icons/IC-Dhost-48.png"; +my $wm_name = "Manage hosts definitions"; + +yui::YUI::app()->setApplicationTitle($wm_name); +yui::YUI::app()->setApplicationIcon($wm_icon); + +my $hostMan = AdminPanel::Module::Hosts->new({ + icon => $wm_icon, + name => $wm_name + }); +$hostMan->start(); + +1; diff --git a/scripts/mgaAddUser b/scripts/mgaAddUser new file mode 100755 index 00000000..093da724 --- /dev/null +++ b/scripts/mgaAddUser @@ -0,0 +1,13 @@ +#!/usr/bin/perl + +use lib qw(/usr/lib/libDrakX); + +use common qw(N); + +use AdminPanel::Module::Users; + +my $userMan = AdminPanel::Module::Users->new({icon => "/usr/share/icons/userdrake.png", + name => N("Mageia Add Users Tool"),}); +$userMan->addUserDialog(1); + +1; diff --git a/t/00-load.t b/t/00-load.t new file mode 100644 index 00000000..5be19d43 --- /dev/null +++ b/t/00-load.t @@ -0,0 +1,13 @@ +#!perl -T +use 5.006; +use strict; +use warnings FATAL => 'all'; +use Test::More; + +plan tests => 1; + +BEGIN { + use_ok( 'AdminPanel::Shared' ) || print "Bail out!\n"; +} + +diag( "Testing AdminPanel::Shared $AdminPanel::Shared::VERSION, Perl $], $^X" ); diff --git a/t/boilerplate.t b/t/boilerplate.t new file mode 100644 index 00000000..9d8d3fae --- /dev/null +++ b/t/boilerplate.t @@ -0,0 +1,57 @@ +#!perl -T +use 5.006; +use strict; +use warnings FATAL => 'all'; +use Test::More; + +plan tests => 3; + +sub not_in_file_ok { + my ($filename, %regex) = @_; + open( my $fh, '<', $filename ) + or die "couldn't open $filename for reading: $!"; + + my %violated; + + while (my $line = <$fh>) { + while (my ($desc, $regex) = each %regex) { + if ($line =~ $regex) { + push @{$violated{$desc}||=[]}, $.; + } + } + } + + if (%violated) { + fail("$filename contains boilerplate text"); + diag "$_ appears on lines @{$violated{$_}}" for keys %violated; + } else { + pass("$filename contains no boilerplate text"); + } +} + +sub module_boilerplate_ok { + my ($module) = @_; + not_in_file_ok($module => + 'the great new $MODULENAME' => qr/ - The great new /, + 'boilerplate description' => qr/Quick summary of what the module/, + 'stub function definition' => qr/function[12]/, + ); +} + +TODO: { + local $TODO = "Need to replace the boilerplate text"; + + not_in_file_ok(README => + "The README is used..." => qr/The README is used/, + "'version information here'" => qr/to provide version information/, + ); + + not_in_file_ok(Changes => + "placeholder date/time" => qr(Date/time) + ); + + module_boilerplate_ok('lib/AdminPanel/Shared.pm'); + + +} + diff --git a/t/manifest.t b/t/manifest.t new file mode 100644 index 00000000..6ddfe364 --- /dev/null +++ b/t/manifest.t @@ -0,0 +1,15 @@ +#!perl -T +use 5.006; +use strict; +use warnings FATAL => 'all'; +use Test::More; + +unless ( $ENV{RELEASE_TESTING} ) { + plan( skip_all => "Author tests not required for installation" ); +} + +my $min_tcm = 0.9; +eval "use Test::CheckManifest $min_tcm"; +plan skip_all => "Test::CheckManifest $min_tcm required" if $@; + +ok_manifest(); diff --git a/t/pod-coverage.t b/t/pod-coverage.t new file mode 100644 index 00000000..866fac2b --- /dev/null +++ b/t/pod-coverage.t @@ -0,0 +1,20 @@ +#!perl -T +use 5.006; +use strict; +use warnings FATAL => 'all'; +use Test::More; + +# Ensure a recent version of Test::Pod::Coverage +my $min_tpc = 1.08; +eval "use Test::Pod::Coverage $min_tpc"; +plan skip_all => "Test::Pod::Coverage $min_tpc required for testing POD coverage" + if $@; + +# Test::Pod::Coverage doesn't require a minimum Pod::Coverage version, +# but older versions don't recognize some common documentation styles +my $min_pc = 0.18; +eval "use Pod::Coverage $min_pc"; +plan skip_all => "Pod::Coverage $min_pc required for testing POD coverage" + if $@; + +all_pod_coverage_ok(); diff --git a/t/pod.t b/t/pod.t new file mode 100644 index 00000000..a0054e97 --- /dev/null +++ b/t/pod.t @@ -0,0 +1,12 @@ +#!perl -T +use 5.006; +use strict; +use warnings FATAL => 'all'; +use Test::More; + +# Ensure a recent version of Test::Pod +my $min_tp = 1.22; +eval "use Test::Pod $min_tp"; +plan skip_all => "Test::Pod $min_tp required for testing POD" if $@; + +all_pod_files_ok(); -- cgit v1.2.1