diff options
author | Angelo Naselli <anaselli@linux.it> | 2014-01-27 18:20:30 +0100 |
---|---|---|
committer | Angelo Naselli <anaselli@linux.it> | 2014-01-27 18:20:30 +0100 |
commit | 1624ce382eb033c2cf3ef1fe6b9c41beb0b0a91b (patch) | |
tree | 1363e3d3bdcfa5b2ff3111a41b2c700a5a922140 /lib/AdminPanel/Module | |
parent | f519e47d15103514585a272c6308467ac41ce551 (diff) | |
download | manatools-1624ce382eb033c2cf3ef1fe6b9c41beb0b0a91b.tar manatools-1624ce382eb033c2cf3ef1fe6b9c41beb0b0a91b.tar.gz manatools-1624ce382eb033c2cf3ef1fe6b9c41beb0b0a91b.tar.bz2 manatools-1624ce382eb033c2cf3ef1fe6b9c41beb0b0a91b.tar.xz manatools-1624ce382eb033c2cf3ef1fe6b9c41beb0b0a91b.zip |
Project structure change
Diffstat (limited to 'lib/AdminPanel/Module')
-rw-r--r-- | lib/AdminPanel/Module/AdminMouse.pm | 278 | ||||
-rw-r--r-- | lib/AdminPanel/Module/Hosts.pm | 355 | ||||
-rw-r--r-- | lib/AdminPanel/Module/Services.pm | 559 | ||||
-rw-r--r-- | lib/AdminPanel/Module/Users.pm | 2570 |
4 files changed, 3762 insertions, 0 deletions
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 <anaselli@linux.it> +# 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<scalar(@{$fullList->{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 <anaselli\@linux.it>\nMatteo Pasotti <matteo.pasotti\@gmail.com>", + translator_credits => + #-PO: put here name(s) and email(s) of translator(s) (eg: "John Smith <jsmith@nowhere.com>") + 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 <matteo.pasotti@gmail.com> +# +# 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 <matteo.pasotti\@gmail.com>" + } + ); + }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 <anaselli@linux.it> +# 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 <anaselli\@linux.it>\nMatteo Pasotti <matteo.pasotti\@gmail.com>", + translator_credits => + #-PO: put here name(s) and email(s) of translator(s) (eg: "John Smith <jsmith@nowhere.com>") + 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 <anaselli@linux.it> +# 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 <anaselli\@linux.it>\nMatteo Pasotti <matteo.pasotti\@gmail.com>", + translator_credits => + #-PO: put here name(s) and email(s) of translator(s) (eg: "John Smith <jsmith@nowhere.com>") + 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; |