From c3a2201fae42ad9280efb22a7dcf1298fdcfd8dd Mon Sep 17 00:00:00 2001 From: Brian Read Date: Mon, 5 May 2025 20:55:02 +0100 Subject: [PATCH] Add in SM2 panel - wip and re-work IMAP-UTF7 conversion --- .gitignore | 2 +- .../esmith/FormMagick/Panel/mailsort.pm | 29 +- .../SrvMngr/Controller/Mailsorting-Custom.pm | 420 ++++++++++++++++++ .../lib/SrvMngr/Controller/Mailsorting.pm | 358 +++++++++++++++ .../Modules/Mailsorting/mailsorting_en.lex | 41 ++ .../themes/default/public/css/mailsorting.css | 39 ++ .../themes/default/public/js/mailsorting.js | 5 + .../default/templates/mailsorting.html.ep | 64 +++ .../templates/partials/_ms_REMOVE.html.ep | 38 ++ .../templates/partials/_ms_RULES.html.ep | 122 +++++ .../templates/partials/_ms_TABLE.html.ep | 88 ++++ smeserver-mailsorting.spec | 19 +- 12 files changed, 1209 insertions(+), 16 deletions(-) create mode 100644 root/usr/share/smanager/lib/SrvMngr/Controller/Mailsorting-Custom.pm create mode 100644 root/usr/share/smanager/lib/SrvMngr/Controller/Mailsorting.pm create mode 100644 root/usr/share/smanager/lib/SrvMngr/I18N/Modules/Mailsorting/mailsorting_en.lex create mode 100644 root/usr/share/smanager/themes/default/public/css/mailsorting.css create mode 100644 root/usr/share/smanager/themes/default/public/js/mailsorting.js create mode 100644 root/usr/share/smanager/themes/default/templates/mailsorting.html.ep create mode 100644 root/usr/share/smanager/themes/default/templates/partials/_ms_REMOVE.html.ep create mode 100644 root/usr/share/smanager/themes/default/templates/partials/_ms_RULES.html.ep create mode 100644 root/usr/share/smanager/themes/default/templates/partials/_ms_TABLE.html.ep diff --git a/.gitignore b/.gitignore index cbb3a13..e594810 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ *.rpm *.log *spec-20* -*.tar.gz +*.tar.xz diff --git a/root/usr/share/perl5/vendor_perl/esmith/FormMagick/Panel/mailsort.pm b/root/usr/share/perl5/vendor_perl/esmith/FormMagick/Panel/mailsort.pm index 7a983a3..efe1ca4 100644 --- a/root/usr/share/perl5/vendor_perl/esmith/FormMagick/Panel/mailsort.pm +++ b/root/usr/share/perl5/vendor_perl/esmith/FormMagick/Panel/mailsort.pm @@ -12,8 +12,9 @@ use esmith::util; use esmith::FormMagick; use esmith::AccountsDB; use esmith::ConfigDB; -use Unicode::IMAPUtf7; -use Unicode::String qw(utf8 latin1); +#use Unicode::IMAPUtf7; +#use Unicode::String qw(utf8 latin1); +use Encode qw(decode); use Exporter; use Carp qw(verbose); @@ -342,15 +343,23 @@ sub save_rule return $self->success("SUCCESS"); } -sub GetDisplayName ($) -{ - my $s = shift; - my $t = Unicode::IMAPUtf7->new(); - $s =~ s/(.*)//; # untaint it - my $u = utf8($t->decode($1)); - return $u->utf8;#$u->latin1; +#sub GetDisplayName ($) +#{ + #my $s = shift; + #my $t = Unicode::IMAPUtf7->new(); + #$s =~ s/(.*)//; # untaint it + #my $u = utf8($t->decode($1)); + #return $u->utf8;#$u->latin1; +#} + +sub GetDisplayName { + my ($s) = @_; + $s =~ s/(.*)//; # untaint the input + my $decoded = decode('IMAP-UTF-7', $1); + return $decoded; } + sub listfolders { use File::Find::Rule; @@ -436,4 +445,4 @@ sub nonblankWithSort } -1; +1; \ No newline at end of file diff --git a/root/usr/share/smanager/lib/SrvMngr/Controller/Mailsorting-Custom.pm b/root/usr/share/smanager/lib/SrvMngr/Controller/Mailsorting-Custom.pm new file mode 100644 index 0000000..4a9ab02 --- /dev/null +++ b/root/usr/share/smanager/lib/SrvMngr/Controller/Mailsorting-Custom.pm @@ -0,0 +1,420 @@ +# +# Generated by SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-05-04 12:59:05 +# +# +# Routines to be edited by the developer to provide content and validation for parameters +# and provison of the control data for table(s) +# +use esmith::util; +use esmith::util::network; +use esmith::ConfigDB; +use esmith::HostsDB; +use esmith::AccountsDB; +use esmith::NetworksDB; +use esmith::DomainsDB; + +use Encode::IMAPUTF7; +use Encode qw(decode); + +use constant FALSE => 0; +use constant TRUE => 1; + +our $cdb = esmith::ConfigDB->open(); +our $adb = esmith::AccountsDB->open(); +our $pdb = esmith::ConfigDB->open('processmail') or die "Could not open processmail DB\n"; + +our $PanelUser = $ENV{'REMOTE_USER'} ||''; +$PanelUser = $1 if ($PanelUser =~ /^([a-z][\.\-a-z0-9]*)$/); + + +#The most common ones +my $cdb; +my $adb; +my $pdb; +#my $ndb +#my $hdb +#my $ddb + +# Validation routines - parameters for each panel + + sub validate_TABLE { + my $c = shift; + my $ms_data = shift; #Data hash as parameter + # Validation for each field + my $ret = ""; + + if (! TRUE) #validate $c->param('account') + {$ret .= 'Validation for account failed';} + if (! TRUE) #validate $c->param('username') + {$ret .= 'Validation for username failed';} + if ($ret eq "") {$ret = 'ok';} + return $ret; + } + + sub validate_RULES { + my $c = shift; + my $ms_data = shift; #Data hash as parameter + # Validation for each field + my $ret = ""; + + if (! TRUE) #validate $c->param('basis') + {$ret .= 'Validation for basis failed';} + if (! TRUE) #validate $c->param('criterion') + {$ret .= 'Validation for criterion failed';} + if (! TRUE) #validate $c->param('basis2') + {$ret .= 'Validation for basis2 failed';} + if (! TRUE) #validate $c->param('criterion2') + {$ret .= 'Validation for criterion2 failed';} + if (! TRUE) #validate $c->param('action') + {$ret .= 'Validation for action failed';} + if (! TRUE) #validate $c->param('deliver') + {$ret .= 'Validation for deliver failed';} + if (! TRUE) #validate $c->param('folder') + {$ret .= 'Validation for folder failed';} + if (! TRUE) #validate $c->param('copy') + {$ret .= 'Validation for copy failed';} + if (! TRUE) #validate $c->param('action2') + {$ret .= 'Validation for action2 failed';} + if (! TRUE) #validate $c->param('deliver2') + {$ret .= 'Validation for deliver2 failed';} + if (! TRUE) #validate $c->param('key') + {$ret .= 'Validation for key failed';} + if ($ret eq "") {$ret = 'ok';} + return $ret; + } + + sub validate_REMOVE { + my $c = shift; + my $ms_data = shift; #Data hash as parameter + # Validation for each field + my $ret = ""; + + if (! TRUE) #validate $c->param('RemoveRule') + {$ret .= 'Validation for RemoveRule failed';} + if ($ret eq "") {$ret = 'ok';} + return $ret; + } + + +# Get singleton data for each panel + + sub get_data_for_panel_TABLE { + # Return a hash with the fields required which will be loaded into the shared data + my $c = shift; + my %ret = ( + 'Data1'=>'Data for TABLE', #Example + # fields from Inputs in TABLE $fields['TABLE'] + 'account'=>$c->get_panel_user(), + 'username'=> $c->get_full_name(), + + ); + return %ret; + } + + sub get_data_for_panel_RULES { + # Return a hash with the fields required which will be loaded into the shared data + my $c = shift; + my %ret = ( + 'Data1'=>'Data for RULES', #Example + # fields from Inputs in RULES $fields['RULES'] + 'basis'=>'basis contents', + 'criterion'=>'criterion contents', + 'basis2'=>'basis2 contents', + 'criterion2'=>'criterion2 contents', + 'action'=>'action contents', + 'deliver'=>'deliver contents', + 'folder'=>'folder contents', + 'copy'=>'copy contents', + 'action2'=>'action2 contents', + 'deliver2'=>'deliver2 contents', + 'key'=>'key contents', + + ); + return %ret; + } + + sub get_data_for_panel_REMOVE { + # Return a hash with the fields required which will be loaded into the shared data + my $c = shift; + my %ret = ( + 'Data1'=>'Data for REMOVE', #Example + # fields from Inputs in REMOVE $fields['REMOVE'] + 'RemoveRule'=>'RemoveRule contents', + + ); + return %ret; + } + + + +# Get control data for table(s) + + # Define a constant hash for field name mapping + use constant getAllRules_FIELD_MAPPING => ( + 'MatchAgainst' => 'basis', + 'TheRule' => 'criterion', + 'c2ndMatch' => 'basis2', + 'c2ndRule' => 'criterion2', + 'Action' => 'action', + 'Destination' => 'deliver', + 'Copy' => 'copy', + 'Destination2' => 'deliver2', + 'Serial Number' => 'key', + 'Modify' => 'Modify', + 'Remove' => 'Remove' + #'target_field2' => 'source_field2', + # Add more mappings as needed + ); + +sub actual_getAllRules { + my $c = shift; + my @ret = (); + # Actual code for extracting getAllRules + $cdb = esmith::ConfigDB->open(); + $adb = esmith::AccountsDB->open(); + $pdb = esmith::ConfigDB->open('processmail') or die "Could not open processmail DB\n"; + my $PanelUser = $c->get_panel_user(); + my @rules = $pdb->get_all_by_prop(type => "$PanelUser"); + return $c->l("NO_RULES") if (@rules == 0); + foreach my $rule (@rules) + { + my $key = $rule->key; + my $basis = $rule->prop("basis") || ''; + my $basis2 = $rule->prop("basis2") || ''; + my $deliver = $rule->prop("deliver") || ''; + my $deliver2 = $rule->prop("deliver2") || ''; + my $action = $rule->prop("action") || ''; + my $action2 = $rule->prop("action2") || ''; + my $folder = ("$action" eq "sort" )? $deliver : ''; + $folder = "INBOX" if "$folder" eq "" && "$action" eq "sort"; + my $copy = $rule->prop("copy") || ''; + my $oldpmRule = ''; + + for ($basis, $basis2) + { + if ($_ eq '<') + { $_ = 'sizelt'; } + elsif ($_ eq '>') + { $_ = 'sizegt'; } + } + + my $b1 = $c->l($basis); + my $b2 = $c->l($basis2); + + my $copyto = $rule->prop("deliver2") || '';# useless + if (($copy eq 'yes') && ($action2 eq 'inbox')) + { $deliver2 = ""; $copyto = 'inbox'; } # copyto is useless + + $deliver = GetDisplayName($deliver); + $deliver2 = GetDisplayName($deliver2); + + $key = $rule->key; + + push @data, + { + key => $key, + basis => $basis, + basis2 => $basis2, + criterion => $rule->prop("criterion") || '', + criterion2 => $rule->prop("criterion2") || '', + deliver => $deliver, + deliver2 => $deliver2, + folder => $folder, + action => $action, + action2 => $action2, + copy => $copy, + Modify => "".$c->l('MODIFY')."", + Remove => "".$c->l('REMOVE')."", + b1 => $b1, + b2 => $b2, + a => $a, + b => $b, + c => $c, + } + } + return @data; +} + +sub get_getAllRules { + # Return an array of hashes of the contents for each row and column for getAllRules + my $c = shift; + + + my @source_records = $c->actual_getAllRules(); + my @transformed_records; + my %Field_Mapping = getAllRules_FIELD_MAPPING(); + # Iterate over each record in the source array + for my $source_record (@source_records) { + my %transformed_record; + # Iterate over each key-value pair in the $Field_Mapping constant + while (my ($target, $source) = each %Field_Mapping) { + # Check if the source field exists in the source record + if (exists $source_record->{$source}) { + # Assign the source field value to the target field in the transformed record + $transformed_record{$target} = $source_record->{$source}; + } + } + # Add transformed record to the array if it's not empty + push @transformed_records, \%transformed_record if %transformed_record; + } + return \@transformed_records; +} + + + +# Return hash with values from row in which link clicked on table + + sub get_selected_TABLE { + my $c = shift; + my $selected = shift; #Parameter is name of selected row. + my $is_new_record = shift; #Indicates new record required (defaults) + my %ret = {}; + return %ret; + } + + sub get_selected_RULES { + my $c = shift; + my $selected = shift; #Parameter is name of selected row. + my $is_new_record = shift; #Indicates new record required (defaults) + my %ret = {}; + return %ret; + } + + sub get_selected_REMOVE { + my $c = shift; + my $selected = shift; #Parameter is name of selected row. + my $is_new_record = shift; #Indicates new record required (defaults) + my %ret = {}; + return %ret; + } + + +#after sucessful modify or create or whatever and submit then perfom (if the params validate) + + sub perform_TABLE { + my $c = shift; + my $ms_data = shift; #Data hash as parameter + my $ret = ""; + my $db = $cdb; #maybe one of the others + my $dbkey = 'ChangeThis'; + # To make it write to DB as comment, delete this (regex) string in each if statement "TRUE\) \#copy or perform with value: .* e.g." + + if (! TRUE) #copy or perform with value: account e.g. $db->set_prop($dbkey,'account',$c->param('account'),type=>'service')) + {$ret .= 'Perform/save failed for account';} + if (! TRUE) #copy or perform with value: username e.g. $db->set_prop($dbkey,'username',$c->param('username'),type=>'service')) + {$ret .= 'Perform/save failed for username';} + if ($ret eq "") {$ret = 'ok';} + return $ret; + } + + sub perform_RULES { + my $c = shift; + my $ms_data = shift; #Data hash as parameter + my $ret = ""; + my $db = $cdb; #maybe one of the others + my $dbkey = 'ChangeThis'; + # To make it write to DB as comment, delete this (regex) string in each if statement "TRUE\) \#copy or perform with value: .* e.g." + + if (! TRUE) #copy or perform with value: basis e.g. $db->set_prop($dbkey,'basis',$c->param('basis'),type=>'service')) + {$ret .= 'Perform/save failed for basis';} + if (! TRUE) #copy or perform with value: criterion e.g. $db->set_prop($dbkey,'criterion',$c->param('criterion'),type=>'service')) + {$ret .= 'Perform/save failed for criterion';} + if (! TRUE) #copy or perform with value: basis2 e.g. $db->set_prop($dbkey,'basis2',$c->param('basis2'),type=>'service')) + {$ret .= 'Perform/save failed for basis2';} + if (! TRUE) #copy or perform with value: criterion2 e.g. $db->set_prop($dbkey,'criterion2',$c->param('criterion2'),type=>'service')) + {$ret .= 'Perform/save failed for criterion2';} + if (! TRUE) #copy or perform with value: action e.g. $db->set_prop($dbkey,'action',$c->param('action'),type=>'service')) + {$ret .= 'Perform/save failed for action';} + if (! TRUE) #copy or perform with value: deliver e.g. $db->set_prop($dbkey,'deliver',$c->param('deliver'),type=>'service')) + {$ret .= 'Perform/save failed for deliver';} + if (! TRUE) #copy or perform with value: folder e.g. $db->set_prop($dbkey,'folder',$c->param('folder'),type=>'service')) + {$ret .= 'Perform/save failed for folder';} + if (! TRUE) #copy or perform with value: copy e.g. $db->set_prop($dbkey,'copy',$c->param('copy'),type=>'service')) + {$ret .= 'Perform/save failed for copy';} + if (! TRUE) #copy or perform with value: action2 e.g. $db->set_prop($dbkey,'action2',$c->param('action2'),type=>'service')) + {$ret .= 'Perform/save failed for action2';} + if (! TRUE) #copy or perform with value: deliver2 e.g. $db->set_prop($dbkey,'deliver2',$c->param('deliver2'),type=>'service')) + {$ret .= 'Perform/save failed for deliver2';} + if (! TRUE) #copy or perform with value: key e.g. $db->set_prop($dbkey,'key',$c->param('key'),type=>'service')) + {$ret .= 'Perform/save failed for key';} + if ($ret eq "") {$ret = 'ok';} + return $ret; + } + + sub perform_REMOVE { + my $c = shift; + my $ms_data = shift; #Data hash as parameter + my $ret = ""; + my $db = $cdb; #maybe one of the others + my $dbkey = 'ChangeThis'; + # To make it write to DB as comment, delete this (regex) string in each if statement "TRUE\) \#copy or perform with value: .* e.g." + + if (! TRUE) #copy or perform with value: RemoveRule e.g. $db->set_prop($dbkey,'RemoveRule',$c->param('RemoveRule'),type=>'service')) + {$ret .= 'Perform/save failed for RemoveRule';} + if ($ret eq "") {$ret = 'ok';} + return $ret; + } + + +sub create_link{ + # WIP + my ($c,$route, $panel, $index) = @_; + my $link = "$route?trt=$panel&Selected=$index"; + return $link; +} + +sub get_panel_user +{ + my $c = shift; + return $c->session->{username}; +} + +sub get_full_name{ + my $c = shift; + my $adb = esmith::AccountsDB->open(); + my $PanelUser = $c->get_panel_user(); + return $adb->get_prop($PanelUser, "FirstName") . " " . + $adb->get_prop($PanelUser, "LastName"); +} + +sub GetDisplayName { + my ($s) = @_; + $s =~ s/(.*)//; # untaint the input + my $decoded = decode('IMAP-UTF-7', $1); + return $decoded; +} + +sub get_Folders { + my $c = shift; + my $folders_hashref = $c->listfolders(); + # Convert hashref to arrayref of arrayrefs for Mojolicious select + my @options = map { [ $_, $folders_hashref->{$_} ] } sort keys %$folders_hashref; + return \@options; +} + +sub listfolders +{ + my $c = shift; + use File::Find::Rule; + my $PanelUser = $c->get_panel_user(); + my $root="/home/e-smith/files/users/$PanelUser/Maildir"; + $root="/home/e-smith/Maildir" if "$PanelUser" eq "admin" ; + my @dirs = File::Find::Rule->new + ->extras({ untaint => 1 , untaint_pattern => qr|^([-+@\w&. /]+)$| }) + ->directory + ->maxdepth(1) + ->in($root); + my %out_dir; + $out_dir{"INBOX"} .= "INBOX"; + $out_dir{""} .= ""; + for (sort @dirs) { + s/$root\/?\.?//; + my @exclu =("cur", "tmp", "new" , "INBOX" ); + next if $_ ~~ @exclu; + $out_dir{$_} .= GetDisplayName(join('/',split('\.', $_))); + } + return \%out_dir; +} + + +1; \ No newline at end of file diff --git a/root/usr/share/smanager/lib/SrvMngr/Controller/Mailsorting.pm b/root/usr/share/smanager/lib/SrvMngr/Controller/Mailsorting.pm new file mode 100644 index 0000000..ebebe8a --- /dev/null +++ b/root/usr/share/smanager/lib/SrvMngr/Controller/Mailsorting.pm @@ -0,0 +1,358 @@ +package SrvMngr::Controller::Mailsorting; +# +# Generated by SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-05-04 12:59:05 +# Remember that each route must be unique (else they just overwrite each other). +# you cannot have get and post on the same name and url. +# +#---------------------------------------------------------------------- +# heading : System +# description : Process Mail +# navigation : 6000 1200 +# +# name : mailsorting, method : get, url : /mailsorting, ctlact : Mailsorting#main +# name : mailsortingu, method : post, url : /mailsortingu, ctlact : Mailsorting#do_update +# name : mailsortingd, method : get, url : /mailsortingd, ctlact : Mailsorting#do_display + +# +# routes : end +# +# Documentation: https://wiki.contribs.org/Mailsorting +#---------------------------------------------------------------------- + +# +# Scheme of things: +# +# TBA!! + +use strict; +use warnings; +use Mojo::Base 'Mojolicious::Controller'; + +use constant FALSE => 0; +use constant TRUE => 1; + +use Locale::gettext; +use SrvMngr::I18N; +use SrvMngr qw(theme_list init_session); + +use Data::Dumper; + +use esmith::util; +use esmith::util::network; +use esmith::ConfigDB; +use esmith::AccountsDB; +use esmith::NetworksDB; +use esmith::HostsDB; +use esmith::DomainsDB; + +my $cdb; +my $adb; +my $ndb; +my $hdb; +my $ddb; + +my %ms_data; + +require '/usr/share/smanager/lib/SrvMngr/Controller/Mailsorting-Custom.pm'; #The code that is to be added by the developer + +sub main { +# +# Initial entry - route is "/" +# +#set initial panel +#for initial panel: + #Specifiy panel to enter + #load up _data hash with DB fields + #load up stash with pointer(s) to control fields hash(= get-)) + #and a pointer to the prefix_data hash +#render initial panel + + my $c = shift; + $c->app->log->info( $c->log_req ); + + #The most common ones + $cdb = esmith::ConfigDB->open() || die("Couldn't open config db"); + $adb = esmith::AccountsDB->open() || die("Couldn't open Accounts db"); + $ndb = esmith::NetworksDB->open() || die("Couldn't open Network db"); + $hdb = esmith::HostsDB->open() || die("Couldn't open Hosts db"); + $ddb = esmith::DomainsDB->open() || die("Couldn't open Domains db"); + + %ms_data = (); + my $title = $c->l('ms_Process_Mail'); + my $modul = ''; + + $ms_data{'trt'} = 'TABLE'; + + #Load any DB entries into the _data area so as they are preset in the form + # which DB - this only really works if the initial panel is a PARAMS type panel and not a TABLE + my $db = $cdb; #pickup local or global db or Default to config + + + $c->do_display($ms_data{'trt'}); + +} + +# Post request with params - submit from the form +sub do_update { +# +# Return after submit pushed on panel (this is a post) - route is "/u" +# parameters in the params hash. +# +#load up all params into prefix_data hash: +#By panel (series of if statements - only one executed): + #call validate-PANEL() - return ret = ok or error message + +#if validation not ok: + #render back to current panel with error message in stash +#otherwise: + #By panel (series of if statements - only one executed): + #do whatever is required: call perform-PANEL() - return "ok" or Error Message + #call signal-event for any global actions specified (check it exists - error and continue?) + #if action smeserver--update exists + #signal_event smeserver--update + #call signal-event for any specific actions for thids panel (check it exists first - error and continue) + #set success in stash + #if no "nextpanel" entry: + #set firstpanel + #else + #set nextpanel + #call render + + my $c = shift; + $c->app->log->info($c->log_req); + my $modul = ''; + + #The most common ones - you might want to comment out any not used. + $cdb = esmith::ConfigDB->open() || die("Couldn't open config db"); + $adb = esmith::AccountsDB->open() || die("Couldn't open Accounts db"); + $ndb = esmith::NetworksDB->open() || die("Couldn't open Network db"); + $hdb = esmith::HostsDB->open() || die("Couldn't open Hosts db"); + $ddb = esmith::DomainsDB->open() || die("Couldn't open Domains db"); + + my $title = $c->l('ms_Process_Mail'); + + # Accessing all POST/GET parameters + my $params = $c->req->params->to_hash; + + # Get number of POST parameters + #my $num_params = keys scaler %$params; + + #Params are available in the hash "params" - copy to the prefix_data hash + #while (my ($key, $value) = each %{$c->req->params->to_hash}) { + # $ms_data{$key} = $value; + #} + + # the value of trt will tell you which panel has returned + my $trt = $c->param('trt') || 'TABLE'; #hidden control on every form. + my $ret = 'ok'; + + #Validate the parameters in a custom sub one for each panel (although only one of these will be executed) + my $thispanel; + + if ($trt eq 'TABLE'){ + #Validate form parameters for panel TABLE + $ret = $c->validate_TABLE(\%ms_data); + $thispanel = 'TABLE'; + } + + if ($trt eq 'RULES'){ + #Validate form parameters for panel RULES + $ret = $c->validate_RULES(\%ms_data); + $thispanel = 'RULES'; + } + + if ($trt eq 'REMOVE'){ + #Validate form parameters for panel REMOVE + $ret = $c->validate_REMOVE(\%ms_data); + $thispanel = 'REMOVE'; + } + + if ($ret ne "ok"){ + $c->do_display($thispanel); + } else { + #Do whatever is needed, including writing values to the DB + + + if ($trt eq 'TABLE'){ + #do whatever is required ... + $ret = $c->perform_TABLE(\%ms_data); + if ($ret ne "ok") { + # return to the panel with error message + $c->stash(error => $c->l($ret)); + $c->stash( + title => $title, + modul => $modul, + ms_data => \%ms_data + ); + $c->render(template => "mailsorting"); + } else { + $c->stash( success => $c->l('ms_TABLE_panel_action_was_successful')); #A bit bland - edit it in the lex file + } + } + + if ($trt eq 'RULES'){ + #do whatever is required ... + $ret = $c->perform_RULES(\%ms_data); + if ($ret ne "ok") { + # return to the panel with error message + $c->stash(error => $c->l($ret)); + $c->stash( + title => $title, + modul => $modul, + ms_data => \%ms_data + ); + $c->render(template => "mailsorting"); + } else { + $c->stash( success => $c->l('ms_RULES_panel_action_was_successful')); #A bit bland - edit it in the lex file + } + } + + if ($trt eq 'REMOVE'){ + #do whatever is required ... + $ret = $c->perform_REMOVE(\%ms_data); + if ($ret ne "ok") { + # return to the panel with error message + $c->stash(error => $c->l($ret)); + $c->stash( + title => $title, + modul => $modul, + ms_data => \%ms_data + ); + $c->render(template => "mailsorting"); + } else { + $c->stash( success => $c->l('ms_REMOVE_panel_action_was_successful')); #A bit bland - edit it in the lex file + } + } + + # and call any signal-events needed + #TBD + # Setup shared data and call panel + if ('none' eq 'none') { + $ms_data{'trt'} = 'TABLE'; + } else { + $ms_data{'trt'} = 'none'; + } + $c->do_display($ms_data{'trt'}); + } +} + +sub do_display { +# +# Return after link clicked in table (this is a get) - route is "/d" +# Expects ?trt=PANEL&selected="TableRowName" plus any other required +# +# OR it maybe a post from the main panel to add a new record +# +#load up all supplied params into prefix_data hash +#call get-selected-PANEL() - returns hash of all relevent parameters +#load up returned hash into prefix_data +#render - to called panel + + my ($c,$trt) = @_; + $c->app->log->info($c->log_req); + + #The most common ones - you might want to comment out any not used. + $cdb = esmith::ConfigDB->open() || die("Couldn't open config db"); + $adb = esmith::AccountsDB->open() || die("Couldn't open Accounts db"); + $ndb = esmith::NetworksDB->open() || die("Couldn't open Network db"); + $hdb = esmith::HostsDB->open() || die("Couldn't open Hosts db"); + $ddb = esmith::DomainsDB->open() || die("Couldn't open Domains db"); + + my $title = $c->l('ms_Process_Mail'); + my $modul = ""; + + # Accessing all parameters + my $params = $c->req->params->to_hash; + + # Get number of parameters + my $num_params = keys %$params; + + #Tag as Post or Get (ie. create new entry or edit existing one + my $is_new_record = ($c->req->method() eq 'POST'); + + #Params are available in the hash "params" - copy to the prefix_data hash + #while (my ($key, $value) = each %{$c->req->params->to_hash}) { + # $ms_data{$key} = $value; + #} + + # the value of trt will tell you which panel has returned + if (! $trt){ + $trt = $c->param('trt') || 'TABLE'; #Indicates where to go now + } + + # Now add in the params from the selected row from the table + + my %selectedrow; + + if ($trt eq 'TABLE'){ + #Validate Get selected row (if applicable) TABLE + %selectedrow = $c->get_selected_TABLE($ms_data{'Selected'},$is_new_record); + } + + if ($trt eq 'RULES'){ + #Validate Get selected row (if applicable) RULES + %selectedrow = $c->get_selected_RULES($ms_data{'Selected'},$is_new_record); + } + + if ($trt eq 'REMOVE'){ + #Validate Get selected row (if applicable) REMOVE + %selectedrow = $c->get_selected_REMOVE($ms_data{'Selected'},$is_new_record); + } + + + #Copy in the selected row params to the prefix_data hash to pass to the panel + while (my ($key, $value) = each %selectedrow){ + $ms_data{$key} = $value; + } + # Where to go now + $ms_data{'trt'} = $trt; + + # Set up other shared data according to the panel to go to + + if ($trt eq 'TABLE'){ + # pickup any other contents needed and load them into hash shared with panel + my %returned_hash; + # subroutine returns a hash directly + %returned_hash = $c->get_data_for_panel_TABLE(); + # Copy each key-value pair from the returned hash to the prefix data hash + while (my ($key, $value) = each %returned_hash) { + $ms_data{$key} = $value; + } + } + + if ($trt eq 'RULES'){ + # pickup any other contents needed and load them into hash shared with panel + my %returned_hash; + # subroutine returns a hash directly + %returned_hash = $c->get_data_for_panel_RULES(); + # Copy each key-value pair from the returned hash to the prefix data hash + while (my ($key, $value) = each %returned_hash) { + $ms_data{$key} = $value; + } + } + + if ($trt eq 'REMOVE'){ + # pickup any other contents needed and load them into hash shared with panel + my %returned_hash; + # subroutine returns a hash directly + %returned_hash = $c->get_data_for_panel_REMOVE(); + # Copy each key-value pair from the returned hash to the prefix data hash + while (my ($key, $value) = each %returned_hash) { + $ms_data{$key} = $value; + } + } + + + # and table control fields + $c->stash(getAllRules=>$c->get_getAllRules()); + + + # Data for panel + $c->stash( + title => $title, + modul => $modul, + ms_data => \%ms_data + ); + $c->render(template => "mailsorting"); +} +1; \ No newline at end of file diff --git a/root/usr/share/smanager/lib/SrvMngr/I18N/Modules/Mailsorting/mailsorting_en.lex b/root/usr/share/smanager/lib/SrvMngr/I18N/Modules/Mailsorting/mailsorting_en.lex new file mode 100644 index 0000000..e5bdacc --- /dev/null +++ b/root/usr/share/smanager/lib/SrvMngr/I18N/Modules/Mailsorting/mailsorting_en.lex @@ -0,0 +1,41 @@ +# +# Generated by SM2Gen version: SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-05-04 12:59:05 +# +'ms_Modify_your_rule.' => 'Modify your rule', +'ms_REMOVE_panel_action_was_successful' => 'REMOVE panel action was successful', +'ms_criterion' => 'Criterion', +'ms_APPLY' => 'Apply', +'ms_RULES_panel_action_was_successful' => 'RULES panel action was successful', +'ms_Rule_contents' => 'Rule contents', +'ms_Add_new_rule' => 'Add new rule', +'ms_action2' => 'action', +'ms_You_are_about_to_remove' => 'You are about to remove a rule', +'ms_You_can_change_the_order' => 'You can change the order in which rules are evaluated by altering the numeric value in order of rule execution Priority is determined by asci value And must be unique beg rule user101 goes first Then user then user', +'ms_Remove' => 'Remove', +'ms_The_Rule' => 'The Rule', +'ms_key' => 'Key', +'ms_Rules_are_executed_as_email' => 'Rules are executed as email arrives in your mailbox on the server And are independent of your email client Your current rules If you have any are listed below', +'ms_2nd_Rule' => '2nd Rule', +'ms_Action' => 'Action', +'ms_Save' => 'Save', +'ms_TABLE_panel_action_was_successful' => 'TABLE panel action was successful', +'ms_Match_Against' => 'Match Against', +'ms_2nd_Match' => '2nd Match', +'ms_Copy' => 'Copy', +'ms_criterion2' => 'criterion', +'ms_deliver2' => 'deliver', +'ms_basis2' => 'basis', +'ms_Mail_sorting_rules' => 'Mail sorting rules', +'ms_User_Name' => 'User Name', +'ms_folder' => 'Folder', +'ms_action' => 'Action', +'ms_copy' => 'Copy', +'ms_basis' => 'Basis', +'ms_Account' => 'Account', +'ms_Serial_Number' => 'Serial Number', +'ms_Manage_mailsortingModifyRule_settings:' => 'Manage mailsortingModifyRule settings', +'ms_Destination' => 'Destination', +'ms_Modify' => 'Modify', +'ms_Process_Mail' => 'Process Mail', +'ms_deliver' => 'Deliver', +'ms_Current_rules' => 'Current rules', \ No newline at end of file diff --git a/root/usr/share/smanager/themes/default/public/css/mailsorting.css b/root/usr/share/smanager/themes/default/public/css/mailsorting.css new file mode 100644 index 0000000..a1f2099 --- /dev/null +++ b/root/usr/share/smanager/themes/default/public/css/mailsorting.css @@ -0,0 +1,39 @@ +/* +Generated by: SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-05-04 12:59:05 +*/ +.Mailsorting-panel {} +.name {} +.rout {} +.head {} +.para1 {} +.text97 {} +.text96 {} +.link1 {} +.subh {} +.tabl1 {} +thead .tabl1 {} +tbody .tabl1 {} +.name {} +.rout {} +.head {} +.subh {} +.para1 {} +.para2 {} +.sele1 {} +.text2 {} +.sele3 {} +.text4 {} +.sele5 {} +.text6 {} +.sele7 {} +.sele8 {} +.sele9 {} +.text10 {} +.text11 {} +.subm12 {} +.name {} +.rout {} +.head {} +.subh {} +.text94 {} +.subm95 {} diff --git a/root/usr/share/smanager/themes/default/public/js/mailsorting.js b/root/usr/share/smanager/themes/default/public/js/mailsorting.js new file mode 100644 index 0000000..233dbb1 --- /dev/null +++ b/root/usr/share/smanager/themes/default/public/js/mailsorting.js @@ -0,0 +1,5 @@ +// +//Generated by: SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-05-04 12:59:05 +// +$(document).ready(function() { +}); diff --git a/root/usr/share/smanager/themes/default/templates/mailsorting.html.ep b/root/usr/share/smanager/themes/default/templates/mailsorting.html.ep new file mode 100644 index 0000000..b80347d --- /dev/null +++ b/root/usr/share/smanager/themes/default/templates/mailsorting.html.ep @@ -0,0 +1,64 @@ +%# +%# Generated by SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-05-04 12:59:05 +%# +% layout 'default', title => "Sme server 2 - Process Mail", share_dir => './'; +%# css specific to this panel: +% content_for 'module' => begin +%= stylesheet '/css/mailsorting.css' +%= javascript '/js/mailsorting.js' +
+ + % if (config->{debug} == 1) { +
+		%= dumper $c->current_route
+		%= dumper $ms_data->{trt}
+	
+ % } + +

<%=$title%>

+ + % if ( stash('modul')) { + %= $c->render_to_string(inline => stash('modul') ); + % } + + %if ($c->stash('first')) { +

+ %=$c->render_to_string(inline =>$c->l($c->stash('first'))) +

+ + %} elsif ($c->stash('success')) { +
+

+ %= $c->l($c->stash('success')); +

+
+
+ + %} elsif ($c->stash('error')) { +
+

+ %= $c->l($c->stash('error')); +

+
+
+ %} + + %#Routing to partials according to trt parameter. + %#This ought to be cascading if/then/elsif, but is easier to just stack the if/then's rather like a case statement' + + % if ($ms_data->{trt} eq "TABLE") { + %= include 'partials/_ms_TABLE' + %} + + % if ($ms_data->{trt} eq "RULES") { + %= include 'partials/_ms_RULES' + %} + + % if ($ms_data->{trt} eq "REMOVE") { + %= include 'partials/_ms_REMOVE' + %} + + + +
+%end \ No newline at end of file diff --git a/root/usr/share/smanager/themes/default/templates/partials/_ms_REMOVE.html.ep b/root/usr/share/smanager/themes/default/templates/partials/_ms_REMOVE.html.ep new file mode 100644 index 0000000..9faf58d --- /dev/null +++ b/root/usr/share/smanager/themes/default/templates/partials/_ms_REMOVE.html.ep @@ -0,0 +1,38 @@ +%# +%# Generated by SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-05-04 12:59:05 +%# +
+ + % if (config->{debug} == 1) { +
+			%= dumper $ms_data
+		
+ % } + % my $btn = l('ms_APPLY'); + %= form_for "mailsortingu" => (method => 'POST') => begin + % param 'trt' => $ms_data->{trt} unless param 'trt'; + %= hidden_field 'trt' => $ms_data->{trt} + %# Inputs etc in here. + +

<%=l('ms_Mail_sorting_rules')%>

+ +

<%=l('ms_You_are_about_to_remove')%>

+ + + %=l('ms_Rule_contents') + + % param 'RemoveRule' => $ms_data->{RemoveRule} unless param 'RemoveRule'; + %= text_area 'RemoveRule', cols=>40, rows=>10, Readonly=>'true',' +
+ + + %= submit_button l('ms_Remove'), class => 'action subm95' + + + %# Probably finally by a submit. + %end +
\ No newline at end of file diff --git a/root/usr/share/smanager/themes/default/templates/partials/_ms_RULES.html.ep b/root/usr/share/smanager/themes/default/templates/partials/_ms_RULES.html.ep new file mode 100644 index 0000000..687c0d8 --- /dev/null +++ b/root/usr/share/smanager/themes/default/templates/partials/_ms_RULES.html.ep @@ -0,0 +1,122 @@ +%# +%# Generated by SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-05-04 12:59:05 +%# +
+ + % if (config->{debug} == 1) { +
+			%= dumper $ms_data
+		
+ % } + % my $btn = l('ms_APPLY'); + %= form_for "mailsortingu" => (method => 'POST') => begin + % param 'trt' => $ms_data->{trt} unless param 'trt'; + %= hidden_field 'trt' => $ms_data->{trt} + %# Inputs etc in here. + +

<%=l('ms_Mail_sorting_rules')%>

+ +

<%=l('ms_Manage_mailsortingModifyRule_settings:')%>

+ +

+ %=l('ms_Modify_your_rule.') +

+ +

+ %=l('ms_You_can_change_the_order') +

+ +

+ %=l('ms_basis') + + % my @basis_options = [['Subject' => 'Subject'], ['To' => 'TO_'], ['From' => 'From'], ['Email Headers' => 'headers'], ['Size greater than' => 'sizegt'], ['Size less than' => 'sizelt']]; + % param 'basis' => $ms_data->{basis} unless param 'basis'; + %= select_field 'basis' => @basis_options, class => 'input', id => 'basis_select' +

+ +

+ %=l('ms_criterion') + + % param 'criterion' => $ms_data->{criterion} unless param 'criterion'; + %= text_field 'criterion', size => '50', class => 'textinput criterion' , pattern=>'.*' , placeholder=>'criterion', title =>'Pattern regex mismatch', id => 'criterion_text' +

+ +

+ %=l('ms_basis2') + + % my @basis2_options = [['' => ''], ['Subject' => 'Subject'], ['To' => 'TO_'], ['From' => 'From'], ['Email Headers' => 'headers']]; + % param 'basis2' => $ms_data->{basis2} unless param 'basis2'; + %= select_field 'basis2' => @basis2_options, class => 'input', id => 'basis2_select' +

+ +

+ %=l('ms_criterion2') + + % param 'criterion2' => $ms_data->{criterion2} unless param 'criterion2'; + %= text_field 'criterion2', size => '50', class => 'textinput criterion2' , pattern=>'.*' , placeholder=>'criterion2', title =>'Pattern regex mismatch', id => 'criterion2_text' +

+ +

+ %=l('ms_action') + + % my @action_options = [['Delete email' => 'delete'], ['Forward email' => 'forward'], ['Sort to mail folder' => 'sort']]; + % param 'action' => $ms_data->{action} unless param 'action'; + %= select_field 'action' => @action_options, class => 'input', id => 'action_select' +

+ +

+ %=l('ms_deliver') + + % param 'deliver' => $ms_data->{deliver} unless param 'deliver'; + %= text_field 'deliver', size => '50', class => 'textinput deliver' , pattern=>'.*' , placeholder=>'deliver', title =>'Pattern regex mismatch', id => 'deliver_text' +

+ +

+ %=l('ms_folder') + + % my @folder_options = $c->get_Folders(); + % param 'folder' => $ms_data->{folder} unless param 'folder'; + %= select_field 'folder' => @folder_options, class => 'input', id => 'folder_select' +

+ +

+ %=l('ms_copy') + + % my @copy_options = [['No' => 'no'], ['Yes' => 'yes']]; + % param 'copy' => $ms_data->{copy} unless param 'copy'; + %= select_field 'copy' => @copy_options, class => 'input', id => 'copy_select' +

+ +

+ %=l('ms_action2') + + % my @action2_options = [['' => ''], ['Delete email' => 'delete'], ['Forward email' => 'forward'], ['Send to my inbox' => 'inbox']]; + % param 'action2' => $ms_data->{action2} unless param 'action2'; + %= select_field 'action2' => @action2_options, class => 'input', id => 'action2_select' +

+ +

+ %=l('ms_deliver2') + + % param 'deliver2' => $ms_data->{deliver2} unless param 'deliver2'; + %= text_field 'deliver2', size => '50', class => 'textinput deliver2' , pattern=>'.*' , placeholder=>'deliver2', title =>'Pattern regex mismatch', id => 'deliver2_text' +

+ +

+ %=l('ms_key') + + % param 'key' => $ms_data->{key} unless param 'key'; + %= text_field 'key', size => '50', class => 'textinput key' , pattern=>'.*' , placeholder=>'key', title =>'Pattern regex mismatch', id => 'key_text' +

+ + + %= submit_button l('ms_Save'), class => 'action subm12' + + + %# Probably finally by a submit. + %end +
\ No newline at end of file diff --git a/root/usr/share/smanager/themes/default/templates/partials/_ms_TABLE.html.ep b/root/usr/share/smanager/themes/default/templates/partials/_ms_TABLE.html.ep new file mode 100644 index 0000000..fe6c49c --- /dev/null +++ b/root/usr/share/smanager/themes/default/templates/partials/_ms_TABLE.html.ep @@ -0,0 +1,88 @@ +%# +%# Generated by SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-05-04 12:59:05 +%# +
+ + % if (config->{debug} == 1) { +
+			%= dumper $ms_data
+		
+ % } + % my $btn = l('ms_APPLY'); + %= form_for "mailsortingu" => (method => 'POST') => begin + % param 'trt' => $ms_data->{trt} unless param 'trt'; + %= hidden_field 'trt' => $ms_data->{trt} + %# Inputs etc in here. + +

<%=l('ms_Mail_sorting_rules')%>

+ +

+ %=l('ms_Rules_are_executed_as_email') +

+ +

+ %=l('ms_Account') + + % param 'account' => $ms_data->{account} unless param 'account'; + %= text_field 'account', size => '50', class => 'textinput account' , pattern=>'.*' , placeholder=>'account', title =>'Pattern regex mismatch', id => 'account_text' +

+ +

+ %=l('ms_User_Name') + + % param 'username' => $ms_data->{username} unless param 'username'; + %= text_field 'username', size => '50', class => 'textinput username' , pattern=>'.*' , placeholder=>'username', title =>'Pattern regex mismatch', id => 'username_text' +

+ + + %= l('ms_Add_new_rule') + + %#= link_to l('ms_Add_new_rule'), 'mailsortingdd?trt=RULES' , class=>'link link1' + + +

<%=l('ms_Current_rules')%>

+ +
+ + + + + + + + + + + + + + + + + % my $control_data = $c->stash('getAllRules'); + % foreach my $row (@$control_data) { + + + + + + + + + + + + + + %} + +
<%=l('ms_Match_Against')%><%=l('ms_The_Rule')%><%=l('ms_2nd_Match')%><%=l('ms_2nd_Rule')%><%=l('ms_Action')%><%=l('ms_Destination')%><%=l('ms_Copy')%><%=l('ms_Destination')%><%=l('ms_Serial_Number')%><%=l('ms_Modify')%><%=l('ms_Remove')%>
<%=$c->render_to_string(inline=>$row->{'MatchAgainst'})%><%=$c->render_to_string(inline=>$row->{'TheRule'})%><%=$c->render_to_string(inline=>$row->{'c2ndMatch'})%><%=$c->render_to_string(inline=>$row->{'c2ndRule'})%><%=$c->render_to_string(inline=>$row->{'Action'})%><%=$c->render_to_string(inline=>$row->{'Destination'})%><%=$c->render_to_string(inline=>$row->{'Copy'})%><%=$c->render_to_string(inline=>$row->{'Destination2'})%><%=$c->render_to_string(inline=>$row->{'Serial Number'})%><%=$c->render_to_string(inline=>$row->{'Modify'})%><%=$c->render_to_string(inline=>$row->{'Remove'})%>
+ + + %# Probably finally by a submit. + %end +
\ No newline at end of file diff --git a/smeserver-mailsorting.spec b/smeserver-mailsorting.spec index 9c72f35..475b75a 100644 --- a/smeserver-mailsorting.spec +++ b/smeserver-mailsorting.spec @@ -5,8 +5,8 @@ Summary: Lets users configure procmail or maildrop rules. %define name smeserver-mailsorting Name: %{name} -%define version 1.4 -%define release 17 +%define version 11.0.0 +%define release 2 Version: %{version} Release: %{release}%{?dist} License: GPL @@ -15,13 +15,14 @@ Group: SMEserver/addon Source: %{name}-%{version}.tar.xz BuildArchitectures: noarch -BuildRoot: /var/tmp/%{name}-%{version} + BuildRoot: /var/tmp/%{name}-%{version} Requires: smeserver-release >= 9.0 -Requires: perl-Unicode-IMAPUtf7 +#Requires: perl-Unicode-IMAPUtf7 Requires: smeserver-formmagick >= 1.4.0-12 Requires: perl-File-Find-Rule >= 0.33 Requires: maildrop Requires: procmail +Requires: perl-Encode-IMAPUTF7 #Requires: smeserver-userpanel, userpanel causes endless problems BuildRequires: smeserver-devtools >= 1.13.1-03 AutoReqProv: no @@ -31,6 +32,13 @@ SME Server enhancement to enable procmail or maildrop filtering for users. Optionally provides user panels where users can create mail rules for themselves %changelog +* Mon May 05 2025 Brian Read 11.0.0-2.sme +- Add first go at SM2 panels - still wip + +* Fri May 02 2025 Brian Read 11.0.0-1.sme +- Initial build for SME11 [SME: ] +- Remove use of Unicode::IMAPUtf7 as no rpm for Rocky8 + * Sun Sep 08 2024 fix-e-smith-pkg.sh by Trevor Batley 1.4-17.sme - Fix e-smith references in smeserver-mailsorting [SME: 12732] @@ -299,6 +307,7 @@ echo "%doc COPYING" >> %{name}-%{version}-filelist %clean %pre + %preun %post @@ -306,7 +315,7 @@ echo "%doc COPYING" >> %{name}-%{version}-filelist if [ $1 = 1 ] ; then echo '' echo '#############################################################' - echo ' Please visit the url below to apprehend all the db commands' + echo ' Please visit the url below to understand all the db commands' echo ' http://wiki.contribs.org/Mailsorting#Configuration ' echo '#############################################################' echo ''