From b4e446c21e299af0441ec44db7a86334980b77c2 Mon Sep 17 00:00:00 2001 From: Angelo Naselli Date: Mon, 16 Mar 2015 19:20:40 +0100 Subject: Moved the tree accordingly --- lib/ManaTools/Module/AdminMouse.pm | 282 ++++ lib/ManaTools/Module/Clock.pm | 518 +++++++ lib/ManaTools/Module/DisplayManager.pm | 298 ++++ lib/ManaTools/Module/Firewall.pm | 1208 +++++++++++++++ lib/ManaTools/Module/Hosts.pm | 530 +++++++ lib/ManaTools/Module/LogViewer.pm | 568 +++++++ lib/ManaTools/Module/Proxy.pm | 396 +++++ lib/ManaTools/Module/Services.pm | 588 +++++++ lib/ManaTools/Module/Users.pm | 2637 ++++++++++++++++++++++++++++++++ 9 files changed, 7025 insertions(+) create mode 100644 lib/ManaTools/Module/AdminMouse.pm create mode 100644 lib/ManaTools/Module/Clock.pm create mode 100644 lib/ManaTools/Module/DisplayManager.pm create mode 100644 lib/ManaTools/Module/Firewall.pm create mode 100644 lib/ManaTools/Module/Hosts.pm create mode 100644 lib/ManaTools/Module/LogViewer.pm create mode 100644 lib/ManaTools/Module/Proxy.pm create mode 100644 lib/ManaTools/Module/Services.pm create mode 100644 lib/ManaTools/Module/Users.pm (limited to 'lib/ManaTools/Module') diff --git a/lib/ManaTools/Module/AdminMouse.pm b/lib/ManaTools/Module/AdminMouse.pm new file mode 100644 index 00000000..279fb760 --- /dev/null +++ b/lib/ManaTools/Module/AdminMouse.pm @@ -0,0 +1,282 @@ +# vim: set et ts=4 sw=4: +#***************************************************************************** +# +# Copyright (c) 2013 - 2015 Angelo Naselli +# from drakx services +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** + +# NOTE this module has not been ported and does not work +# TODO porting it if it is really needed nowadays +package ManaTools::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 ManaTools::Shared; + +use yui; +use Moose; + +extends qw( ManaTools::Module ); + +has '+icon' => ( + default => "/usr/share/mcc/themes/default/mousedrake-mdk.png", +); + +has '+name' => ( + default => N("AdminMouse"), +); + +sub start { + my $self = shift; + + $self->_adminMouseDialog(); +} + +sub _getUntranslatedName { + my ($self, $name, $list) = @_; + + foreach my $n (@{$list}) { + my @names = split(/\|/, $n); + for (my $lev=0; $lev < scalar(@names); $lev++) { + if (translate($names[$lev]) eq $name) { + return $names[$lev]; + } + } + } + + return undef; +} + + +sub _adminMouseDialog { + my $self = shift; + + my $datavalue = "TEST"; + + my $appTitle = yui::YUI::app()->applicationTitle(); + + ## set new title to get it in dialog + yui::YUI::app()->setApplicationTitle($self->name); + ## set icon if not already set by external launcher + yui::YUI::app()->setApplicationIcon($self->icon); + + my $factory = yui::YUI::widgetFactory; + + my $dialog = $factory->createMainDialog; + my $vbox = $factory->createVBox( $dialog ); + my $frame = $factory->createFrame ($vbox, N("Please choose your type of mouse.")); + my $treeWidget = $factory->createTree($frame, ""); + + my $modules_conf = modules::any_conf->read; + + my $mouse = mouse::read(); + + if (!$::noauto) { + my $probed_mouse = mouse::detect($modules_conf); + $mouse = $probed_mouse if !$mouse->{Protocol} || !$probed_mouse->{unsafe}; + } + + if (!$mouse || !$::auto) { + $mouse ||= mouse::fullname2mouse('Universal|Any PS/2 & USB mice'); + + my $prev = my $fullname = $mouse->{type} . '|' . $mouse->{name}; + my $selected = $mouse->{name}; + + my $fullList = { list => [ mouse::_fullnames() ], items => [], separator => '|', val => \$fullname, + format => sub { join('|', map { translate($_) } split('\|', $_[0])) } } ; + my $i; + + my $itemColl = new yui::YItemCollection; + my @items; + for ($i=0; $i{list}}); $i++) { + my @names = split(/\|/, $fullList->{list}[$i]); + for (my $lev=0; $lev < scalar(@names); $lev++) { + $names[$lev] = N($names[$lev]); + } + if ($i == 0 || $names[0] ne $items[0]->{label}) { + if ($i != 0) { + $itemColl->push($items[0]->{item}); + push @{$fullList->{items}}, $items[-1]->{item};; + } + @items = undef; + my $item = new yui::YTreeItem ($names[0]); + + if ($selected eq $self->_getUntranslatedName($item->label(), $fullList->{list})) { + $item->setSelected(1) ; + $item->setOpen(1); + my $parent = $item; + while($parent = $parent->parent()) { + $parent->setOpen(1); + } + } + $item->DISOWN(); + @items = ({item => $item, label => $names[0], level => 0}); + for (my $lev=1; $lev < scalar(@names); $lev++) { + $item = new yui::YTreeItem ($items[$lev-1]->{item}, $names[$lev]); + + if ($selected eq $self->_getUntranslatedName($item->label(), $fullList->{list})) { + $item->setSelected(1) ; + $item->setOpen(1); + my $parent = $item; + while($parent = $parent->parent()) { + $parent->setOpen(1); + } + } + $item->DISOWN(); + if ($lev < scalar(@names)-1) { + push @items, {item => $item, label => $names[$lev], level => $lev}; + } + } + } + else { + my $prevItem = 0; + for (my $lev=1; $lev < scalar(@names); $lev++) { + my $it; + for ($it=1; $it < scalar(@items); $it++){ + if ($items[$it]->{label} eq $names[$lev] && $items[$it]->{level} == $lev) { + $prevItem = $it; + last; + } + } + if ($it == scalar(@items)) { + my $item = new yui::YTreeItem ($items[$prevItem]->{item}, $names[$lev]); + + if ($selected eq $self->_getUntranslatedName($item->label(), $fullList->{list})) { + $item->setSelected(1) ; + $item->setOpen(1); + my $parent = $item; + while($parent = $parent->parent()) { + $parent->setOpen(1); + } + } + $item->DISOWN(); + push @items, {item => $item, label => $names[$lev], level => $lev}; + } + } + } + } + $itemColl->push($items[0]->{item}); + push @{$fullList->{items}}, $items[-1]->{item}; + + $treeWidget->addItems($itemColl); + my $align = $factory->createLeft($vbox); + my $hbox = $factory->createHBox($align); + my $aboutButton = $factory->createPushButton($hbox, N("About") ); + $align = $factory->createRight($hbox); + $hbox = $factory->createHBox($align); + my $cancelButton = $factory->createPushButton($hbox, N("Cancel") ); + my $okButton = $factory->createPushButton($hbox, N("Ok") ); + + while(1) { + my $event = $dialog->waitForEvent(); + my $eventType = $event->eventType(); + + #event type checking + if ($eventType == $yui::YEvent::CancelEvent) { + last; + } + elsif ($eventType == $yui::YEvent::WidgetEvent) { + # widget selected + my $widget = $event->widget(); + + if ($widget == $cancelButton) { + last; + } + elsif ($widget == $aboutButton) { + my $license = translate($ManaTools::Shared::License); + ManaTools::Shared::AboutDialog( + { name => N("AdminMouse"), + version => $self->VERSION, + copyright => N("Copyright (C) %s Mageia community", '2014'), + license => $license, + comments => N("AdminMouse is the Mageia mouse management tool \n(from the original idea of Mandriva mousedrake)."), + website => 'http://www.mageia.org', + website_label => N("Mageia"), + authors => "Angelo Naselli \nMatteo Pasotti ", + translator_credits => + #-PO: put here name(s) and email(s) of translator(s) (eg: "John Smith ") + N("_: Translator(s) name(s) & email(s)\n")} + ); + } + elsif ($widget == $okButton) { + my $continue = 1; + my $selectedItem = $treeWidget->selectedItem(); + + my $it=$selectedItem; + my $fullname = $self->_getUntranslatedName($it->label(), $fullList->{list}); + while($it = yui::toYTreeItem($it)->parent()) { + $fullname = join("|", $self->_getUntranslatedName($it->label(), $fullList->{list}), $fullname); + } + + if ($fullname ne $prev) { + my $mouse_ = mouse::fullname2mouse($fullname, device => $mouse->{device}); + if ($fullname =~ /evdev/) { + $mouse_->{evdev_mice} = $mouse_->{evdev_mice_all} = $mouse->{evdev_mice_all}; + } + %$mouse = %$mouse_; + } + + if ($mouse->{nbuttons} < 3 ) { + $mouse->{Emulate3Buttons} = ManaTools::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 = ManaTools::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'; + + ManaTools::Shared::infoMsgBox(N("Not implemented yet: configuration is not changed")); + + $dialog->destroy(); + + #restore old application title + yui::YUI::app()->setApplicationTitle($appTitle); +} + +1; diff --git a/lib/ManaTools/Module/Clock.pm b/lib/ManaTools/Module/Clock.pm new file mode 100644 index 00000000..f2bb5c08 --- /dev/null +++ b/lib/ManaTools/Module/Clock.pm @@ -0,0 +1,518 @@ +# vim: set et ts=4 sw=4: +package ManaTools::Module::Clock; +#============================================================= -*-perl-*- + +=head1 NAME + +ManaTools::Module::Clock - This module aims to configure system clock and time + +=head1 SYNOPSIS + + my $clockSettings = ManaTools::Module::Clock->new(); + $clockSettings->start(); + +=head1 DESCRIPTION + +Long_description + +=head1 SUPPORT + +You can find documentation for this module with the perldoc command: + +perldoc ManaTools::Module::Clock + +=head1 SEE ALSO + +SEE_ALSO + +=head1 AUTHOR + +Angelo Naselli + +=head1 COPYRIGHT and LICENSE + +Copyright (C) 2014-2015, Angelo Naselli. + +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 + +=head1 FUNCTIONS + +=cut + +use Moose; + +use diagnostics; + +use ManaTools::Shared::GUI; +use ManaTools::Shared::Locales; +use ManaTools::Shared::TimeZone; + +use Time::Piece; + +use yui; + +extends qw( ManaTools::Module ); + +### TODO icon +has '+icon' => ( + default => "/usr/share/mcc/themes/default/time-mdk.png", +); + +has 'loc' => ( + is => 'rw', + init_arg => undef, + builder => '_localeInitialize' +); + +sub _localeInitialize { + my $self = shift; + + # TODO fix domain binding for translation + $self->loc(ManaTools::Shared::Locales->new(domain_name => 'libDrakX-standalone') ); + # TODO if we want to give the opportunity to test locally add dir_name => 'path' +} + +has 'sh_gui' => ( + is => 'rw', + lazy => 1, + init_arg => undef, + builder => '_SharedGUIInitialize' +); + +sub _SharedGUIInitialize { + my $self = shift; + + $self->sh_gui(ManaTools::Shared::GUI->new() ); +} + +has 'sh_tz' => ( + is => 'rw', + lazy => 1, + builder => '_SharedTimeZoneInitialize' +); + +sub _SharedTimeZoneInitialize { + my $self = shift; + + $self->sh_tz(ManaTools::Shared::TimeZone->new() ); +} + + +=head1 VERSION + +Version 1.0.0 + +=cut + +our $VERSION = '1.0.0'; + +#============================================================= + +=head2 BUILD + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + The BUILD method is called after a Moose object is created, + in this methods Services loads all the service information. + +=cut + +#============================================================= +sub BUILD { + my $self = shift; + + if (! $self->name) { + $self->name ($self->loc->N("Date, Clock & Time Zone Settings")); + } +} + +#============================================================= + +=head2 start + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + This method extends Module::start and is invoked to + start admin clock + +=cut + +#============================================================= +sub start { + my $self = shift; + + $self->_adminClockPanel(); +}; + +### _get_NTPservers +## returns ntp servers in the format +## Zone|Nation: server +# +sub _get_NTPservers { + my $self = shift; + + my $servs = $self->sh_tz->ntpServers(); + [ map { "$servs->{$_}|$_" } sort { $servs->{$a} cmp $servs->{$b} || $a cmp $b } keys %$servs ]; +} + +### _restoreValues +## restore NTP server and Time Zone from configuration files +# +## input '$datetime_only' restore date and time only +# +## returns 'info', a HASH references containing: +## time_zone => time zone hash reference to be restored +## ntp_server => ntp server address +## date => date string +## time => time string +## ntp_running => is NTP running? +# +sub _restoreValues { + my ($self, $datetime_only) = @_; + + my $info; + if (!$datetime_only) { + $info->{time_zone} = $self->sh_tz->readConfiguration(); + $info->{ntp_server} = $self->sh_tz->ntpCurrentServer(); + #- strip digits from \d+.foo.pool.ntp.org + $info->{ntp_server} =~ s/^\d+\.// if $info->{ntp_server}; + $info->{ntp_running} = $self->sh_tz->isNTPRunning(); + } + my $t = localtime; + my $day = $t->strftime("%F"); + my $time = $t->strftime("%H:%M:%S"); + $info->{date} = $day; + $info->{time} = $time; + + return $info; +} + +sub _adminClockPanel { + 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 $factory = yui::YUI::widgetFactory; + my $optFactory = yui::YUI::optionalWidgetFactory; + die "calendar widgets missing" if (!$optFactory->hasDateField() || !$optFactory->hasTimeField()); + + # Create Dialog + my $dialog = $factory->createMainDialog; +# my $minSize = $factory->createMinSize($dialog, 40, 15); + + # Start Dialog layout: + my $layout = $factory->createVBox($dialog); + my $align = $factory->createLeft($layout); + + my $frame = $factory->createFrame($align, $self->loc->N("Setting date and time")); + my $hbox = $factory->createHBox($frame); + + my $dateField = $optFactory->createDateField($hbox, ""); + $factory->createHSpacing($hbox, 3.0); + my $timeField = $optFactory->createTimeField($hbox, ""); + $factory->createHSpacing($hbox, 1.0); + $factory->createVSpacing($hbox, 1.0); + $factory->createVSpacing($layout, 1.0); + + $align = $factory->createLeft($layout); + $hbox = $factory->createHBox($align); + my $ntpFrame = $factory->createCheckBoxFrame($hbox, $self->loc->N("Enable Network Time Protocol"), 0); + + my $hbox1 = $factory->createHBox($ntpFrame); + my $changeNTPButton = $factory->createPushButton($hbox1, $self->loc->N("Change &NTP server")); + $factory->createHSpacing($hbox1, 1.0); + $factory->createLabel($hbox1,$self->loc->N("Current:")); + $factory->createHSpacing($hbox1, 1.0); + my $ntpLabel = $factory->createLabel($hbox1, $self->loc->N("not defined")); + $factory->createHSpacing($hbox1, 1.0); + $ntpLabel->setWeight($yui::YD_HORIZ, 2); + $changeNTPButton->setWeight($yui::YD_HORIZ, 1); + $factory->createHSpacing($hbox, 1.0); + + $factory->createVSpacing($layout, 1.0); + $align = $factory->createLeft($layout); + $hbox = $factory->createHBox($align); + $frame = $factory->createFrame ($hbox, $self->loc->N("TimeZone")); + $hbox1 = $factory->createHBox( $frame ); + my $changeTZButton = $factory->createPushButton($hbox1, $self->loc->N("Change &Time Zone")); + $factory->createHSpacing($hbox1, 1.0); + $factory->createLabel($hbox1,$self->loc->N("Current:")); + $factory->createHSpacing($hbox1, 1.0); + my $timeZoneLbl = $factory->createLabel($hbox1, $self->loc->N("not defined")); + $factory->createHSpacing($hbox1, 1.0); + $timeZoneLbl->setWeight($yui::YD_HORIZ, 2); + $changeTZButton->setWeight($yui::YD_HORIZ, 1); + + $factory->createHSpacing($hbox, 1.0); + + # buttons on the last line + $factory->createVSpacing($layout, 1.0); + $hbox = $factory->createHBox($layout); + + $align = $factory->createLeft($hbox); + $hbox = $factory->createHBox($align); + my $aboutButton = $factory->createPushButton($hbox, $self->loc->N("&About") ); + my $resetButton = $factory->createPushButton($hbox, $self->loc->N("&Reset") ); + + $align = $factory->createRight($hbox); + $hbox = $factory->createHBox($align); + my $cancelButton = $factory->createPushButton($hbox, $self->loc->N("&Cancel")); + my $okButton = $factory->createPushButton($hbox, $self->loc->N("&Ok")); + $factory->createHSpacing($hbox, 1.0); + + ## no changes by default + $dialog->setDefaultButton($cancelButton); + + # End Dialof layout + + ## default value + my $info = $self->_restoreValues(); + + $dateField->setValue($info->{date}); + $timeField->setValue($info->{time}); + + if (exists $info->{time_zone} && $info->{time_zone}->{ZONE}) { + $timeZoneLbl->setValue($info->{time_zone}->{ZONE}); + } + + if ($info->{ntp_server}) { + $ntpLabel->setValue($info->{ntp_server}); + } + $ntpFrame->setValue($info->{ntp_running}); + + + # get only once + my $NTPservers = $self->_get_NTPservers(); + + while(1) { + my $event = $dialog->waitForEvent(1000); + my $eventType = $event->eventType(); + + #event type checking + if ($eventType == $yui::YEvent::CancelEvent) { + last; + } + elsif ($eventType == $yui::YEvent::TimeoutEvent) { + my $t = Time::Piece->strptime($timeField->value(), "%H:%M:%S") + 1; + $timeField->setValue($t->strftime("%H:%M:%S")); + } + elsif ($eventType == $yui::YEvent::WidgetEvent) { + # widget selected + my $widget = $event->widget(); + if ($widget == $cancelButton) { + last; + } + elsif ($widget == $okButton) { + yui::YUI::app()->busyCursor(); + my $finished = 1; + # (1) write new TZ settings + # (2) write new NTP settigs if checked + # (3) use date time fields if NTP is not checked + + my $old_conf = $self->sh_tz->readConfiguration(); + if ($info->{time_zone}->{UTC} != $old_conf->{UTC} || + $info->{time_zone}->{ZONE} ne $old_conf->{ZONE}) { + # (1) + eval { $self->sh_tz->writeConfiguration($info->{time_zone}) }; + my $errors = $@; + if ($errors) { + $finished = 0; + $self->sh_gui->warningMsgBox({ + title => $self->loc->N("Write configuration failed"), + text => "$errors", + richtext => 1, + }); + } + } + if ($ntpFrame->value()) { + # (2) + if ($info->{ntp_server}) { + eval { $self->sh_tz->setNTPServer($info->{ntp_server}) }; + my $errors = $@; + if ($errors) { + $finished = 0; + $self->sh_gui->warningMsgBox({ + title => $self->loc->N("Set NTP failed"), + text => "$errors", + richtext => 1, + }); + } + } + else { + $self->sh_gui->warningMsgBox({text => $self->loc->N("Please enter a valid NTP server address.")}); + $finished = 0; + } + } + else { + my $t = Time::Piece->strptime($dateField->value()."T".$timeField->value(), + "%Y-%m-%dT%H:%M:%S" + ); + eval { + $self->sh_tz->disableAndStopNTP(); + # (3) + $self->sh_tz->setTime($t->epoch()); + }; + my $errors = $@; + if ($errors) { + $finished = 0; + $self->sh_gui->warningMsgBox({ + title => $self->loc->N("Set system time failed"), + text => "$errors", + richtext => 1, + }); + } + } + yui::YUI::app()->normalCursor(); + + last if ($finished); + } + elsif ($widget == $changeNTPButton) { + # get time to calculate elapsed + my $t0 = localtime; + my $item = $self->sh_gui->ask_fromTreeList({title => $self->loc->N("NTP server - DrakClock"), + header => $self->loc->N("Choose your NTP server"), + default_button => 1, + item_separator => '|', + default_item => $info->{ntp_server}, + skip_path => 1, + list => $NTPservers}); + if ($item) { + $ntpLabel->setValue($item); + $info->{ntp_server} = $item; + } + # fixing elapsed time (dialog is modal) + my $t1 = localtime; + my $elapsed = $t1->epoch - $t0->epoch; + + my $t = Time::Piece->strptime($dateField->value() . "T" . $timeField->value(), + '%Y-%m-%dT%H:%M:%S') + $elapsed; + $timeField->setValue($t->strftime("%H:%M:%S")); + $dateField->setValue($t->strftime("%F")); + } + elsif ($widget == $changeTZButton) { + # get time to calculate elapsed + my $t0 = localtime; + my $timezones = $self->sh_tz->getTimeZones(); + if (!$timezones || scalar (@{$timezones}) == 0) { + $self->sh_gui->warningMsgBox({title => $self->loc->N("Timezone - DrakClock"), + text => $self->loc->N("Failed to retrieve timezone list"), + }); + $changeTZButton->setDisabled(); + } + else { + my $item = $self->sh_gui->ask_fromTreeList({title => $self->loc->N("Timezone - DrakClock"), + header => $self->loc->N("Which is your timezone?"), + default_button => 1, + item_separator => '/', + default_item => $info->{time_zone}->{ZONE}, + list => $timezones}); + if ($item) { + my $utc = 0; + if ($info->{time_zone}->{UTC} ) { + $utc = $info->{time_zone}->{UTC}; + } + $utc = $self->sh_gui->ask_YesOrNo({ + title => $self->loc->N("GMT - manaclock"), + text => $self->loc->N("Is your hardware clock set to GMT?"), + default_button => 1, + }); + $info->{time_zone}->{UTC} = $utc; + $info->{time_zone}->{ZONE} = $item; + $timeZoneLbl->setValue($info->{time_zone}->{ZONE}); + } + } + # fixing elapsed time (dialog is modal) + my $t1 = localtime; + my $elapsed = $t1->epoch - $t0->epoch; + + my $t = Time::Piece->strptime($dateField->value() . "T" . $timeField->value(), + '%Y-%m-%dT%H:%M:%S') + $elapsed; + $timeField->setValue($t->strftime("%H:%M:%S")); + $dateField->setValue($t->strftime("%F")); + } + elsif ($widget == $resetButton) { + my $datetime_only = $self->sh_gui->ask_YesOrNo({ + title => $self->loc->N("Restore data"), + text => $self->loc->N("Restore date and time only?"), + default_button => 1, #Yes + }); + my $newInfo = $self->_restoreValues($datetime_only); + if ($datetime_only) { + $info->{date} = $newInfo->{date}; + $info->{time} = $newInfo->{time}; + } + else{ + $info = $newInfo; + } + + $dateField->setValue($info->{date}); + $timeField->setValue($info->{time}); + if (exists $info->{time_zone} && $info->{time_zone}->{ZONE}) { + $timeZoneLbl->setValue($info->{time_zone}->{ZONE}); + } + else { + $timeZoneLbl->setValue($self->loc->N("not defined")); + } + if ($info->{ntp_server}) { + $ntpLabel->setValue($info->{ntp_server}); + } + else { + $ntpLabel->setValue($self->loc->N("not defined")); + } + $ntpFrame->setValue($info->{ntp_running}); + } + elsif($widget == $aboutButton) { + my $translators = $self->loc->N("_: Translator(s) name(s) & email(s)\n"); + $translators =~ s/\/\>\;/g; + $self->sh_gui->AboutDialog({ name => $self->name, + version => $self->VERSION, + credits => $self->loc->N("Copyright (C) %s Mageia community", '2014-2015'), + license => $self->loc->N("GPLv2"), + description => $self->loc->N("Date, Clock & Time Zone Settings allows to setup time zone and adjust date and time"), + authors => $self->loc->N("

Developers

+
  • %s
  • +
  • %s
  • +
+

Translators

+
  • %s
", + "Angelo Naselli <anaselli\@linux.it>", + $translators + ), + } + ); + } + } + } + $dialog->destroy(); + + #restore old application title + yui::YUI::app()->setApplicationTitle($appTitle) if $appTitle; +} + + + diff --git a/lib/ManaTools/Module/DisplayManager.pm b/lib/ManaTools/Module/DisplayManager.pm new file mode 100644 index 00000000..39aa6175 --- /dev/null +++ b/lib/ManaTools/Module/DisplayManager.pm @@ -0,0 +1,298 @@ +# vim: set et ts=4 sw=4: +#***************************************************************************** +# +# Copyright (c) 2013-2015 Matteo Pasotti +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** + +package ManaTools::Module::DisplayManager; + +use Modern::Perl '2011'; +use autodie; +use Moose; +use POSIX qw(ceil); +use English; +use utf8; + +use yui; +use ManaTools::Shared qw(trim apcat); +use ManaTools::Shared::GUI; +# use ManaTools::Shared::DisplayManager; + +# TODROP but provides network::network +use lib qw(/usr/lib/libDrakX); +use network::network; +use MDK::Common::System qw(getVarsFromSh addVarsInSh); +use MDK::Common::Func qw(find); + +extends qw( ManaTools::Module ); + + +has '+icon' => ( + default => "/usr/share/mcc/themes/default/drakedm-mdk.png", +); + +has '+name' => ( + default => "DisplayManager", +); + +=head1 VERSION + +Version 1.0.0 + +=cut + +our $VERSION = '1.0.0'; + +has 'dialog' => ( + is => 'rw', + init_arg => undef +); + +has 'conffile' => ( + is => 'rw', + isa => 'Str', + default => '/etc/sysconfig/desktop', +); + +has 'dmlist' => ( + is => 'rw', + isa => 'ArrayRef', + builder => '_build_dmlist', +); + +has 'desc_for_i18n' => ( + is => 'rw', + isa => 'ArrayRef', +); + +has 'sh_gui' => ( + is => 'rw', + init_arg => undef, + builder => '_SharedUGUIInitialize' +); + +has 'loc' => ( + is => 'rw', + init_arg => undef, + builder => '_localeInitialize' +); + +sub _build_desc_for_i18n { + my $self = shift(); + + my @_DESCRIPTIONS_for_i18n = ( + $self->loc->N("LightDM (The Light Display Manager)"), + $self->loc->N("GDM (GNOME Display Manager)"), + $self->loc->N("KDM (KDE Display Manager)"), + $self->loc->N("XDM (X Display Manager)"), + ); + + $self->desc_for_i18n(\@_DESCRIPTIONS_for_i18n); + + return 1; +} + +sub _build_dmlist { + my $self = shift(); + + my @list = map { + my %l = map { /(\S+)=(.*)/ } apcat($_); + \%l; + } sort(glob("/usr/share/X11/dm.d/*.conf")); + return \@list; +} + +sub _localeInitialize { + my $self = shift(); + + # TODO fix domain binding for translation + $self->loc(ManaTools::Shared::Locales->new(domain_name => 'drakdm') ); + # TODO if we want to give the opportunity to test locally add dir_name => 'path' +} + +sub _SharedUGUIInitialize { + my $self = shift(); + + $self->sh_gui( ManaTools::Shared::GUI->new() ); +} + +#============================================================= + +=head2 start + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + This method extends Module::start and is invoked to + start proxy manager + +=cut + +#============================================================= +sub start { + my $self = shift; + + if ($EUID != 0) { + $self->sh_gui->warningMsgBox({ + title => $self->name, + text => $self->loc->N("root privileges required"), + }); + return; + } + + # initialize dm descriptions for i18n + $self->_build_desc_for_i18n(); + + $self->_manageProxyDialog(); +}; + +#============================================================= + +=head2 ask_for_X_restart + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + This method shows a message box warning the user + that a X server restart is required + +=cut + +#============================================================= + +sub ask_for_X_restart { + my $self = shift; + + $self->sh_gui->warningMsgBox({title=>$self->loc->N("X Restart Required"),text=>$self->loc->N("You need to log out and back in again for changes to take effect"),richtext=>1}); +} + +sub _manageProxyDialog { + my $self = shift; + + ## TODO fix for manatools + my $appTitle = yui::YUI::app()->applicationTitle(); + my $appIcon = yui::YUI::app()->applicationIcon(); + ## set new title to get it in dialog + my $newTitle = $self->loc->N("Display Manager"); + yui::YUI::app()->setApplicationTitle($newTitle); + + my $factory = yui::YUI::widgetFactory; + my $optional = yui::YUI::optionalWidgetFactory; + + my $label_width = 25; + my $inputfield_width = 45; + + my ($dm_NAME) = apcat($self->conffile) =~ /^DISPLAYMANAGER=(.*)/m; + my $dm = (MDK::Common::Func::find { uc($_->{NAME}) eq uc($dm_NAME) } @{$self->dmlist}); + + $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); + + # app description + my $hbox_content = $factory->createHBox($layout); + $factory->createLabel($hbox_content, $self->loc->N("Choosing a display manager")); + + $hbox_content = $factory->createHBox($layout); + + my $vbox_spacer = $factory->createVBox($hbox_content); + $factory->createHSpacing($vbox_spacer,2); + my $vbox_labels_flags = $factory->createVBox($hbox_content); + my $vbox_inputfields = $factory->createVBox($hbox_content); + + # list of desktop managers + my $rb_group = $factory->createRadioButtonGroup($vbox_labels_flags); + my $rbbox = $factory->createVBox($rb_group); + foreach my $d (@{$self->dmlist()}) + { + my $rowentry = $factory->createHBox($factory->createLeft($rbbox)); + my $rb = $factory->createRadioButton($rowentry, $d->{NAME}); + $rb->setWeight($yui::YD_HORIZ, 1); + my $desc = $factory->createLabel($rowentry, $self->loc->N($d->{DESCRIPTION})); + $desc->setWeight($yui::YD_HORIZ, 2); + if($d->{PACKAGE} eq lc($dm_NAME)) + { + $rb->setValue(1); + } + $rb_group->addRadioButton($rb); + $rb->DISOWN(); + } + my $hbox_filler = $factory->createHBox($layout); + $factory->createSpacing($hbox_filler,$yui::YD_VERT,2); + + 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,$self->loc->N("&About")); + my $cancelButton = $factory->createPushButton($vbox_foot_right,$self->loc->N("&Cancel")); + my $okButton = $factory->createPushButton($vbox_foot_right,$self->loc->N("&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 == $aboutButton) { + $self->sh_gui->AboutDialog({ + name => $appTitle, + version => $VERSION, + credits => "Copyright (c) 2013-2015 by Matteo Pasotti", + license => "GPLv2", + description => $self->loc->N("Graphical configurator for system Display Manager"), + authors => "Matteo Pasotti <matteo.pasotti\@gmail.com>" + } + ); + }elsif ($widget == $okButton) { + my $current_choice = ManaTools::Shared::trim($rb_group->currentButton()->label()); + $current_choice =~s/\&//g; + addVarsInSh($self->conffile, { DISPLAYMANAGER => lc($current_choice) } ); + $self->ask_for_X_restart(); + last; + } + } + } + + $self->dialog->destroy() ; + + #restore old application title + yui::YUI::app()->setApplicationTitle($appTitle); +} + +1; diff --git a/lib/ManaTools/Module/Firewall.pm b/lib/ManaTools/Module/Firewall.pm new file mode 100644 index 00000000..2ac56a59 --- /dev/null +++ b/lib/ManaTools/Module/Firewall.pm @@ -0,0 +1,1208 @@ +# vim: set et ts=4 sw=4: +#***************************************************************************** +# +# Copyright (c) 2013-2015 Matteo Pasotti +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** + +package ManaTools::Module::Firewall; + +use Modern::Perl '2011'; +use autodie; +use Moose; +use Moose::Autobox; +use utf8; + +use yui; +use ManaTools::Shared qw(trim); +use ManaTools::Shared::GUI; +use ManaTools::Shared::Firewall; +use ManaTools::Shared::Shorewall; +use ManaTools::Shared::Services; + +use MDK::Common::Func qw(if_ partition); +use MDK::Common::System qw(getVarsFromSh); +use MDK::Common::Various qw(text2bool to_bool); +use MDK::Common::DataStructure qw(intersection); +use MDK::Common::File qw(substInFile output_with_perm); + +use List::Util qw(any); +use List::MoreUtils qw(uniq); + +extends qw( ManaTools::Module ); + +has '+icon' => ( + default => "/usr/share/icons/manawall.png", +); + +has '+name' => ( + default => "Firewall Manager", +); + +=head1 VERSION + +Version 1.0.0 + +=cut + +our $VERSION = '1.0.0'; + +has 'dialog' => ( + is => 'rw', + init_arg => undef +); + +has 'sh_gui' => ( + is => 'rw', + init_arg => undef, + builder => '_SharedUGUIInitialize' +); + +has 'loc' => ( + is => 'rw', + init_arg => undef, + builder => '_localeInitialize', + required => 1, +); + +has 'all_servers' => ( + is => 'rw', + init_arg => undef, + isa => 'ArrayRef', +); + +has 'ifw_rules' => ( + is => 'rw', + init_arg => undef, + isa => 'ArrayRef', +); + +has 'wdg_ifw' => ( + is => 'rw', + init_arg => undef, + isa => 'ArrayRef', + default => sub { [] }, +); + +has 'wdg_servers' => ( + is => 'rw', + init_arg => undef, + isa => 'ArrayRef', + default => sub { [] }, +); + +has 'net' => ( + is => 'rw', + init_arg => undef, + isa => 'HashRef', + builder => '_initNet', +); + +has 'unlisted' => ( + is => 'rw', + init_arg => undef, + isa => 'ArrayRef', + builder => '_initUnlisted', +); + +has 'log_net_drop' => ( + is => 'rw', + isa => 'Bool', + default => sub { return 1; } +); + +has 'aboutDialog' => ( + is => 'ro', + init_arg => undef, + isa => 'HashRef', + builder => '_setupAboutDialog', +); + +sub _setupAboutDialog { + my $self = shift(); + return { + name => "", + version => $VERSION, + credits => "Copyright (c) 2013-2015 by Matteo Pasotti", + license => "GPLv2", + description => "", + authors => "Matteo Pasotti <matteo.pasotti\@gmail.com>" + }; +} + +sub _localeInitialize { + my $self = shift(); + + # TODO fix domain binding for translation + $self->loc(ManaTools::Shared::Locales->new(domain_name => 'drakx-net') ); + # TODO if we want to give the opportunity to test locally add dir_name => 'path' +} + +sub _SharedUGUIInitialize { + my $self = shift(); + + $self->sh_gui(ManaTools::Shared::GUI->new() ); +} + +sub _initAllServers { + my $self = shift(); + my @all_servers = ( + { + id => 'www', + name => $self->loc->N("Web Server"), + pkg => 'apache apache-mod_perl boa lighttpd thttpd', + ports => '80/tcp 443/tcp', + }, + { + id => 'dns', + name => $self->loc->N("Domain Name Server"), + pkg => 'bind dnsmasq mydsn', + ports => '53/tcp 53/udp', + }, + { + id => 'ssh', + name => $self->loc->N("SSH server"), + pkg => 'openssh-server', + ports => '22/tcp', + }, + { + id => 'ftp', + name => $self->loc->N("FTP server"), + pkg => 'ftp-server-krb5 wu-ftpd proftpd pure-ftpd', + ports => '20/tcp 21/tcp', + }, + { + id => 'dhcp', + name => $self->loc->N("DHCP Server"), + pkg => 'dhcp-server udhcpd', + ports => '67/udp 68/udp', + hide => 1, + }, + { + id => 'mail', + name => $self->loc->N("Mail Server"), + pkg => 'sendmail postfix qmail exim', + ports => '25/tcp 465/tcp 587/tcp', + }, + { + id => 'popimap', + name => $self->loc->N("POP and IMAP Server"), + pkg => 'imap courier-imap-pop', + ports => '109/tcp 110/tcp 143/tcp 993/tcp 995/tcp', + }, + { + id => 'telnet', + name => $self->loc->N("Telnet server"), + pkg => 'telnet-server-krb5', + ports => '23/tcp', + hide => 1, + }, + { + id => 'nfs', + name => $self->loc->N("NFS Server"), + pkg => 'nfs-utils nfs-utils-clients', + ports => '111/tcp 111/udp 2049/tcp 2049/udp ' . network::nfs::list_nfs_ports(), + hide => 1, + prepare => sub { network::nfs::write_nfs_ports(network::nfs::read_nfs_ports()) }, + restart => 'nfs-common nfs-server', + }, + { + id => 'smb', + name => $self->loc->N("Windows Files Sharing (SMB)"), + pkg => 'samba-server', + ports => '137/tcp 137/udp 138/tcp 138/udp 139/tcp 139/udp 445/tcp 445/udp 1024:1100/tcp 1024:1100/udp', + hide => 1, + }, + { + id => 'bacula', + name => $self->loc->N("Bacula backup"), + pkg => 'bacula-fd bacula-sd bacula-dir-common', + ports => '9101:9103/tcp', + hide => 1, + }, + { + id => 'syslog', + name => $self->loc->N("Syslog network logging"), + pkg => 'rsyslog syslog-ng', + ports => '514/udp', + hide => 1, + }, + { + id => 'cups', + name => $self->loc->N("CUPS server"), + pkg => 'cups', + ports => '631/tcp 631/udp', + hide => 1, + }, + { + id => 'mysql', + name => $self->loc->N("MySQL server"), + pkg => 'mysql', + ports => '3306/tcp 3306/udp', + hide => 1, + }, + { + id => 'postgresql', + name => $self->loc->N("PostgreSQL server"), + pkg => 'postgresql8.2 postgresql8.3', + ports => '5432/tcp 5432/udp', + hide => 1, + }, + { + id => 'echo', + name => $self->loc->N("Echo request (ping)"), + ports => '8/icmp', + force_default_selection => 0, + }, + { + id => 'zeroconf', + name => $self->loc->N("Network services autodiscovery (zeroconf and slp)"), + ports => '5353/udp 427/udp', + pkg => 'avahi cups openslp', + }, + { + id => 'bittorrent', + name => $self->loc->N("BitTorrent"), + ports => '6881:6999/tcp 6881:6999/udp', + hide => 1, + pkg => 'bittorrent deluge ktorrent transmission vuze rtorrent ctorrent', + }, + { + id => 'wmds', + name => $self->loc->N("Windows Mobile device synchronization"), + pkg => 'synce-hal', + ports => '990/tcp 999/tcp 5678/tcp 5679/udp 26675/tcp', + hide => 1, + }, + ); + return \@all_servers; +} + +sub _initIFW { + my $self = shift(); + my @ifw_rules = ( + { + id => 'psd', + name => $self->loc->N("Port scan detection"), + ifw_rule => 'psd', + }, + ); + return \@ifw_rules; +} + +sub _initNet { + my $self = shift(); + my $net = {}; + network::network::read_net_conf($net); + return $net; +} + +sub _initUnlisted { + my $self = shift(); + my @unlisted = (); + return \@unlisted; +} + +#============================================================= + +sub check_ports_syntax { + my ($ports) = @_; + foreach (split ' ', $ports) { + my ($nb, $range, $nb2) = m!^(\d+)(:(\d+))?/(tcp|udp|icmp)$! or return $_; + foreach my $port ($nb, if_($range, $nb2)) { + 1 <= $port && $port <= 65535 or return $_; + } + $nb < $nb2 or return $_ if $range; + } + return ''; +} + +#============================================================= + +=head2 port2server + +=head3 INPUT + + $self: this object + + $ports: port object + +=head3 DESCRIPTION + + This method retrieves the server from a given port + +=cut + +#============================================================= + +sub port2server { + my $self = shift(); + my ($port) = @_; + for my $service(@{$self->all_servers()}) + { + if(any { $port eq $_ } split(' ', $service->{ports})) + { + return $service; + } + } + return 0; +} + +#============================================================= + +=head2 to_ports + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + This method converts from server definitions to port definitions + +=cut + +#============================================================= + +sub to_ports { + my ($self, $servers) = @_; + my $ports = join(' ', (map { $_->{ports} } @$servers), @{$self->unlisted()}); + return $ports; +} + +#============================================================= + +=head2 from_ports + +=head3 INPUT + + $self: this object + + $ports: ports object + +=head3 DESCRIPTION + + This method does... + +=cut + +#============================================================= + +sub from_ports { + my $self = shift(); + my ($ports) = @_; + + my @l; + foreach (split ' ', $ports) { + if (my $s = $self->port2server($_)) { + push @l, $s; + } else { + push (@{$self->unlisted()}, $_); + } + } + my @result = [ uniq(@l) ], join(' ', @{$self->unlisted()}); + return \@result; +} + +#============================================================= + +=head2 get_conf + +=head3 INPUT + + $self: this object + + $disabled: boolean + + $o_ports: object representing ports + +=head3 DESCRIPTION + + This method retrieves the configuration + +=cut + +#============================================================= + +sub get_conf { + my $self = shift(); + my ($disabled, $o_ports) = @_; + my $possible_servers = undef; + my $conf = ManaTools::Shared::Shorewall::read_(); + my $shorewall = (ManaTools::Shared::Shorewall::get_config_file('zones', '') && $conf); + + if ($o_ports) { + return ($disabled, $self->from_ports($o_ports)); + } elsif ($shorewall) { + # WARNING: this condition fails (the method fails) + # if manawall runs as unprivileged user + # cause it can't read the interfaces file + return ($shorewall->{disabled}, $self->from_ports($shorewall->{ports}), $shorewall->{log_net_drop}); + } else { + $self->sh_gui->ask_OkCancel({ + title => $self->loc->N("Firewall configuration"), + text => $self->loc->N("drakfirewall configurator + This configures a personal firewall for this Mageia machine."), + richtext => 1 + }) or return; + + $self->sh_gui->ask_OkCancel({ + title => $self->loc->N("Firewall configuration"), + text => $self->loc->N("drakfirewall configurator +Make sure you have configured your Network/Internet access with +drakconnect before going any further."), + richtext => 1 + }) or return; + + return($disabled, $possible_servers, ''); + } +} + +sub set_ifw { + # my ($do_pkgs, $enabled, $rules, $ports) = @_; + my $self = shift(); + my ($enabled, $rules, $ports) = @_; + if ($enabled) + { + my $ports_by_proto = ManaTools::Shared::Shorewall::ports_by_proto($ports); + output_with_perm("$::prefix/etc/ifw/rules", 0644, + (map { ". /etc/ifw/rules.d/$_\n" } @$rules), + map { + my $proto = $_; + map { + my $multiport = /:/ && " -m multiport"; + "iptables -A Ifw -m conntrack --ctstate NEW -p $proto$multiport --dport $_ -j IFWLOG --log-prefix NEW\n"; + } @{$ports_by_proto->{$proto}}; + } intersection([ qw(tcp udp) ], [ keys %$ports_by_proto ]), + ); + } + + substInFile { + undef $_ if m!^INCLUDE /etc/ifw/rules|^iptables -I INPUT 2 -j Ifw!; + } "$::prefix/etc/shorewall/start"; + ManaTools::Shared::Shorewall::set_in_file('start', $enabled, "INCLUDE /etc/ifw/start", "INCLUDE /etc/ifw/rules", "iptables -I INPUT 1 -j Ifw"); + ManaTools::Shared::Shorewall::set_in_file('stop', $enabled, "iptables -D INPUT -j Ifw", "INCLUDE /etc/ifw/stop"); +} + +#============================================================= + +=head2 choose_watched_services + +=head3 INPUT + + $self: this object + + $servers: array of hashes representing servers + +=head3 DESCRIPTION + + This method shows the main dialog to let users choose the allowed services + +=cut + +#============================================================= + +sub choose_watched_services { + my ($self, $servers) = @_; + + my @l = (@{$self->ifw_rules()}, @$servers, map { { ports => $_ } } @{$self->unlisted()}); + + my $enabled = 1; + $_->{ifw} = 1 foreach @l; + + my $retval = $self->ask_WatchedServices({ + title => $self->loc->N("Interactive Firewall"), + icon => $self->icon(), + # if_(!$::isEmbedded, banner_title => N("Interactive Firewall")), + messages => + $self->loc->N("You can be warned when someone accesses to a service or tries to intrude into your computer. +Please select which network activities should be watched."), + }, + [ + { + id=>'useifw', + text => $self->loc->N("Use Interactive Firewall"), + val => $enabled, + type => 'bool' + }, + map { + { + text => (exists $_->{name} ? $_->{name} : $_->{ports}), + val => $_->{ifw}, + type => 'bool', + id => $_->{id}, + }, + } @l, + ]); + + return if($retval == 0); + + for my $server(@{$self->wdg_ifw()}) + { + for my $k(keys @l) + { + if(defined($l[$k]->{id}) && defined($server->{id})) + { + if($server->{id} eq 'useifw') + { + $enabled = $server->{value}; + } + else + { + if($l[$k]->{id} eq $server->{id}) + { + $l[$k]->{ifw} = $server->{value}; + last; + } + } + } + } + } + + my ($rules, $ports) = partition { exists $_->{ifw_rule} } grep { $_->{ifw} } @l; + $self->set_ifw($enabled, [ map { $_->{ifw_rule} } @$rules ], $self->to_ports($ports)); + + # return something to say that we are done ok + return ($rules, $ports); +} + +#============================================================= + +sub ask_WatchedServices { + my $self = shift; + + my ($dlg_data, + $items) = @_; + + my $old_title = yui::YUI::app()->applicationTitle(); + + ## set new title to get it in dialog + yui::YUI::app()->setApplicationTitle($dlg_data->{title}); + + 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, $dlg_data->{icon}); + my $labelAppDescription = $factory->createLabel($headRight,$dlg_data->{messages}); + $logoImage->setWeight($yui::YD_HORIZ,0); + $labelAppDescription->setWeight($yui::YD_HORIZ,3); + + my $hbox_content = $factory->createHBox($layout); + + my $widgetContainer = $factory->createVBox($hbox_content); + + + foreach my $item(@{$items}) + { + if(defined($item->{label})) + { + $factory->createLabel($factory->createLeft($factory->createHBox($widgetContainer)), $item->{label}); + } + elsif(defined($item->{text})) + { + my $ckbox = $factory->createCheckBox( + $factory->createLeft($factory->createHBox($widgetContainer)), + $item->{text}, + $item->{val} + ); + $ckbox->setNotify(1); + push @{$self->wdg_ifw()}, { + id => $item->{id}, + widget => \$ckbox, + value => $item->{val}, + }; + $ckbox->DISOWN(); + } + } + + 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,$self->loc->N("&About")); + my $cancelButton = $factory->createPushButton($vbox_foot_right,$self->loc->N("&Cancel")); + my $okButton = $factory->createPushButton($vbox_foot_right,$self->loc->N("&OK")); + + my $retval = 0; + + # 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(); + + # loop on every checkbox representing servers + foreach my $server(@{$self->wdg_ifw()}) + { + if($widget == ${$server->{widget}}) + { + if($server->{id} eq 'useifw') + { + if(!${$server->{widget}}->value()) + { + yui::YUI::ui()->blockEvents(); + foreach my $server(@{$self->wdg_ifw()}) + { + if($server->{id} ne 'useifw') + { + ${$server->{widget}}->setValue(0); + $server->{value} = ${$server->{widget}}->value(); + } + } + yui::YUI::ui()->unblockEvents(); + last; + } + } + else + { + $server->{value} = ${$server->{widget}}->value(); + } + } + } + if ($widget == $cancelButton) { + last; + }elsif ($widget == $aboutButton) { + my $abtdlg = $self->aboutDialog(); + $abtdlg->{name} = $dlg_data->{title}; + $abtdlg->{description} = $self->loc->N("Graphical manager for interactive firewall rules"); + $self->sh_gui->AboutDialog($abtdlg + ); + }elsif ($widget == $okButton) { + $retval = 1; + last; + } + } + } + + $self->dialog->destroy(); + + #restore old application title + yui::YUI::app()->setApplicationTitle($old_title); + + return $retval; +} + + +#============================================================= + +=head2 choose_allowed_services + +=head3 INPUT + + $self: this object + + $disabled: boolean + + $servers: array of hashes representing servers + +=head3 DESCRIPTION + + This method shows the main dialog to let users choose the allowed services + +=cut + +#============================================================= + +sub choose_allowed_services { + my ($self, $disabled, $servers) = @_; + + $_->{on} = 0 foreach @{$self->all_servers()}; + $_->{on} = 1 foreach @$servers; + my @l = grep { $_->{on} || !$_->{hide} } @{$self->all_servers()}; + + my $dialog_data = { + title => $self->loc->N("Firewall"), + icon => $self->icon(), + # if_(!$::isEmbedded, banner_title => $self->loc->N("Firewall")), + banner_title => $self->loc->N("Firewall"), + }; + + my $items = [ + { label => $self->loc->N("Which services would you like to allow the Internet to connect to?"), title => 1 }, + if_($self->net()->{PROFILE} && network::network::netprofile_count() > 0, { label => $self->loc->N("Those settings will be saved for the network profile %s", $self->net()->{PROFILE}) }), + { text => $self->loc->N("Everything (no firewall)"), val => \$disabled, type => 'bool' }, + (map { { text => $_->{name}, val => \$_->{on}, type => 'bool', disabled => sub { $disabled }, id => $_->{id} } } @l), + ]; + + return if(!$self->ask_AllowedServices($dialog_data, $items)); + + for my $server(@{$self->wdg_servers()}) + { + for my $k(keys @l) + { + if(defined($l[$k]->{id}) && defined($server->{id})) + { + if($l[$k]->{id} eq $server->{id}) + { + $l[$k]->{on} = ${$server->{value}}; + last; + } + } + else + { + # fake server, the checkbox allowing the user to disable the firewall + # if Everything checkbox is selected, value = 1 then firewall disabled = 1 + $disabled = ${$server->{value}}; + last; + } + } + } + + return ($disabled, [ grep { $_->{on} } @l ]); +} + +#============================================================= + +sub ask_AllowedServices { + my $self = shift; + + my ($dlg_data, + $items) = @_; + + my $old_title = yui::YUI::app()->applicationTitle(); + + ## set new title to get it in dialog + yui::YUI::app()->setApplicationTitle($dlg_data->{title}); + + 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, $dlg_data->{icon}); + my $labelAppDescription = $factory->createLabel($headRight,$dlg_data->{title}); + $logoImage->setWeight($yui::YD_HORIZ,0); + $labelAppDescription->setWeight($yui::YD_HORIZ,3); + + my $hbox_content = $factory->createHBox($layout); + + my $widgetContainer = $factory->createVBox($hbox_content); + + my $evry = undef; + + foreach my $item(@{$items}) + { + if(defined($item->{label})) + { + $factory->createLabel($factory->createLeft($factory->createHBox($widgetContainer)), $item->{label}); + } + elsif(defined($item->{text})) + { + my $ckbox = $factory->createCheckBox( + $factory->createLeft($factory->createHBox($widgetContainer)), + $item->{text}, + ${$item->{val}} + ); + $ckbox->setNotify(1); + if(!defined($item->{id})) + { + $evry = $ckbox; + } + if(defined($item->{disabled})) + { + $ckbox->setEnabled(!$item->{disabled}->()); + } + push @{$self->wdg_servers()}, { + id => $item->{id}, + widget => \$ckbox, + value => $item->{val}, + }; + $ckbox->DISOWN(); + } + } + + 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 $advButton = $factory->createPushButton($vbox_foot_left,$self->loc->N("A&dvanced")); + my $aboutButton = $factory->createPushButton($vbox_foot_left,$self->loc->N("&About")); + my $cancelButton = $factory->createPushButton($vbox_foot_right,$self->loc->N("&Cancel")); + my $okButton = $factory->createPushButton($vbox_foot_right,$self->loc->N("&OK")); + + my $retval = 0; + + # 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(); + + # loop on every checkbox representing servers + foreach my $server(@{$self->wdg_servers()}) + { + if($widget == ${$server->{widget}}) + { + ${$server->{value}} = !${$server->{value}}; + } + } + + if ($widget == $cancelButton) { + last; + }elsif ($widget == $aboutButton) { + my $abtdlg = $self->aboutDialog(); + $abtdlg->{name} = $dlg_data->{title}; + $abtdlg->{description} = $self->loc->N("Graphical manager for firewall rules"); + $self->sh_gui->AboutDialog($abtdlg); + }elsif ($widget == $okButton) { + $retval = 1; + last; + } + elsif ($widget == $advButton) { + $self->ask_CustomPorts(); + } + elsif ($widget == $evry) { + foreach my $wdg_ckbox(@{$self->wdg_servers()}) + { + if(defined($wdg_ckbox->{id})) + { + ${$wdg_ckbox->{widget}}->setEnabled(!${$wdg_ckbox->{widget}}->isEnabled()); + } + } + } + } + } + + $self->dialog->destroy(); + + #restore old application title + yui::YUI::app()->setApplicationTitle($old_title); + + return $retval; +} + +sub ask_CustomPorts { + my $self = shift(); + + my $adv_msg = $self->loc->N("You can enter miscellaneous ports. +Valid examples are: 139/tcp 139/udp 600:610/tcp 600:610/udp. +Have a look at /etc/services for information."); + + my $old_title = yui::YUI::app()->applicationTitle(); + my $win_title = $self->loc->N("Define miscellaneus ports"); + + ## set new title to get it in dialog + yui::YUI::app()->setApplicationTitle($win_title); + + my $factory = yui::YUI::widgetFactory; + my $optional = yui::YUI::optionalWidgetFactory; + + my $advdlg = $factory->createPopupDialog(); + my $layout = $factory->createVBox($advdlg); + + my $hbox_header = $factory->createHBox($layout); + my $headLeft = $factory->createHBox($factory->createLeft($hbox_header)); + my $headRight = $factory->createHBox($factory->createRight($hbox_header)); + + my $labelAppDescription = $factory->createLabel($headRight,$self->loc->N("Other ports")); + $labelAppDescription->setWeight($yui::YD_HORIZ,3); + + my $hbox_content = $factory->createHBox($layout); + my $vbox_inputs = $factory->createVBox($hbox_content); + my $labelAdvMessage = $factory->createLabel($factory->createHBox($vbox_inputs), $adv_msg); + my $txtPortsList = $factory->createInputField($vbox_inputs,''); + $txtPortsList->setValue(join(' ',@{$self->unlisted()})); + my $ckbLogFWMessages = $factory->createCheckBox($factory->createHBox($vbox_inputs), $self->loc->N("Log firewall messages in system logs"), $self->log_net_drop()); + 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 $cancelButton = $factory->createPushButton($vbox_foot_right,$self->loc->N("&Cancel")); + my $okButton = $factory->createPushButton($vbox_foot_right,$self->loc->N("&OK")); + + my $retval = 0; + + # main loop + while(1) { + my $event = $advdlg->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 ) + { + $retval = 0; + last; + } + elsif( $widget == $okButton ) + { + if(scalar(@{$self->unlisted()}) > 0) + { + $self->unlisted([]); + } + my $invalid_ports = check_ports_syntax($txtPortsList->value()); + if(ManaTools::Shared::trim($invalid_ports) eq '') + { + if($txtPortsList->value() =~m/\s+/g) + { + my @unlstd = split(' ', $txtPortsList->value()); + foreach my $p(@unlstd) + { + push(@{$self->unlisted()},$p); + } + } + else + { + if(ManaTools::Shared::trim($txtPortsList->value()) ne '') + { + push(@{$self->unlisted()}, ManaTools::Shared::trim($txtPortsList->value())); + } + } + $retval = 1; + } + else + { + $self->sh_gui->warningMsgBox({ + title=>$self->loc->N("Invalid port given"), + text=> $self->loc->N("Invalid port given: %s. +The proper format is \"port/tcp\" or \"port/udp\", +where port is between 1 and 65535. + +You can also give a range of ports (eg: 24300:24350/udp)", $invalid_ports) + }); + $retval = 0; + } + last; + } + } + } + + $advdlg->destroy(); + + #restore old application title + yui::YUI::app()->setApplicationTitle($old_title); + + return $retval; +} + +sub get_zones { + my $self = shift(); + my $confref = shift(); + my $disabled = shift(); + my $conf = ${$confref}; + my $interfacesfile = ManaTools::Shared::Shorewall::get_config_file('interfaces', $conf->{version} || ''); + network::network::read_net_conf($self->net()); + #- find all interfaces but alias interfaces + my @all_intf = grep { !/:/ } uniq(keys(%{$self->net()->{ifcfg}}), detect_devices::get_net_interfaces()); + my %net_zone = map { $_ => undef } @all_intf; + $net_zone{$_} = 1 foreach ManaTools::Shared::Shorewall::get_net_zone_interfaces($interfacesfile, $self->net(), \@all_intf); + + # if firewall/shorewall is not disabled (i.e. everything has been allowed) + # then ask for network interfaces to protect + if(!$disabled) + { + my $retvals = $self->sh_gui->ask_multiple_fromList({ + title => $self->loc->N("Firewall configuration"), + header => $self->loc->N("Please select the interfaces that will be protected by the firewall. + +All interfaces directly connected to Internet should be selected, +while interfaces connected to a local network may be unselected. + +If you intend to use Mageia Internet Connection sharing, +unselect interfaces which will be connected to local network. + +Which interfaces should be protected? +"), + list => [ + map { + { + id => $_, + text => network::tools::get_interface_description($self->net(), $_), + val => \$net_zone{$_}, + type => 'bool' + }; + } (sort keys %net_zone) ] + }); + + if(!defined($retvals)) + { + return 0; + } + else + { + # it was: ($conf->{net_zone}, $conf->{loc_zone}) = partition { $net_zone{$_} } keys %net_zone; + foreach my $net_int (@{$retvals}) + { + push (@{$conf->{net_zone}}, $net_int); + } + return $retvals; + } + } + + foreach my $net_int(keys %net_zone) + { + push (@{$conf->{net_zone}}, $net_int); + } + return keys %net_zone; +} + +#============================================================= + +=head2 set_ports + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + This method extends Module::start and is invoked to + start host manager + +=cut + +#============================================================= + +sub set_ports { + my ($self, $disabled, $ports, $log_net_drop) = @_; + + if (!$disabled || -x "$::prefix/sbin/shorewall") { + # $do_pkgs->ensure_files_are_installed([ [ qw(shorewall shorewall) ], [ qw(shorewall-ipv6 shorewall6) ] ], $::isInstall) or return; + my $conf = ManaTools::Shared::Shorewall::read_(); + if(!$self->get_zones(\$conf,$disabled)) + { + # Cancel button has been pressed, aborting + return 0; + } + my $shorewall = (ManaTools::Shared::Shorewall::get_config_file('zones', '') && $conf); + if (!$shorewall) { + print ("unable to read shorewall configuration, skipping installation"); + return 0; + } + + $shorewall->{disabled} = $disabled; + $shorewall->{ports} = $ports; + $shorewall->{log_net_drop} = $log_net_drop; + + print ($disabled ? "disabling shorewall" : "configuring shorewall to allow ports: $ports"); + + # NOTE: the 2nd param is undef in this case! + if(!ManaTools::Shared::Shorewall::write_($shorewall)) + { + # user action request + my $action = $self->sh_gui->ask_fromList({ + title => $self->loc->N("Firewall"), + header => $self->loc->N("Your firewall configuration has been manually edited and contains + rules that may conflict with the configuration that has just been set up. + What do you want to do?"), + list => [ "keep", "drop"], + default => "keep", + }); + ManaTools::Shared::Shorewall::write_($shorewall,$action); + return 1; + } + } + return 0; +} + +#============================================================= + +=head2 start + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + This method extends Module::start and is invoked to + start host manager + +=cut + +#============================================================= + +sub start { + my $self = shift; + + my @server = (); + $self->wdg_servers(@server); + + # init servers definitions + $self->all_servers($self->_initAllServers()); + + # initialize ifw_rules here + $self->ifw_rules($self->_initIFW()); + + my ($disabled, $servers, $log_net_drop) = $self->get_conf(undef) or return; + + # $log_net_drop: network::shorewall log_net_drop attribute + $self->log_net_drop($log_net_drop); + undef($log_net_drop); + ($disabled, $servers) = $self->choose_allowed_services($disabled, @$servers) or return; + + my $system_file = '/etc/sysconfig/drakx-net'; + my %global_settings = getVarsFromSh($system_file); + + if (!$disabled && (!defined($global_settings{IFW}) || text2bool($global_settings{IFW}))) { + $self->choose_watched_services($servers) or return; + } + + # preparing services when required ( look at $self->all_servers() ) + foreach (@$servers) { + exists $_->{prepare} and $_->{prepare}(); + } + + my $ports = $self->to_ports($servers); + + $self->set_ports($disabled, $ports, $self->log_net_drop()) or return; + + # restart mandi + my $services = ManaTools::Shared::Services->new(); + $services->is_service_running("mandi") and $services->restart("mandi"); + + # restarting services if needed + foreach my $service (@$servers) { + if ($service->{restart}) { + $services->is_service_running($_) and $services->restart($_) foreach split(' ', $service->{restart}); + } + } + + # clearing pending ifw notifications in net_applet + system('killall -s SIGUSR1 net_applet'); + + return ($disabled, $ports); +}; + +1; diff --git a/lib/ManaTools/Module/Hosts.pm b/lib/ManaTools/Module/Hosts.pm new file mode 100644 index 00000000..faae3f0e --- /dev/null +++ b/lib/ManaTools/Module/Hosts.pm @@ -0,0 +1,530 @@ +# vim: set et ts=4 sw=4: +#***************************************************************************** +# +# Copyright (c) 2013-2015 Matteo Pasotti +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** + +package ManaTools::Module::Hosts; + +use Modern::Perl '2011'; +use autodie; +use Moose; +use POSIX qw(ceil); +use utf8; + +use Glib; +use yui; +use ManaTools::Shared qw(trim); +use ManaTools::Shared::GUI; +use ManaTools::Shared::Hosts; + +extends qw( ManaTools::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 +); + +has 'sh_gui' => ( + is => 'rw', + init_arg => undef, + builder => '_SharedUGUIInitialize' +); + +has 'loc' => ( + is => 'rw', + init_arg => undef, + builder => '_localeInitialize' +); + +sub _localeInitialize { + my $self = shift(); + + # TODO fix domain binding for translation + $self->loc(ManaTools::Shared::Locales->new(domain_name => 'drakx-net') ); + # TODO if we want to give the opportunity to test locally add dir_name => 'path' +} + +sub _SharedUGUIInitialize { + my $self = shift(); + + $self->sh_gui(ManaTools::Shared::GUI->new() ); +} + +#============================================================= + +=head2 start + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + This method extends Module::start and is invoked to + start host manager + +=cut + +#============================================================= +sub start { + my $self = shift; + + $self->_manageHostsDialog(); +}; + +#============================================================= + +=head2 _changeHostNameDialog + +=head3 INPUT + + $self: this object + + $headerString: a title for the dialog + +=head3 DESCRIPTION + + This method display a dialog allowing the user + to change the hostname + +=cut + +#============================================================= +sub _changeHostNameDialog { + my $self = shift; + + my $headerString = 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 $fourthHbox = $factory->createHBox($vbox_content); + my $fifthHbox = $factory->createHBox($vbox_content); + my $sixthHbox = $factory->createHBox($vbox_content); + + my $labelHostName = $factory->createLabel($secondHbox,$self->loc->N("Hostname")); + $labelHostName->setWeight($yui::YD_HORIZ, 10); + my $textHostName = $factory->createInputField($secondHbox,""); + $textHostName->setWeight($yui::YD_HORIZ, 30); + + my $labelPrettyHostName = $factory->createLabel($thirdHbox,$self->loc->N("Pretty Hostname")); + $labelPrettyHostName->setWeight($yui::YD_HORIZ, 10); + my $textPrettyHostName = $factory->createInputField($thirdHbox,""); + $textPrettyHostName->setWeight($yui::YD_HORIZ, 30); + + my $labelStaticHostName = $factory->createLabel($fourthHbox,$self->loc->N("Static Hostname")); + $labelStaticHostName->setWeight($yui::YD_HORIZ, 10); + my $textStaticHostName = $factory->createInputField($fourthHbox,""); + $textStaticHostName->setWeight($yui::YD_HORIZ, 30); + + my $labelChassis = $factory->createLabel($fifthHbox,$self->loc->N("Chassis")); + $labelChassis->setWeight($yui::YD_HORIZ, 10); + my $textChassis = $factory->createInputField($fifthHbox,""); + $textChassis->setWeight($yui::YD_HORIZ, 30); + + my $labelIconName = $factory->createLabel($sixthHbox,$self->loc->N("Icon Name")); + $labelIconName->setWeight($yui::YD_HORIZ, 10); + my $textIconName = $factory->createInputField($sixthHbox,""); + $textIconName->setWeight($yui::YD_HORIZ, 30); + + $textHostName->setValue($self->cfgHosts->_getLocalHostName()); + $textPrettyHostName->setValue($self->cfgHosts->_getLocalPrettyHostName()); + $textStaticHostName->setValue($self->cfgHosts->_getLocalStaticHostName()); + $textChassis->setValue($self->cfgHosts->_getLocalChassis()); + $textIconName->setValue($self->cfgHosts->_getLocalIconName()); + + # footer + my $cancelButton = $factory->createPushButton($factory->createLeft($hbox_footer),$self->loc->N("&Cancel")); + my $okButton = $factory->createPushButton($factory->createRight($hbox_footer),$self->loc->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 == $okButton) { + $self->cfgHosts->_setLocalHostName($textHostName->value()); + $self->cfgHosts->_setLocalPrettyHostName($textPrettyHostName->value()); + $self->cfgHosts->_setLocalStaticHostName($textStaticHostName->value()); + $self->cfgHosts->_setLocalChassis($textChassis->value()); + $self->cfgHosts->_setLocalIconName($textIconName->value()); + last; + } + } + } + + destroy $dlg; +} + +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,$self->loc->N("IP Address")); + my $labelHostName = $factory->createLabel($secondHbox,$self->loc->N("Hostname")); + my $labelHostAlias = $factory->createLabel($thirdHbox,$self->loc->N("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),$self->loc->N("&Cancel")); + my $okButton = $factory->createPushButton($factory->createRight($hbox_footer),$self->loc->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 == $okButton) { + my $res = undef; + my @hosts_toadd; + push @hosts_toadd, $textHostName->value(); + if(ManaTools::Shared::trim($textHostAlias->value()) ne ""){ + push @hosts_toadd, $textHostAlias->value(); + } + if($boolEdit == 0){ + $res = $self->cfgHosts->_insertHost($textIPAddress->value(),[@hosts_toadd]); + }else{ + $res = $self->cfgHosts->_modifyHost($textIPAddress->value(),[@hosts_toadd]); + } + $res = $self->cfgHosts->_writeHosts(); + last; + } + } + } + + destroy $dlg; +} + +#============================================================= + +=head2 _addHostDialog + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + +This subroutine creates the Host dialog to add host definitions + +=cut + +#============================================================= + +sub _addHostDialog { + my $self = shift(); + return $self->_manipulateHostDialog($self->loc->N("Add the information"),0); +} + +#============================================================= + +=head2 _edtHostDialog + +=head3 INPUT + +=over 4 + +=item $self: this object + +=item B<$hostIp> : the ip of the host entry that we want to modify + +=item B<$hostName> : the name of the host entry we want to modify + +=item B<$hostAliases> : aliases of the host entry we want to modify + +=back + +=head3 DESCRIPTION + +This subroutine creates the Host dialog to modify host definitions + +=cut + +#============================================================= + +sub _edtHostDialog { + my $self = shift(); + my $hostIp = shift(); + my $hostName = shift(); + my $hostAliases = shift(); + return $self->_manipulateHostDialog($self->loc->N("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 manatools + my $appTitle = yui::YUI::app()->applicationTitle(); + my $appIcon = yui::YUI::app()->applicationIcon(); + ## set new title to get it in dialog + my $newTitle = $self->loc->N("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($self->loc->N("IP Address")); + $tableHeader->addColumn($self->loc->N("Hostname")); + $tableHeader->addColumn($self->loc->N("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(ManaTools::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),$self->loc->N("A&dd")); + my $edtButton = $factory->createPushButton($factory->createHBox($vbox_commands),$self->loc->N("&Edit")); + my $remButton = $factory->createPushButton($factory->createHBox($vbox_commands),$self->loc->N("&Remove")); + my $hnButton = $factory->createPushButton($factory->createHBox($vbox_commands),$self->loc->N("&Hostname")); + $addButton->setWeight($yui::YD_HORIZ,1); + $edtButton->setWeight($yui::YD_HORIZ,1); + $remButton->setWeight($yui::YD_HORIZ,1); + $hnButton->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,$self->loc->N("&About")); + my $cancelButton = $factory->createPushButton($vbox_foot_right,$self->loc->N("&Cancel")); + my $okButton = $factory->createPushButton($vbox_foot_right,$self->loc->N("&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($self->sh_gui->ask_YesOrNo({title => $self->loc->N("Confirmation"), text => $self->loc->N("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 == $hnButton) { + $self->_changeHostNameDialog("Change the HostName FQDN"); + $self->setupTable(); + }elsif ($widget == $aboutButton) { + $self->sh_gui->AboutDialog({ + name => $appTitle, + version => $VERSION, + credits => "Copyright (c) 2013-2015 by Matteo Pasotti", + license => "GPLv2", + description => $self->loc->N("Graphical manager for hosts definitions"), + 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/ManaTools/Module/LogViewer.pm b/lib/ManaTools/Module/LogViewer.pm new file mode 100644 index 00000000..e009c1c7 --- /dev/null +++ b/lib/ManaTools/Module/LogViewer.pm @@ -0,0 +1,568 @@ +# vim: set et ts=4 sw=4: +package ManaTools::Module::LogViewer; +#============================================================= -*-perl-*- + +=head1 NAME + +ManaTools::Module::LogViewer - Log viewer + +=head1 SYNOPSIS + +my $logViewer = ManaTools::Module::LogViewer->new(); +$logViewer->start(); + +=head1 DESCRIPTION + +Log viewer is a backend to journalctl, it can also load a custom +file. + + +=head1 SUPPORT + +You can find documentation for this module with the perldoc command: + +perldoc ManaTools::Module::::LogViewer + +=head1 AUTHOR + +Angelo Naselli + +=head1 COPYRIGHT and LICENSE + +Copyright (C) 2014-2015, Angelo Naselli. + +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 + +=head1 FUNCTIONS + +=cut + +use Moose; + +use diagnostics; +use open OUT => ':utf8'; + +use ManaTools::Shared::GUI; +use ManaTools::Shared::Locales; +use ManaTools::Shared::Services; +use ManaTools::Shared::JournalCtl; + + +use POSIX qw/strftime floor/; +use English; +use Date::Simple (); +use File::HomeDir qw(home); + +use yui; + +extends qw( ManaTools::Module ); + +### TODO icon +has '+icon' => ( + default => "/usr/share/mcc/themes/default/logdrake-mdk.png", +); + +has 'loc' => ( + is => 'rw', + init_arg => undef, + builder => '_localeInitialize' +); + +sub _localeInitialize { + my $self = shift; + + # TODO fix domain binding for translation + $self->loc(ManaTools::Shared::Locales->new(domain_name => 'libDrakX-standalone') ); + # TODO if we want to give the opportunity to test locally add dir_name => 'path' +} + +has 'sh_gui' => ( + is => 'rw', + init_arg => undef, + builder => '_SharedUGUIInitialize' +); + +sub _SharedUGUIInitialize { + my $self = shift; + + $self->sh_gui(ManaTools::Shared::GUI->new() ); +} + +=head1 VERSION + +Version 1.0.0 + +=cut + +our $VERSION = '1.0.0'; + + +my %prior = ('emerg' => 0, + 'alert' => 1, + 'crit' => 2, + 'err' => 3, + 'warning' => 4, + 'notice' => 5, + 'info' => 6, + 'debug' => 7); + + +#============================================================= + +=head2 BUILD + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + The BUILD method is called after a Moose object is created, + in this methods Services loads all the service information. + +=cut + +#============================================================= +sub BUILD { + my $self = shift; + + if (! $self->name) { + $self->name ($self->loc->N("Log viewer")); + } +} + + +#============================================================= + +=head2 start + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + This method extends Module::start and is invoked to + start the log viewer + +=cut + +#============================================================= +sub start { + my $self = shift; + + $self->_logViewerPanel(); +}; + + + + + +sub _logViewerPanel { + my $self = shift; + + if(!$self->_warn_about_user_mode()) { + return 0; + } + + 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 $optFactory = yui::YUI::optionalWidgetFactory; + + # Create Dialog + my $dialog = $factory->createMainDialog; + + # Start Dialog layout: + my $layout = $factory->createVBox( $dialog ); + my $align = $factory->createAlignment($layout, $yui::YAlignCenter, $yui::YAlignUnchanged); + $factory->createLabel( $align, $self->loc->N("A tool to monitor your logs"), 1, 0 ); + + #### matching + my $hbox = $factory->createHBox($layout); + my $matchingInputField = $factory->createInputField($hbox, $self->loc->N("Matching")); + $factory->createHSpacing($hbox, 1); + + #### not matching + my $notMatchingInputField = $factory->createInputField($hbox, $self->loc->N("but not matching")); + $matchingInputField->setWeight($yui::YD_HORIZ, 2); + $notMatchingInputField->setWeight($yui::YD_HORIZ, 2); + + my $frame = $factory->createFrame($layout, $self->loc->N("Options")); + + #### lastBoot + my $vbox = $factory->createVBox( $frame ); + $align = $factory->createLeft($vbox); + my $lastBoot = $factory->createCheckBox($align, $self->loc->N("Last boot"), 1); + $factory->createVSpacing($vbox, 0.5); + $lastBoot->setNotify(1); + + my $row1 = $factory->createHBox($vbox); + $factory->createVSpacing($vbox, 0.5); + my $row2 = $factory->createHBox($vbox); + $factory->createVSpacing($vbox, 0.5); + my $row3 = $factory->createHBox($vbox); + + #### since and until + my $sinceDate; + my $sinceTime; + my $sinceFrame = $factory->createCheckBoxFrame($row1, $self->loc->N("Since"), 1); + $sinceFrame->setNotify(1); + + my $untilDate; + my $untilTime; + my $untilFrame = $factory->createCheckBoxFrame($row2, $self->loc->N("Until"), 1); + $untilFrame->setNotify(1); + if ($optFactory->hasDateField()) { + my $hbox1 = $factory->createHBox($sinceFrame); + + $sinceDate = $optFactory->createDateField($hbox1, ""); + $factory->createHSpacing($hbox1, 1.0); + $sinceTime = $optFactory->createTimeField($hbox1, ""); + my $day = strftime "%F", localtime; + $sinceDate->setValue($day); + $sinceTime->setValue("00:00:00"); + + $hbox1 = $factory->createHBox($untilFrame); + $untilDate = $optFactory->createDateField($hbox1, ""); + $factory->createHSpacing($hbox1, 1.0); + $untilTime = $optFactory->createTimeField($hbox1, ""); + $untilDate->setValue($day); + $untilTime->setValue("23:59:59"); + } + else { + $sinceFrame->enable(0); + $untilFrame->enable(0); + } + + #### units + my $spacing = $factory->createHSpacing($row1, 2.0); + + my $unitsFrame = $factory->createCheckBoxFrame($row1, $self->loc->N("Select a unit"), 1); + $unitsFrame->setNotify(1); + $align = $factory->createLeft($unitsFrame); + my $units = $factory->createComboBox ( $align, "" ); + my $itemCollection = new yui::YItemCollection; + + yui::YUI::app()->busyCursor(); + my $serv = ManaTools::Shared::Services->new(); + my ($l, $active_services) = $serv->services(); + + foreach (@{$active_services}) { + my $serviceName = $_; + my $item = new yui::YItem($serviceName); + $itemCollection->push($item); + $item->DISOWN(); + } + $units->addItems($itemCollection); + yui::YUI::app()->normalCursor(); + + #### priority + # From + $factory->createHSpacing($row2, 2.0); + my $priorityFromFrame = $factory->createCheckBoxFrame($row2, $self->loc->N("From priority"), 1); + $priorityFromFrame->setNotify(1); + $priorityFromFrame->setWeight($yui::YD_HORIZ, 1); + my $priorityFrom = $factory->createComboBox ( $priorityFromFrame, "" ); + $itemCollection->clear(); + + my @pr = ('emerg', 'alert', 'crit', 'err', + 'warning', 'notice', 'info', 'debug'); + foreach (@pr) { + my $item = new yui::YItem($_); + if ( $_ eq 'emerg' ) { + $item->setSelected(1); + } + $itemCollection->push($item); + $item->DISOWN(); + } + $priorityFrom->addItems($itemCollection); + + $factory->createHSpacing( $row2, 2.0 ); + # To + my $priorityToFrame = $factory->createCheckBoxFrame($row2, $self->loc->N("To priority"), 1); + $priorityToFrame->setNotify(1); + $priorityToFrame->setWeight($yui::YD_HORIZ, 1); + my $priorityTo = $factory->createComboBox ( $priorityToFrame, "" ); + $itemCollection->clear(); + + foreach (@pr) { + my $item = new yui::YItem($_); + if ( $_ eq 'debug' ) { + $item->setSelected(1); + } + $itemCollection->push($item); + $item->DISOWN(); + } + $priorityTo->addItems($itemCollection); + + #### search + $align = $factory->createRight($row3); + my $searchButton = $factory->createPushButton($align, $self->loc->N("&Find")); + + #### create log view object + my $logView = $factory->createLogView($layout, $self->loc->N("Log content"), 10, 0); + + + ### NOTE CheckBoxFrame doesn't honoured his costructor checked value for his children + $unitsFrame->setValue(0); + $sinceFrame->setValue(0); + $untilFrame->setValue(0); + $priorityFromFrame->setValue(0); + $priorityToFrame->setValue(0); + + # buttons on the last line + $align = $factory->createRight($layout); + $hbox = $factory->createHBox($align); + my $aboutButton = $factory->createPushButton($hbox, $self->loc->N("&About") ); + $align = $factory->createRight($hbox); + $hbox = $factory->createHBox($align); + my $saveButton = $factory->createPushButton($hbox, $self->loc->N("&Save")); + my $quitButton = $factory->createPushButton($hbox, $self->loc->N("&Quit")); + + # End Dialof layout + + 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 == $quitButton) { + last; + } + elsif($widget == $aboutButton) { + my $translators = $self->loc->N("_: Translator(s) name(s) & email(s)\n"); + $translators =~ s/\/\>\;/g; + $self->sh_gui->AboutDialog({ name => $self->name, + version => $self->VERSION, + credits => $self->loc->N("Copyright (C) %s Mageia community", '2014'), + license => $self->loc->N("GPLv2"), + description => $self->loc->N("Log viewer is a systemd journal viewer"), + authors => $self->loc->N("

Developers

+
  • %s
  • +
  • %s
  • +
+

Translators

+
  • %s
", + "Angelo Naselli <anaselli\@linux.it>", + "Matteo Pasotti <matteo.pasotti\@gmail.com>", + $translators + ), + } + ); + } + elsif($widget == $saveButton) { + if ($logView->lines()) { + $self->_save($logView); + } + else { + $self->sh_gui->warningMsgBox({text => $self->loc->N("Empty log found")}); + } + } + elsif ($widget == $searchButton) { + yui::YUI::app()->busyCursor(); + $dialog->startMultipleChanges(); + $logView->clearText(); + my %log_opts; + if ($lastBoot->value()) { + $log_opts{this_boot} = 1; + } + if ($unitsFrame->value()) { + $log_opts{unit} = $units->value(); + } + if ($sinceFrame->value()) { + $log_opts{since} = $sinceDate->value() . " " . $sinceTime->value(); + } + if ($untilFrame->value()) { + $log_opts{until} = $untilDate->value() . " " . $untilTime->value(); +# TODO check date until > date since + } + if ($priorityFromFrame->value() || $priorityToFrame->value()) { + my $prio = $priorityFrom->value(); + $prio .= "..".$priorityTo->value() if ($priorityToFrame->value()); + $log_opts{priority} = $prio; +# TODO enabling right using checkBoxes + } + my $log = $self->_search(\%log_opts); +print " log lines: ". scalar (@{$log}) ."\n"; +# TODO check on log line number what to do if too big? and adding a progress bar? + $self->_parse_content({'matching' => $matchingInputField->value(), + 'noMatching' => $notMatchingInputField->value(), + 'log' => $log, + 'logView' => $logView, + } + ); + $dialog->recalcLayout(); + $dialog->doneMultipleChanges(); + yui::YUI::app()->normalCursor(); + } + elsif ($widget == $lastBoot) { + yui::YUI::ui()->blockEvents(); + if ($lastBoot->value()) { + #last boot overrrides until and since + $sinceFrame->setValue(0); + $untilFrame->setValue(0); + } + yui::YUI::ui()->unblockEvents(); + } + elsif ($widget == $sinceFrame) { + yui::YUI::ui()->blockEvents(); + if ($sinceFrame->value()) { + #disabling last boot that overrrides until and since + $lastBoot->setValue(0); + } + yui::YUI::ui()->unblockEvents(); + } + elsif ($widget == $untilFrame) { + yui::YUI::ui()->blockEvents(); + if ($untilFrame->value()) { + #disabling last boot that overrrides until and since + $lastBoot->setValue(0); + } + yui::YUI::ui()->unblockEvents(); + } + elsif ($widget == $priorityFromFrame) { + if ($priorityToFrame->value() && !$priorityFromFrame->value()) { + yui::YUI::ui()->blockEvents(); + $priorityToFrame->setValue(0) ; + yui::YUI::ui()->unblockEvents(); + } + } + elsif ($widget == $priorityToFrame) { + if ($priorityToFrame->value() && !$priorityFromFrame->value()) { + yui::YUI::ui()->blockEvents(); + $priorityFromFrame->setValue(1) ; + yui::YUI::ui()->unblockEvents(); + } + } + + } + } + $dialog->destroy(); + + #restore old application title + yui::YUI::app()->setApplicationTitle($appTitle) if $appTitle; +} + + + +sub _warn_about_user_mode { + my $self = shift; + + my $title = $self->loc->N("Running in user mode"); + my $msg = $self->loc->N("You are launching this program as a normal user.\n". + "You will not be able to read system logs which you do not have rights to,\n". + "but you may still browse all the others."); + + if(($EUID != 0) and (!$self->sh_gui->ask_OkCancel({title => $title, text => $msg}))) { + # TODO add Privileges? + return 0; + } + + return 1; +} + + +## Save as +# +# $logView: log Widget +# +## +sub _save { + my ($self, $logView) = @_; + + yui::YUI::app()->busyCursor(); + + my $outFile = yui::YUI::app()->askForSaveFileName(home(), "*", $self->loc->N("Save as..")); + if ($outFile) { + open(OF, ">".$outFile); + print OF $logView->logText(); + close OF; + } + + yui::YUI::app()->normalCursor(); +} + +## Search call back +sub _search { + my ($self, $log_opts) = @_; + + my $log = ManaTools::Shared::JournalCtl->new(%{$log_opts}); + my $all = $log->getLog(); + + return $all; +} + +## _parse_content +# +# $info : HASH cotaining +# +# matching: string to match +# notMatching: string to skip +# log: ARRAY REF to log content +# logViewer: logViewer Widget +# +## +sub _parse_content { + my ($self, $info) = @_; + + my $ey = ""; + my $en = ""; + + if( exists($info->{'matching'} ) ){ + $ey = $info->{'matching'}; + } + if( exists($info->{'noMatching'} ) ){ + $en = $info->{'noMatching'}; + } + + $ey =~ s/ OR /|/ if ($ey); + $ey =~ s/^\*$// if ($ey); + $en =~ s/^\*$/.*/ if ($en); + + my $test; + + if ($en && !$ey) { + $test = sub { $_[0] !~ /$en/ }; + } + elsif ($ey && !$en) { + $test = sub { $_[0] =~ /$ey/ }; + } + elsif ($ey && $en) { + $test = sub { $_[0] =~ /$ey/ && $_[0] !~ /$en/ }; + } + else { + $test = sub { $_[0] }; + } + + foreach (@{$info->{log}}) { + $info->{logView}->appendLines($_) if $test->($_); + } + +} + + +1 diff --git a/lib/ManaTools/Module/Proxy.pm b/lib/ManaTools/Module/Proxy.pm new file mode 100644 index 00000000..ff2af3e5 --- /dev/null +++ b/lib/ManaTools/Module/Proxy.pm @@ -0,0 +1,396 @@ +# vim: set et ts=4 sw=4: +#***************************************************************************** +# +# Copyright (c) 2013-2015 Matteo Pasotti +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +#***************************************************************************** + +package ManaTools::Module::Proxy; + +use Modern::Perl '2011'; +use autodie; +use Moose; +use POSIX qw(ceil); +use English; +use utf8; + +use yui; +use ManaTools::Shared qw(trim); +use ManaTools::Shared::GUI; +use ManaTools::Shared::Proxy; + +# TODROP but provides network::network +use lib qw(/usr/lib/libDrakX); +use network::network; +use MDK::Common::System qw(getVarsFromSh); + +extends qw( ManaTools::Module ); + + +has '+icon' => ( + default => "/usr/share/mcc/themes/default/drakproxy-mdk.png" +); + +has '+name' => ( + default => "Proxymanager", +); + +=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 'proxy' => ( + is => 'rw', + isa => 'HashRef', + builder => "init_proxy" +); + +has 'sh_gui' => ( + is => 'rw', + init_arg => undef, + builder => '_SharedUGUIInitialize' +); + +has 'loc' => ( + is => 'rw', + init_arg => undef, + builder => '_localeInitialize' +); + + +sub _localeInitialize { + my $self = shift(); + + # TODO fix domain binding for translation + $self->loc(ManaTools::Shared::Locales->new(domain_name => 'drakx-net') ); + # TODO if we want to give the opportunity to test locally add dir_name => 'path' +} + +sub _SharedUGUIInitialize { + my $self = shift(); + + $self->sh_gui( ManaTools::Shared::GUI->new() ); +} + +#============================================================= + +=head2 init_proxy + +=head3 DESCRIPTION + +=over 4 + +=item This method does initialize the proxy attribute provided by this class. + +=item $self->proxy is structured as follows: + +=over 6 + +=item B the string with the list of the excluded domains/addresses + +=item B the url of the http proxy + +=item B the url of the https proxy + +=item B the url for the ftp proxy + +=back + +=back + +=cut + +#============================================================= + +sub init_proxy { + my %p = ( + 'no_proxy' => '', + 'http_proxy' => '', + 'https_proxy' => '', + 'ftp_proxy' => '', + ); + return \%p; +} + +#============================================================= + +=head2 start + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + This method extends Module::start and is invoked to + start proxy manager + +=cut + +#============================================================= +sub start { + my $self = shift; + + if ($EUID != 0) { + $self->sh_gui->warningMsgBox({ + title => $self->name, + text => $self->loc->N("root privileges required"), + }); + return; + } + + $self->_manageProxyDialog(); +}; + +#============================================================= + +=head2 ask_for_X_restart + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + This method shows a message box warning the user + that a X server restart is required + +=cut + +#============================================================= + +sub ask_for_X_restart { + my $self = shift; + + $self->sh_gui->warningMsgBox({title=>$self->loc->N("X Restart Required"),text=>$self->loc->N("You need to log out and back in again for changes to take effect"),richtext=>1}); +} + +#============================================================= + +=head2 validate + +=head3 INPUT + + $self: this object + + $proxy: the hash containing what returns from getVarFromSh + eventually modified by the user + +=head3 DESCRIPTION + + This method returns true if the each value match + certain conditions like the leading http:// for http proxy + or https:// for the https proxy, etc. + + $proxy is passed by reference thus $proxy->{no_proxy} value + is sanitized (trimmed). + +=cut + +#============================================================= + +sub validate { + my $self = shift; + my $proxy = shift; + my $retval = 1; + $proxy->{no_proxy} =~ s/\s//g; + # using commas rather than slashes + if($proxy->{http_proxy} !~ m,^($|http://),) + { + $self->sh_gui->warningMsgBox({title=>'Error',text=>$self->loc->N("Proxy should be http://..."),richtext=>0}); + $retval = 0; + } + if($proxy->{https_proxy} !~ m,^($|https?://),) + { + $self->sh_gui->warningMsgBox({title=>'Error',text=>$self->loc->N("Proxy should be http://... or https://..."),richtext=>0}); + $retval = 0; + } + if($proxy->{ftp_proxy} !~ m,^($|ftp://|http://),) + { + $self->sh_gui->warningMsgBox({title=>'Error',text=>$self->loc->N("URL should begin with 'ftp:' or 'http:'"),richtext=>0}); + $retval = 0; + } + return $retval; +} + +sub _manageProxyDialog { + my $self = shift; + + ## TODO fix for manatools + my $appTitle = yui::YUI::app()->applicationTitle(); + my $appIcon = yui::YUI::app()->applicationIcon(); + ## set new title to get it in dialog + my $newTitle = $self->loc->N("Proxies configuration"); + yui::YUI::app()->setApplicationTitle($newTitle); + + my $factory = yui::YUI::widgetFactory; + my $optional = yui::YUI::optionalWidgetFactory; + + my $label_width = 25; + my $inputfield_width = 45; + # getVarsFromSh returns an empty hash if no vars are defined + # possible alternatives: + # . Config::Auto::parse + my $proxy_curr_settings = { getVarsFromSh('/etc/profile.d/proxy.sh') }; + my $httpsProxyEqualToHttpProxy = 0; + if((defined($proxy_curr_settings->{http_proxy}) && defined($proxy_curr_settings->{https_proxy}))&& + (($proxy_curr_settings->{http_proxy} eq $proxy_curr_settings->{https_proxy}) && + ($proxy_curr_settings->{http_proxy} ne ""))){ + $httpsProxyEqualToHttpProxy = 1; + } + + # + # @layout + # + # +------------------------------+ + # | +------------+-------------+ | + # | |LABELS | VALUES | | + # | | | | | + # | | | | | + # | | | | | + # | +------------+-------------+ | + # +------------------------------+ + + $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); + + # app description + my $hbox_content = $factory->createHBox($layout); + $factory->createLabel($hbox_content, $self->loc->N("Here you can set up your proxies configuration (eg: http://my_caching_server:8080)")); + + $hbox_content = $factory->createHBox($layout); + + my $vbox_labels_flags = $factory->createVBox($hbox_content); + my $vbox_inputfields = $factory->createVBox($hbox_content); + + # http proxy section + my $httpproxy_label = $factory->createLabel($vbox_labels_flags, $self->loc->N("HTTP proxy")); + my $http_proxy = $factory->createInputField($factory->createHBox($vbox_inputfields),"",0); + $http_proxy->setValue($proxy_curr_settings->{http_proxy}) if(defined($proxy_curr_settings->{http_proxy})); + $http_proxy->setWeight($yui::YD_HORIZ, 30); + + # flag to setup the https proxy with the same value of the http proxy + my $ckbHttpEqHttps = $factory->createCheckBox($vbox_labels_flags, $self->loc->N("Use HTTP proxy for HTTPS connections"),$httpsProxyEqualToHttpProxy); + $ckbHttpEqHttps->setNotify(1); + # add a spacing as we have + $factory->createLabel($factory->createHBox($vbox_inputfields)," "); + + # https proxy + $factory->createLabel($vbox_labels_flags, $self->loc->N("HTTPS proxy")); + my $https_proxy = $factory->createInputField($factory->createHBox($vbox_inputfields),"",0); + $https_proxy->setValue($proxy_curr_settings->{https_proxy}) if(defined($proxy_curr_settings->{https_proxy})); + $https_proxy->setWeight($yui::YD_HORIZ, 30); + + # ftp proxy + $factory->createLabel($vbox_labels_flags, $self->loc->N("FTP proxy")); + my $ftp_proxy = $factory->createInputField($factory->createHBox($vbox_inputfields),"",0); + $ftp_proxy->setValue($proxy_curr_settings->{ftp_proxy}) if(defined($proxy_curr_settings->{ftp_proxy})); + $ftp_proxy->setWeight($yui::YD_HORIZ, 30); + + # no-proxy list + $factory->createLabel($vbox_labels_flags, $self->loc->N("No proxy for (comma separated list):")); + my $no_proxy = $factory->createInputField($factory->createHBox($vbox_inputfields),"",0); + $no_proxy->setValue($proxy_curr_settings->{no_proxy}) if(defined($proxy_curr_settings->{no_proxy})); + $no_proxy->setWeight($yui::YD_HORIZ, 30); + + my $hbox_filler = $factory->createHBox($layout); + $factory->createSpacing($hbox_filler,$yui::YD_VERT,2); + + 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,$self->loc->N("&About")); + my $cancelButton = $factory->createPushButton($vbox_foot_right,$self->loc->N("&Cancel")); + my $okButton = $factory->createPushButton($vbox_foot_right,$self->loc->N("&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 == $aboutButton) { + $self->sh_gui->AboutDialog({ + name => $appTitle, + version => $VERSION, + credits => "Copyright (c) 2013-2014 by Matteo Pasotti", + license => "GPLv2", + description => $self->loc->N("Graphical manager for proxies"), + authors => "Matteo Pasotti <matteo.pasotti\@gmail.com>" + } + ); + }elsif ($widget == $okButton) { + # setup proxy attribute + my %_proxy = ( + no_proxy => $no_proxy->value(), + http_proxy => $http_proxy->value(), + https_proxy => $https_proxy->value(), + ftp_proxy => $ftp_proxy->value() + ); + if($self->validate(\%_proxy)) { + # validation succeded + $self->proxy(\%_proxy); + # save changes + network::network::proxy_configure($self->proxy); + $self->ask_for_X_restart(); + last; + } + # validation failed + next; + }elsif ($widget == $ckbHttpEqHttps){ + $https_proxy->setEnabled(!$ckbHttpEqHttps->isChecked()); + } + } + } + + $self->dialog->destroy() ; + + #restore old application title + yui::YUI::app()->setApplicationTitle($appTitle); +} + +1; diff --git a/lib/ManaTools/Module/Services.pm b/lib/ManaTools/Module/Services.pm new file mode 100644 index 00000000..dca0c0c6 --- /dev/null +++ b/lib/ManaTools/Module/Services.pm @@ -0,0 +1,588 @@ +# vim: set et ts=4 sw=4: + +package ManaTools::Module::Services; + +#============================================================= -*-perl-*- + +=head1 NAME + +ManaTools::Module::Services - This module aims to manage service + with GUI + +=head1 SYNOPSIS + + my $serviceMan = ManaTools::Module::Services->new(); + $serviceMan->start(); + +=head1 DESCRIPTION + + This module presents all the system service status and gives + the availability to administrator to stop, start and active at boot + them. + + From the original code drakx services. + +=head1 SUPPORT + + You can find documentation for this module with the perldoc command: + + perldoc ManaTools::Module::Services + +=head1 SEE ALSO + + ManaTools::Module + +=head1 AUTHOR + +Angelo Naselli + +=head1 COPYRIGHT and LICENSE + +Copyright (C) 2014-2015, Angelo Naselli. + +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 + +=cut + + +use Moose; +use English; +use Time::HiRes qw(usleep); + +use MDK::Common::String qw(formatAlaTeX); +use MDK::Common::DataStructure qw(member); + +use yui; +use ManaTools::Shared::GUI; +use ManaTools::Shared::Locales; +use ManaTools::Shared::Services; + + +use File::Basename; + +extends qw( ManaTools::Module ); + +has '+icon' => ( + default => "/usr/share/mcc/themes/default/service-mdk.png", +); + +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 'sh_gui' => ( + is => 'rw', + init_arg => undef, + builder => '_SharedUGUIInitialize' +); + +sub _SharedUGUIInitialize { + my $self = shift(); + + $self->sh_gui(ManaTools::Shared::GUI->new() ); +} + +has 'sh_services' => ( + is => 'rw', + init_arg => undef, + lazy => 1, + builder => '_SharedServicesInitialize' +); + +sub _SharedServicesInitialize { + my $self = shift(); + + $self->sh_services(ManaTools::Shared::Services->new() ); +} + + +has 'loc' => ( + is => 'rw', + init_arg => undef, + builder => '_localeInitialize' +); + +sub _localeInitialize { + my $self = shift(); + + # TODO fix domain binding for translation + $self->loc(ManaTools::Shared::Locales->new(domain_name => 'libDrakX-standalone') ); + # TODO if we want to give the opportunity to test locally add dir_name => 'path' +} + +=head1 VERSION + +Version 1.0.0 + +=cut + +our $VERSION = '1.0.0'; + +=head1 METHODS + +=cut + +#============================================================= + +=head2 BUILD + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + The BUILD method is called after a Moose object is created, + in this methods Services loads all the service information. + +=cut + +#============================================================= +sub BUILD { + my $self = shift; + + if (! $self->name) { + $self->name ($self->loc->N("adminService")); + } + + $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; + +# if ($EUID != 0) { +# $self->sh_gui->warningMsgBox({ +# title => $self->name, +# text => $self->loc->N("root privileges required"), +# }); +# return; +# } + + $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 $refresh = 1; + my ($l, $on_services) = $self->sh_services->services($refresh); + my @xinetd_services = map { $_->[0] } $self->sh_services->xinetd_services(); + + $self->_xinetd_services(); + $self->_xinetd_services(\@xinetd_services); + $self->_services(\@$l); + $self->on_services(\@$on_services); + +} + +## _waitUnitStatus wait unit status is reached for +## a while (10 secs max) +sub _waitUnitStatus { + my ($self, $service, $running) = @_; + + for (my $i=0; $i < 100; $i++) { + $self->loadServices(); + if ($running) { + last if $self->sh_services->is_service_running($service); + } + else { + last if !$self->sh_services->is_service_running($service); + } + usleep(100); + } +} + +## _serviceInfo sets service description 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(MDK::Common::String::formatAlaTeX($self->sh_services->description($service))); + yui::YUI::ui()->unblockEvents(); +} + + +sub _serviceStatusString { + my ($self, $serviceName) = @_; + + my $started; + + if (MDK::Common::DataStructure::member($serviceName, $self->all_xinetd_services)) { + $started = $self->loc->N("Start when requested"); + } + else { + $started = ($self->sh_services->is_service_running($serviceName)? $self->loc->N("running") : $self->loc->N("stopped")); + } + + return $started; +} + +## _serviceStatus sets status label accordingly to selected item +## param +## 'service' yui CB table (service table) +## 'item' selected item (service) +sub _serviceStatus { + my ($self, $tbl, $item) = @_; + + my $started = $self->_serviceStatusString($item->label()); + + # TODO add icon green/red led + my $cell = $tbl->toCBYTableItem($item)->cell(1); + if ($cell) { + $cell->setLabel($started); + $tbl->cellChanged($cell); + } +} + + +## fill service table with service info +## param +## 'tbl' yui table +sub _fillServiceTable { + my ($self, $tbl) = @_; + + $tbl->startMultipleChanges(); + $tbl->deleteAllItems(); + my $itemCollection = new yui::YItemCollection; + foreach (sort $self->all_services) { + + my $serviceName = $_; + + my $item = new yui::YCBTableItem($serviceName); + my $started = $self->_serviceStatusString($serviceName); + + # TODO add icon green/red led + my $cell = new yui::YTableCell($started); + $item->addCell($cell); + + $item->check(MDK::Common::DataStructure::member($serviceName, $self->all_on_services)); + $item->setLabel($serviceName); + $itemCollection->push($item); + $item->DISOWN(); + } + $tbl->addItems($itemCollection); + $tbl->doneMultipleChanges(); +} + +## draw service panel and manage it (main dialog) +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 $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 ); + + #Line for logo and title + my $hbox_iconbar = $factory->createHBox($vbox); + my $head_align_left = $factory->createLeft($hbox_iconbar); + $hbox_iconbar = $factory->createHBox($head_align_left); + $factory->createImage($hbox_iconbar, $self->icon); + + $factory->createHeading($hbox_iconbar, $self->loc->N("Manage system services by enabling or disabling them")); + + my $frame = $factory->createFrame ($vbox, ""); + + my $frmVbox = $factory->createVBox( $frame ); + my $hbox = $factory->createHBox( $frmVbox ); + + my $yTableHeader = new yui::YTableHeader(); + $yTableHeader->addColumn($self->loc->N("Service"), $yui::YAlignBegin); + $yTableHeader->addColumn($self->loc->N("Status"), $yui::YAlignCenter); + $yTableHeader->addColumn($self->loc->N("On boot"), $yui::YAlignBegin); + + ## service list (serviceBox) + my $serviceTbl = $mgaFactory->createCBTable($hbox, $yTableHeader, $yui::YCBTableCheckBoxOnLastColumn); + + $self->_fillServiceTable($serviceTbl); + + $serviceTbl->setImmediateMode(1); + $serviceTbl->setWeight(0, 50); + + ## info panel (infoPanel) + $frame = $factory->createFrame ($hbox, $self->loc->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, $self->loc->N("&Start")); + + ### Service Stop button ($stopButton) + my $stopButton = $factory->createPushButton($hbox, $self->loc->N("S&top")); + + # 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, $self->loc->N("&About") ); + $align = $factory->createRight($hbox); + $hbox = $factory->createHBox($align); + + ### Service Refresh button ($refreshButton) + my $refreshButton = $factory->createPushButton($hbox, $self->loc->N("&Refresh")); + my $closeButton = $factory->createPushButton($hbox, $self->loc->N("&Quit") ); + + #first item status + my $item = $serviceTbl->selectedItem(); + if ($item) { + $self->_serviceInfo($item->label(), $infoPanel); + if (MDK::Common::DataStructure::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 $translators = $self->loc->N("_: Translator(s) name(s) & email(s)\n"); + $translators =~ s/\/\>\;/g; + $self->sh_gui->AboutDialog({ name => $self->name, + version => $self->VERSION, + credits => $self->loc->N("Copyright (C) %s Mageia community", '2013-2015'), + license => $self->loc->N("GPLv2"), + description => $self->loc->N("adminService is the Mageia service and daemon management tool\n + (from the original idea of Mandriva draxservice)."), + authors => $self->loc->N("

Developers

+
  • %s
  • +
  • %s
  • +
+

Translators

+
  • %s
", + "Angelo Naselli <anaselli\@linux.it>", + "Matteo Pasotti <matteo.pasotti\@gmail.com>", + $translators + ), + } + ); + } + elsif ($widget == $serviceTbl) { + + # service selection changed + $item = $serviceTbl->selectedItem(); + if ($item) { + $self->_serviceInfo($item->label(), $infoPanel); + if (MDK::Common::DataStructure::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) { + yui::YUI::app()->busyCursor(); + eval { + $self->sh_services->set_service($item->label(), $item->checked()); + }; + my $errors = $@; + $self->loadServices(); + yui::YUI::app()->normalCursor(); + + if ($errors) { + $self->sh_gui->warningMsgBox({ + title => $self->loc->N($item->checked() ? "Enabling %s" : "Disabling %s", $item->label()), + text => "$errors", + richtext => 1, + }); + $dialog->startMultipleChanges(); + $self->_fillServiceTable($serviceTbl); + $dialog->recalcLayout(); + $dialog->doneMultipleChanges(); + } + } + } + } + elsif ($widget == $startButton) { + $item = $serviceTbl->selectedItem(); + if ($item) { + my $serviceName = $item->label(); + yui::YUI::app()->busyCursor(); + eval { + $self->sh_services->restart_or_start($serviceName); + $self->_waitUnitStatus($serviceName, 1); + }; + my $errors = $@; + yui::YUI::app()->normalCursor(); + $self->_serviceStatus($serviceTbl, $item); + + $self->sh_gui->warningMsgBox({ + title => $self->loc->N("Starting %s", $serviceName), + text => "$errors", + richtext => 1, + }) if $errors; + } + } + elsif ($widget == $stopButton) { + $item = $serviceTbl->selectedItem(); + if ($item) { + my $serviceName = $item->label(); + yui::YUI::app()->busyCursor(); + eval { + $self->sh_services->stopService($serviceName); + $self->_waitUnitStatus($serviceName, 0); + }; + my $errors = $@; + yui::YUI::app()->normalCursor(); + $self->_serviceStatus($serviceTbl, $item); + + $self->sh_gui->warningMsgBox({ + title => $self->loc->N("Stopping %s", $serviceName), + text => "$errors", + richtext => 1, + }) if $errors; + } + } + elsif ($widget == $refreshButton) { + yui::YUI::app()->busyCursor(); + $self->loadServices(); + $dialog->startMultipleChanges(); + $self->_fillServiceTable($serviceTbl); + $dialog->recalcLayout(); + $dialog->doneMultipleChanges(); + yui::YUI::app()->normalCursor(); + } + } + } + $dialog->destroy(); + + #restore old application title + yui::YUI::app()->setApplicationTitle($appTitle) if $appTitle; +} + +no Moose; +__PACKAGE__->meta->make_immutable; + +1; diff --git a/lib/ManaTools/Module/Users.pm b/lib/ManaTools/Module/Users.pm new file mode 100644 index 00000000..2ef9066a --- /dev/null +++ b/lib/ManaTools/Module/Users.pm @@ -0,0 +1,2637 @@ +# vim: set et ts=4 sw=4: + +package ManaTools::Module::Users; + +#============================================================= -*-perl-*- + +=head1 NAME + +ManaTools::Module::Users - This module aims to manage service + with GUI + +=head1 SYNOPSIS + + my $userManager = ManaTools::Module::Users->new(); + $userManager->start(); + +=head1 DESCRIPTION + + This module is a tool to manage users on the system. + + From the original code adduserdrake and userdrake. + +=head1 SUPPORT + + You can find documentation for this module with the perldoc command: + + perldoc ManaTools::Module::Users + +=head1 SEE ALSO + + ManaTools::Module + +=head1 AUTHOR + +Angelo Naselli + +=head1 COPYRIGHT and LICENSE + +Copyright (C) 2013-2015, Angelo Naselli. + +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 + +=head1 VERSION + +Version 1.0.0 + +=cut + +our $VERSION = '1.0.0'; + + +############################################### +## +## graphic related routines for managing user +## +############################################### + +use Moose; + +use POSIX qw(ceil); +use Config::Auto; +use File::ShareDir ':ALL'; + +use utf8; +use Sys::Syslog; +use Glib; +use English; +use yui; +use ManaTools::Shared; +use ManaTools::Shared::GUI; +use ManaTools::Shared::Locales; +use ManaTools::Shared::Users; +use MDK::Common::DataStructure qw(member); +use feature 'state'; + +extends qw( ManaTools::Module ); + +has '+icon' => ( + default => "/usr/share/icons/userdrake.png", +); + + +# 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, +); + + +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, +); + +has 'sh_users' => ( + is => 'rw', + init_arg => undef, + builder => '_SharedUsersInitialize' +); + +sub _SharedUsersInitialize { + my $self = shift(); + + $self->sh_users(ManaTools::Shared::Users->new() ); +} + +has 'sh_gui' => ( + is => 'rw', + init_arg => undef, + builder => '_SharedUGUIInitialize' +); + +sub _SharedUGUIInitialize { + my $self = shift(); + + $self->sh_gui(ManaTools::Shared::GUI->new() ); +} + +has 'loc' => ( + is => 'rw', + init_arg => undef, + builder => '_localeInitialize' +); + + +sub _localeInitialize { + my $self = shift(); + + # TODO fix domain binding for translation + $self->loc(ManaTools::Shared::Locales->new(domain_name => 'userdrake') ); + # TODO if we want to give the opportunity to test locally add dir_name => 'path' +} + + +#============================================================= + +=head1 METHODS + +=cut + +=head2 new - additional parameters + +=head3 config_file + + optional parameter to set the configuration file name + +=cut + +has 'config_file' => ( + is => 'rw', + isa => 'Str', + default => '/etc/sysconfig/manauser', +); + + + +#============================================================= + +=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->_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; +# usefull local variable to avoid duplicating +# translation point for group edit labels +my %groupEditLabel; + + +#============================================================= + +=head2 BUILD + +=head3 INPUT + + $self: this object + +=head3 DESCRIPTION + + The BUILD method is called after a Moose object is created, + Into this method additional data are initialized. + +=cut + +#============================================================= +sub BUILD { + my $self = shift; + + if (! $self->name) { + $self->name ($self->loc->N("manauser")); + } + + %userEditLabel = ( + user_data => $self->loc->N("User Data"), + account_info => $self->loc->N("Account Info"), + password_info => $self->loc->N("Password Info"), + groups => $self->loc->N("Groups"), + ); + %groupEditLabel = ( + group_data => $self->loc->N("Group Data"), + group_users => $self->loc->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($self->loc->N("Choose group")); + + my $factory = yui::YUI::widgetFactory; + + my $dlg = $factory->createPopupDialog(); + my $layout = $factory->createVBox($dlg); + + + my $frame = _labeledFrameBox($layout, $self->loc->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, $self->loc->N("Add to the existing group"), 1); + $rb1->setNotify(1); + $rbg->addRadioButton( $rb1 ); + $align = $factory->createLeft($frame); + my $rb2 = $factory->createRadioButton( $align, $self->loc->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, $self->loc->N("Cancel")); + my $okButton = $factory->createPushButton($hbox, $self->loc->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 _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($self->loc->N("Warning")); + + my $factory = yui::YUI::widgetFactory; + my $dlg = $factory->createPopupDialog(); + my $layout = $factory->createVBox($dlg); + + my $align = $factory->createLeft($layout); + + $factory->createLabel($align, $self->loc->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, $self->loc->N("Cancel")); + my $deleteButton = $factory->createPushButton($hbox, $self->loc->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 $username = $self->sh_users->isPrimaryGroup($groupname); + if (defined($username)) { + $self->sh_gui->msgBox({ + text => $self->loc->N("%s is a primary group for user %s\n Remove the user first", + $groupname, $username + ) + }); + } + else { + if ($self->sh_users->deleteGroup($groupname)) { + Sys::Syslog::syslog('info|local1', $self->loc->N("Removing group: %s", $groupname)); + } + $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 $homedir = $self->sh_users->getUserHome($username); + return if !defined($homedir); + + + ## push application title + my $appTitle = yui::YUI::app()->applicationTitle(); + ## set new title to get it in dialog + yui::YUI::app()->setApplicationTitle($self->loc->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, $self->loc->N("Deleting user %s\nAlso perform the following actions\n", + $username)); + $align = $factory->createLeft($layout); + my $checkhome = $factory->createCheckBox($align, $self->loc->N("Delete Home Directory: %s", $homedir), 0); + $align = $factory->createLeft($layout); + my $checkspool = $factory->createCheckBox($align, $self->loc->N("Delete Mailbox: /var/spool/mail/%s", + $username), 0); + $align = $factory->createRight($layout); + my $hbox = $factory->createHBox($align); + my $cancelButton = $factory->createPushButton($hbox, $self->loc->N("Cancel")); + my $deleteButton = $factory->createPushButton($hbox, $self->loc->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) { + Sys::Syslog::syslog('info|local1', $self->loc->N("Removing user: %s", $username)); + my $option = undef; + $option->{clean_home} = $checkhome->isChecked() if $checkhome->isChecked(); + $option->{clean_spool} = $checkspool->isChecked() if $checkspool->isChecked(); + + my $err = $self->sh_users->deleteUser($username, $option); + $self->sh_gui->msgBox({text => $err}) if (defined($err)); + + #remove added icon + $self->sh_users->removeKdmIcon($username); + $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($self->loc->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, $self->loc->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, $self->loc->N("Specify group ID manually"), 0); + $factory->createHSpacing($hbox, 2); + my $GID = $factory->createIntField($hbox, $self->loc->N("GID"), 1, 65000, $self->sh_users->min_GID); + $GID->setEnabled($gidManually->value()); + $gidManually->setNotify(1); + + $hbox = $factory->createHBox($layout); + $align = $factory->createRight($hbox); + my $cancelButton = $factory->createPushButton($align, $self->loc->N("Cancel")); + my $okButton = $factory->createPushButton($hbox, $self->loc->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) = $self->sh_users->valid_groupname($groupname); + my $nm = $continue && $self->sh_users->groupNameExists($groupname); + if ($nm) { + $groupName->setValue(""); + $errorString = $self->loc->N("Group already exists, please choose another Group Name"); + $continue = 0; + } + + my $gid = -1; + if ($continue && $gidManually->value()) { + if (($gid = $GID->value()) < $self->sh_users->min_GID) { + $errorString = ""; + my $gidchoice = $self->sh_gui->ask_YesOrNo({ title => $self->loc->N(" Group Gid is < %n", $self->sh_users->min_GID), + text => $self->loc->N("Creating a group with a GID less than %d is not recommended.\n Are you sure you want to do this?\n\n", + $self->sh_users->min_GID + ) + }); + $continue = $gidchoice; + } else { + if ($self->sh_users->groupIDExists($gid)) { + $errorString = ""; + my $gidchoice = $self->sh_gui->ask_YesOrNo({title => $self->loc->N(" Group ID is already used "), + text => $self->loc->N("Creating a group with a non unique GID?\n\n")}); + $continue = $gidchoice; + } + } + } + + + if (!$continue) { + #--- raise error + $self->sh_gui->msgBox({text => $errorString}) if ($errorString); + } + else { + Sys::Syslog::syslog('info|local1', $self->loc->N("Adding group: %s ", $groupname)); + my $groupParams = { + groupname => $groupname, + is_system => $is_system, + }; + $groupParams->{gid} = $gid if $gid != -1; + $self->sh_users->addGroup($groupParams); + $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 reference containing reference to graphical object + such as: + full_name, login_name, password, password1, + login_shell + full_name, login_name, password, password1, + weakness (icon), 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->sh_users->getUserShells()}; + + my $factory = yui::YUI::widgetFactory; + + ## user 'full name' + my $align = $factory->createRight($layout); + my $hbox = $factory->createHBox($align); + my $label = $factory->createLabel($hbox, $self->loc->N("Full Name:") ); + $factory->createHSpacing($hbox, 2.0); + 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, $self->loc->N("Login:") ); + $factory->createHSpacing($hbox, 2.0); + 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, $self->loc->N("Password:") ); + my $weakness = undef; + if (yui::YUI::app()->hasImageSupport()) { + $factory->createHSpacing($hbox, 2.0); + my $file = File::ShareDir::dist_file(ManaTools::Shared::distName(), 'images/Blank16x16.png'); + $weakness = $factory->createImage($hbox, $file); + } + else { + $factory->createHSpacing($hbox, 1.0); + $weakness = $factory->createLabel($hbox, " "); + $factory->createHSpacing($hbox, 1.0); + } + my $password = $factory->createInputField($hbox, "", 1); + $weakness->setWeight($yui::YD_HORIZ, 1); + $label->setWeight($yui::YD_HORIZ, 1); + $password->setWeight($yui::YD_HORIZ, 4); + # notify input to check weakness + $password->setNotify(1); + + ## user 'confirm Password' + $align = $factory->createRight($layout); + $hbox = $factory->createHBox($align); + $label = $factory->createLabel($hbox, $self->loc->N("Confirm Password:") ); + $factory->createHSpacing($hbox, 2.0); + 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, $self->loc->N("Login Shell:") ); + $factory->createHSpacing($hbox, 2.0); + 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, + weakness => $weakness, + login_shell => $loginShell, + ); + + return ( \%userData ); +} + +# get/set icon button name +# if $icon_name is present it sets as "&Icon icon_name", so the shortcut is always the same +# if $icon_name is not present it returns the previous set $label +sub _iconButtonLabel { + my ($self, $icon_button, $icon_name) = @_; + + state $label = ""; + + return if !$icon_button; + return if ref $icon_button ne "yui::YPushButton"; + + if ($icon_name) { + #set + $icon_button->setLabel($self->loc->N("&Icon (%s)", $icon_name)); + $label = $icon_name; + } + + return $label; +} + + +#============================================================= + +=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; + + if ($EUID != 0) { + $self->sh_gui->warningMsgBox({ + title => $self->name, + text => $self->loc->N("root privileges required"), + }); + return; + } + + 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($self->loc->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, $self->loc->N("Create Home Directory"), 1); + ## Home directory + $align = $factory->createLeft($layout); + $hbox = $factory->createHBox($align); + my $label = $factory->createLabel($hbox, $self->loc->N("Home Directory:") ); + $factory->createHSpacing($hbox, 2.0); + 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, $self->loc->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, $self->loc->N("Specify user ID manually"), 0); + $factory->createHSpacing($hbox, 2.0); + my $UID = $factory->createIntField($hbox, $self->loc->N("UID"), 1, 65000, $self->sh_users->min_UID); + $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, $self->loc->N("Click on icon to change it") ); + my $iconFace = $self->sh_users->GetFaceIcon(); + my $icon = $factory->createPushButton($hbox, ""); + $icon->setIcon($self->sh_users->face2png($iconFace)); + $self->_iconButtonLabel($icon, $iconFace); + + $hbox = $factory->createHBox($layout); + $align = $factory->createRight($hbox); + my $cancelButton = $factory->createPushButton($align, $self->loc->N("&Cancel")); + my $okButton = $factory->createPushButton($hbox, $self->loc->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->_iconButtonLabel($icon); + my $nextIcon = $self->sh_users->GetFaceIcon($iconLabel, 1); + $self->_iconButtonLabel($icon, $nextIcon); + $icon->setIcon($self->sh_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 == $userData->{password}) { + my $pass = $userData->{ password }->value(); + $self->_checkWeaknessPassword($pass, $userData->{ weakness }); + } + elsif ($widget == $okButton) { + ## check data + my $username = $userData->{ login_name }->value(); + my ($continue, $errorString) = $self->sh_users->valid_username($username); + my $nm = $continue && $self->sh_users->userNameExists($username); + if ($nm) { + $userData->{ login_name }->setValue(""); + $homeDir->setValue(""); + $errorString = $self->loc->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 = $self->loc->N("Password Mismatch"); + $continue = 0; + } + if ($self->sh_users->weakPasswordForSecurityLevel($passwd)) { + $errorString = $self->loc->N("This password is too simple. \n Good passwords should be > 6 characters"); + $continue = 0; + } + my $homedir; + if ($continue && $createHome->value()) { + $homedir = $homeDir->value(); + if ( -d $homedir) { + $errorString = $self->loc->N("Home directory <%s> already exists.\nPlease uncheck the home creation option, or change the directory path name", $homedir); + $continue = 0; + } + else { + $dontcreatehomedir = 0; + } + } else { + $dontcreatehomedir = 1; + } + my $uid = -1; + if ($continue && $uidManually->value()) { + if (($uid = $UID->value()) < $self->sh_users->min_UID) { + $errorString = ""; + my $uidchoice = $self->sh_gui->ask_YesOrNo({title => $self->loc->N("User Uid is < %d", $self->sh_users->min_UID), + text => $self->loc->N("Creating a user with a UID less than %d is not recommended.\nAre you sure you want to do this?\n\n", $self->sh_users->min_UID)}); + $continue = $uidchoice; + } + } + my $gid = undef; + if ($createGroup->value()) { + if ($continue) { + #Check if group exist + if ($self->sh_users->groupNameExists($username)) { + my $groupchoice = $self->ChooseGroup(); + if ($groupchoice == 0 ) { + #You choose to put it in the existing group + $gid = $self->sh_users->groupID($username); + } elsif ($groupchoice == 1) { + # Put it in 'users' group + Sys::Syslog::syslog('info|local1', $self->loc->N("Putting %s to 'users' group", + $username)); + $gid = $self->sh_users->Add2UsersGroup($username); + } + else { + $errorString = ""; + $continue = 0; + } + } else { + #it's a new group: Add it + $gid = $self->sh_users->addGroup({ + groupname => $username, + is_system => $is_system, + }); + Sys::Syslog::syslog('info|local1', $self->loc->N("Creating new group: %s", $username)); + } + } + } else { + $continue and $gid = $self->sh_users->Add2UsersGroup($username); + } + + if (!$continue) { + #---rasie error + $self->sh_gui->msgBox({text => $errorString}) if ($errorString); + } + else { + ## OK let's create the user + print $self->loc->N("Adding user: ") . $username . " \n"; + Sys::Syslog::syslog('info|local1', $self->loc->N("Adding user: %s", $username)); + my $loginshell = $userData->{ login_shell }->value(); + my $fullname = $userData->{ full_name }->value(); + utf8::decode($fullname); + + my $userParams = { + username => $username, + is_system => $is_system, + donotcreatehome => $dontcreatehomedir, + shell => $loginshell, + fullname => $fullname, + gid => $gid, + password => $passwd, + }; + $userParams->{uid} = $uid if $uid != -1; + $userParams->{homedir} = $homedir if !$dontcreatehomedir; + $self->sh_users->addUser($userParams); + + defined $icon->label() and + $self->sh_users->addKdmIcon($username, $icon->label()); +### TODO Migration wizard +# +# Refresh($sysfilter, $stringsearch); +# transfugdrake::get_windows_disk() +# and $in->ask_yesorno($self->loc->N("Migration wizard"), +# $self->loc->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($self->loc->N("User Name"), $yui::YAlignBegin); + $yTableHeader->addColumn($self->loc->N("User ID"), $yui::YAlignBegin); + $yTableHeader->addColumn($self->loc->N("Primary Group"), $yui::YAlignBegin); + $yTableHeader->addColumn($self->loc->N("Full Name"), $yui::YAlignBegin); + $yTableHeader->addColumn($self->loc->N("Login Shell"), $yui::YAlignBegin); + $yTableHeader->addColumn($self->loc->N("Home Directory"), $yui::YAlignBegin); + $yTableHeader->addColumn($self->loc->N("Status"), $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($self->loc->N("Group Name"), $yui::YAlignBegin); + $yTableHeader->addColumn($self->loc->N("Group ID"), $yui::YAlignBegin); + $yTableHeader->addColumn($self->loc->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 _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 $usersInfo = $self->sh_users->getUsersInfo({ + username_filter => $strfilt, + filter_system => $filterusers, + }); + + + $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 $itemColl = new yui::YItemCollection; + foreach my $username (keys %{$usersInfo}) { + my $info = $usersInfo->{$username}; + my $item = new yui::YTableItem ( + "$username", + "$info->{uid}", + "$info->{group}", + "$info->{fullname}", + "$info->{shell}", + "$info->{home}", + "$info->{status}" + ); + + # 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(); + + $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 $groupInfo = $self->sh_users->getGroupsInfo({ + groupname_filter => $strfilt, + filter_system => $filtergroups, + }); + + my $itemColl = new yui::YItemCollection; + foreach my $groupname (keys %{$groupInfo}) { + my $info = $groupInfo->{$groupname}; + my $listUbyG = join(',', @{$info->{members}}); + my $item = new yui::YTableItem ("$groupname", + "$info->{gid}", + "$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: HASH reference containing: + 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 $self->loc->N("Users") ) { + return undef; + } + + my $item = $self->get_widget('table')->selectedItem(); + if (! $item) { + return undef; + } + + my %userData; + $userData{old_username} = $item->label(); + $userData{username} = $item->label(); + + my $userInfo = $self->sh_users->getUserInfo($userData{username}); + + $userData{full_name} = $userInfo->{fullname}; + $userData{shell} = $userInfo->{shell}; + $userData{homedir} = $userInfo->{home}; + $userData{UID} = $userInfo->{uid}; + + # 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 = $userInfo->{expire}; + 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; + + $userData{lockuser} = $userInfo->{locked}; + $userData{icon_face} = $self->sh_users->GetFaceIcon($userData{username}); + + $userData{pwd_check_exp} = 0; + $userData{pwd_exp_min} = $userInfo->{exp_min}; + $userData{pwd_exp_max} = $userInfo->{exp_max}; + $userData{pwd_exp_warn} = $userInfo->{exp_warn}; + $userData{pwd_exp_inact} = $userInfo->{exp_inact}; + 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} = $userInfo->{members}; + $userData{primary_group} = $userInfo->{gid}; + + 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 $self->loc->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(); + + $groupData{members} = $self->sh_users->groupMembers($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->_iconButtonLabel($self->get_edit_tab_widget('icon_face')); + } + 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 $groupname = $self->get_edit_tab_widget('primary_group')->selectedItem()->label(); + my $primgroup = $self->sh_users->groupID($groupname); + $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 reference containing user data info, tabs are + removed and added again on selection, so + data must be saved outside of widgets. + +=head3 OUTPUT + + $userDataWidget: hash containing new YUI widget objects + such as: + returned 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, $self->loc->N("Home:") ); + $factory->createHSpacing($hbox, 2.0); + $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}); + yui::YUI::ui()->blockEvents(); + $userDataWidget->{password}->setValue($userData->{password}) if $userData->{password}; + yui::YUI::ui()->unblockEvents(); + $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, $self->loc->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, $self->loc->N("Enable account expiration"), 1); + my $align = $factory->createRight($userAccountWidget{acc_check_exp}); + my $hbox = $factory->createHBox($align); + my $label = $factory->createLabel($hbox, $self->loc->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, $self->loc->N("Lock User Account"), $userData->{lockuser}); + + $align = $factory->createLeft($layout); + $hbox = $factory->createHBox($align); + $label = $factory->createLabel($hbox, $self->loc->N("Click on the icon to change it")); + $userAccountWidget{icon_face} = $factory->createPushButton($hbox, ""); + $userAccountWidget{icon_face}->setIcon($self->sh_users->face2png($userData->{icon_face})); + $self->_iconButtonLabel($userAccountWidget{icon_face}, $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 $userInfo = $self->sh_users->getUserInfo($userData->{username}); + my $lastchg = $userInfo->{last_change}; + + my $align = $factory->createLeft($layout); + my $hbox = $factory->createHBox($align); + my $label = $factory->createLabel($hbox, $self->loc->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, $self->loc->N("Enable Password Expiration"), 1); + $layout = $factory->createVBox($userPasswordWidget{pwd_check_exp}); + $align = $factory->createLeft($layout); + $hbox = $factory->createHBox($align); + $label = $factory->createLabel($hbox, $self->loc->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, $self->loc->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, $self->loc->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, $self->loc->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, $self->loc->N("Select the users to join this group:")); + + my $yTableHeader = new yui::YTableHeader(); + $yTableHeader->addColumn("", $yui::YAlignBegin); + $yTableHeader->addColumn($self->loc->N("User"), $yui::YAlignBegin); + + $groupUsersWidget{members} = $mgaFactory->createCBTable($layout, $yTableHeader, $yui::YCBTableCheckBoxOnFirstColumn); + + my $users = $self->sh_users->getUsers(); + 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(MDK::Common::DataStructure::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 $userInfo = $self->sh_users->getUserInfo($userData->{username}); + my $lastchg = $userInfo->{last_change}; + + my $layout = _labeledFrameBox($replace_pnt, $self->loc->N("Select groups that the user will be member of:")); + + my $yTableHeader = new yui::YTableHeader(); + $yTableHeader->addColumn("", $yui::YAlignBegin); + $yTableHeader->addColumn($self->loc->N("Group"), $yui::YAlignBegin); + + $userGroupsWidget{members} = $mgaFactory->createCBTable($layout, $yTableHeader, $yui::YCBTableCheckBoxOnFirstColumn); + + my $grps = $self->sh_users->getGoups(); + 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(MDK::Common::DataStructure::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) { + $primgroup = $self->sh_users->groupName($userData->{primary_group}); + } + + my $align = $factory->createLeft($layout); + my $hbox = $factory->createHBox($align); + my $label = $factory->createLabel($hbox, $self->loc->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) = $self->sh_users->valid_groupname($groupData{groupname}); + if (!$continue) { + $self->sh_gui->msgBox({text => $errorString}) if ($errorString); + return $continue; + } + + my $groupInfo = { + groupname => $groupData{groupname}, + members => $groupData{members}, + }; + + if ($groupData{start_groupname} ne $groupData{groupname}) { + $groupInfo->{old_groupname} = $groupData{start_groupname}; + } + + my $retval = $self->sh_users->modifyGroup($groupInfo); + + if (!$retval->{status}) { + $self->sh_gui->msgBox({text => $retval->{error}} ); + } + + $self->_refresh(); + + return 1; +} + +sub _userEdit_Ok { + my ($self, $userData) = @_; + + # update last changes if any + $self->_storeDataFromUserEditPreviousTab($userData); + + my ($continue, $errorString) = $self->sh_users->valid_username($userData->{username}); + if (!$continue) { + $self->sh_gui->msgBox({text => $errorString}) if ($errorString); + return $continue; + } + + if ( $userData->{password} ne $userData->{password1}) { + $self->sh_gui->msgBox({text => $self->loc->N("Password Mismatch")}); + return 0; + } + + if ($userData->{password} ne '') { + if ($self->sh_users->weakPasswordForSecurityLevel($userData->{password})) { + $self->sh_gui->msgBox({text => $self->loc->N("This password is too simple. \n Good passwords should be > 6 characters")}); + return 0; + } + } + + if ($userData->{primary_group} == -1) { + $self->sh_gui->msgBox({ text => $self->loc->N("Please select at least one group for the user")}); + return 0; + } + + my $userInfo = { + username => $userData->{username}, + fullname => $userData->{full_name}, + homedir => $userData->{homedir}, + shell => $userData->{shell}, + members => $userData->{members}, + gid => $userData->{primary_group}, + lockuser => $userData->{lockuser}, + }; + + $userInfo->{old_username} = $userData->{old_username} if $userData->{username} ne $userData->{old_username}; + $userInfo->{password} = $userData->{password} if $userData->{password} ne ''; + + + 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)) { + $self->sh_gui->msgBox({text => $self->loc->N("Please specify Year, Month and Day \n for Account Expiration ")}); + return 0; + } + $userInfo->{acc_expires} = { + exp_y => $yr, + exp_m => $mo, + exp_d => $dy, + }; + } + + 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) { + $self->sh_gui->msgBox({text => $self->loc->N("Please fill up all fields in password aging\n")}); + return 0; + } + $userInfo->{password_expires} = { + exp_min => $allowed, + exp_max => $required, + exp_warn => $warning, + exp_inact => $inactive, + }; + } + + $self->sh_users->modifyUser($userInfo); + + + defined $userData->{icon_face} and $self->sh_users->addKdmIcon($userData->{username}, $userData->{icon_face}); + $self->_refresh(); + + return 1; +} + + +# check the password and set the widget accordingly +sub _checkWeaknessPassword { + my ($self, $password, $weakness_widget) = @_; + + my $strongp = $self->sh_users->strongPassword($password); + if (yui::YUI::app()->hasImageSupport()) { + my $file = File::ShareDir::dist_file(ManaTools::Shared::distName(), 'images/Warning_Shield_Grey16x16.png'); + if ($strongp) { + $file = File::ShareDir::dist_file(ManaTools::Shared::distName(), 'images/Checked_Shield_Green16x16.png'); + } + $weakness_widget->setImage($file); + } + else { + # For ncurses set a label + $weakness_widget->setValue(($strongp ? $self->loc->N("Strong") : $self->loc->N("Weak"))); + } +} + +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($self->loc->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, $self->loc->N("&Cancel")); + my $okButton = $factory->createPushButton($hbox, $self->loc->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()) { + $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()) { + $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()) { + $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()) { + $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 == $self->get_edit_tab_widget('password')) { + my $pass = $self->get_edit_tab_widget('password')->value(); + $self->_checkWeaknessPassword($pass, $self->get_edit_tab_widget('weakness')); + } + 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->_iconButtonLabel($self->get_edit_tab_widget('icon_face')); + my $nextIcon = $self->sh_users->GetFaceIcon($iconLabel, 1); + $self->_iconButtonLabel($self->get_edit_tab_widget('icon_face'), $nextIcon); + $self->get_edit_tab_widget('icon_face')->setIcon($self->sh_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 $primgroup = $self->sh_users->groupName($userData->{primary_group}); + $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 { + $self->sh_gui->warningMsgBox({text => $self->loc->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($self->loc->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, $self->loc->N("Cancel")); + my $okButton = $factory->createPushButton($hbox, $self->loc->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 { + $self->sh_gui->warningMsgBox({text => $self->loc->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 $self->loc->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 $self->loc->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 $self->loc->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($self->loc->N("Add User")), + add_group => new yui::YMenuItem($self->loc->N("Add Group")), + edit => new yui::YMenuItem($self->loc->N("&Edit")), + del => new yui::YMenuItem($self->loc->N("&Delete")), + inst => new yui::YMenuItem($self->loc->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 _showAboutDialog { + my $self = shift; + + my $translators = $self->loc->N("_: Translator(s) name(s) & email(s)\n"); + $translators =~ s/\/\>\;/g; + $self->sh_gui->AboutDialog({ + name => $self->loc->N("manauser"), + version => $self->VERSION, + credits => $self->loc->N("Copyright (C) %s Mageia community", '2013-2015'), + license => $self->loc->N("GPLv2"), + description => $self->loc->N("manauser is a Mageia user management tool \n(from the original idea of Mandriva userdrake)."), + authors => $self->loc->N("

Developers

+
  • %s
  • +
  • %s
  • +
+

Translators

+
  • %s
", + "Angelo Naselli <anaselli\@linux.it>", + "Matteo Pasotti <matteo.pasotti\@gmail.com>", + $translators + ), + }); +} +sub _manageUsersDialog { + my $self = shift; + + if ($EUID != 0) { + $self->sh_gui->warningMsgBox({ + title => $self->name, + text => $self->loc->N("root privileges required"), + }); + return; + } + + ## TODO fix for manatools + 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,$self->loc->N("File")), + refresh => new yui::YMenuItem($self->loc->N("Refresh")), + quit => new yui::YMenuItem($self->loc->N("&Quit")), + ); + + $fileMenu{ widget }->addItem($fileMenu{ refresh }); + $fileMenu{ widget }->addItem($fileMenu{ quit }); + $fileMenu{ widget }->rebuildMenuTree(); + + my $actionMenu = $factory->createMenuButton($headbar, $self->loc->N("Actions")); + $actionMenu->DISOWN(); + + my %helpMenu = ( + widget => $factory->createMenuButton($headRight, $self->loc->N("&Help")), + help => new yui::YMenuItem($self->loc->N("Help")), + report_bug => new yui::YMenuItem($self->loc->N("Report Bug")), + about => new yui::YMenuItem($self->loc->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', $self->loc->N("Add User")), + add_group => $factory->createIconButton($hbox, $pixdir . 'group_add.png', $self->loc->N("Add Group")), + edit => $factory->createIconButton($hbox, $pixdir . 'user_conf.png', $self->loc->N("Edit")), + del => $factory->createIconButton($hbox, $pixdir . 'user_del.png', $self->loc->N("Delete")), + refresh => $factory->createIconButton($hbox, $pixdir . 'refresh.png', $self->loc->N("Refresh")), + action_menu => $actionMenu, + ); + + + $hbox = $factory->createHBox($layout); + $head_align_left = $factory->createLeft($hbox); + + my $sysfilter = 1; + if (-e $self->config_file) { + my $prefs = Config::Auto::parse($self->config_file); + $sysfilter = ($prefs->{FILTER} eq 'true' or $prefs->{FILTER} eq 'true' or $prefs->{FILTER} eq '1'); + } + $self->set_widget(filter_system => $factory->createCheckBox($head_align_left, $self->loc->N("Filter system users"), + $sysfilter)); + $factory->createHSpacing($hbox, 3); + $head_align_right = $factory->createRight($hbox); + $headRight = $factory->createHBox($head_align_right); + $factory->createLabel($headRight, $self->loc->N("Search:")); + $self->set_widget(filter => $factory->createInputField($headRight, "", 0)); + $self->set_widget(apply_filter => $factory->createPushButton($headRight, $self->loc->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)); + } + + $hbox = $factory->createHBox($layout); + my $align = $factory->createLeft($hbox); + my $aboutButton = $factory->createPushButton($align, $self->loc->N("&About") ); + $align = $factory->createRight($hbox); + my $quitButton = $factory->createPushButton($align, $self->loc->N("&Quit") ); + + if ($optional->hasDumbTab()) { + $tabs{users} = new yui::YItem($self->loc->N("Users")); + $tabs{users}->setSelected(); + $self->get_widget('tabs')->addItem( $tabs{users} ); + $tabs{users}->DISOWN(); + $tabs{groups} = new yui::YItem($self->loc->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()) { + $self->_showAboutDialog(); + } + 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 == $quitButton) { + last; + } + elsif ($widget == $aboutButton) { + $self->_showAboutDialog(); + } + elsif ($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); +} + + +sub _ValidInt { + foreach my $i (@_) { $i =~ /\d+/ or return 0 } + return 1; +} + + +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; -- cgit v1.2.1