[Bps-public-commit] rt-extension-spamfilter branch, master, updated. d36bb4c9cb51eb0e9d2ce820565846d37af0b1bd

Jim Brandt jbrandt at bestpractical.com
Thu Dec 17 10:36:55 EST 2020


The branch, master has been updated
       via  d36bb4c9cb51eb0e9d2ce820565846d37af0b1bd (commit)
       via  faaac0871d702333e687fd80393a96e4d1f02793 (commit)
       via  9f3801d8dff97bcff30ec71c360a67b8676ac3cd (commit)
       via  f4d0194ff769d90b18811a9c0d7a3ca09af53def (commit)
       via  67d74a136e755f40ff5860899333120ac2873d06 (commit)
       via  8b9c1b223f6c4e7d81cbe047c97cdc88e1572a56 (commit)
       via  baffc9a275031cc4bf3562c50b2a86508310a872 (commit)
       via  6d6a96152c801c2e454395e2a477095fddd20a5a (commit)
       via  b5948c6743b4e64c96a07db338904890566b044a (commit)
      from  4b4e22e2d220446e379227224e56107339971fdb (commit)

Summary of changes:
 Changes                                   |   6 +-
 META.yml                                  |  15 +-
 Makefile.PL                               |   2 +-
 README                                    | 104 ++++++++
 html/Tools/SpamFilter/Display.html        |  24 +-
 html/Tools/SpamFilter/Elements/ShowBasics |  52 ++--
 inc/Module/Install.pm                     |  51 ++--
 inc/Module/Install/Base.pm                |   2 +-
 inc/Module/Install/Can.pm                 |  13 +-
 inc/Module/Install/Fetch.pm               |   2 +-
 inc/Module/Install/Include.pm             |   2 +-
 inc/Module/Install/Makefile.pm            |   4 +-
 inc/Module/Install/Metadata.pm            |   6 +-
 inc/Module/Install/RTx.pm                 | 105 ++++++--
 inc/Module/Install/RTx/Runtime.pm         |   1 +
 inc/Module/Install/ReadmeFromPod.pm       |  76 ++++--
 inc/Module/Install/Win32.pm               |   2 +-
 inc/Module/Install/WriteAll.pm            |   2 +-
 inc/YAML/Tiny.pm                          |  37 ++-
 inc/unicore/Name.pm                       | 417 ------------------------------
 lib/RT/Extension/SpamFilter.pm            |  54 +++-
 static/css/SpamFilter.css                 |   7 -
 22 files changed, 408 insertions(+), 576 deletions(-)
 create mode 100644 README
 delete mode 100644 inc/unicore/Name.pm
 delete mode 100644 static/css/SpamFilter.css

- Log -----------------------------------------------------------------
commit 6d6a96152c801c2e454395e2a477095fddd20a5a
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Thu Dec 17 09:59:22 2020 -0500

    Convert button display to use bootstrap styles
    
    The custom styles are no longer needed after converting
    to bootstrap.

diff --git a/html/Tools/SpamFilter/Display.html b/html/Tools/SpamFilter/Display.html
index 8e9afc0..39ef770 100644
--- a/html/Tools/SpamFilter/Display.html
+++ b/html/Tools/SpamFilter/Display.html
@@ -48,12 +48,18 @@
 <& /Elements/Header, Title => loc('#[_1]: [_2]', $email->id, $email->GetHeader('Subject')) &>
 <& /Elements/Tabs &>
 
-<link rel="stylesheet" href="<%RT->Config->Get('WebPath')%>/static/css/SpamFilter.css" type="text/css" />
-<div class="actions">
-<button class="create_user"><&|/l&>Not Spam</&></button>
+<div class="container actions mt-3">
+  <div class="row">
+    <div class="col-12">
+      <div  class="text-center">
+        <button class="create_user"><&|/l&>Not Spam</&></button>
 % if ( $email->Status ne 'deleted' ) {
-<button class="discard"><&|/l&>Delete</&></button>
+          <button class="discard"><&|/l&>Delete</&></button>
 % }
+      </div>
+    </div>
+  </div>
+</div>
 
 <script type="text/javascript">
     jQuery( function() {
@@ -65,8 +71,6 @@
         });
     });
 </script>
-</div>
-
 
 <& /Elements/ListActions, Actions => \@results &>
 
diff --git a/static/css/SpamFilter.css b/static/css/SpamFilter.css
deleted file mode 100644
index ec7ed63..0000000
--- a/static/css/SpamFilter.css
+++ /dev/null
@@ -1,7 +0,0 @@
-div.actions {
-    text-align: center;
-}
-
-div.actions button a {
-    color: white;
-}

commit baffc9a275031cc4bf3562c50b2a86508310a872
Author: Dianne Skoll <dianne at bestpractical.com>
Date:   Wed Dec 16 09:43:06 2020 -0500

    Update POD to better describe configuration options and supported RT versions.a

diff --git a/lib/RT/Extension/SpamFilter.pm b/lib/RT/Extension/SpamFilter.pm
index 80a83d2..21df99f 100644
--- a/lib/RT/Extension/SpamFilter.pm
+++ b/lib/RT/Extension/SpamFilter.pm
@@ -48,7 +48,7 @@ Admins can manually handle those spams from /Tools/SpamFilter/List.html
 
 =head1 RT VERSION
 
-Works with RT 4.0 and later
+Works with RT 4.0, 4.2, 4.4 and 5.0.
 
 =head1 INSTALLATION
 
@@ -72,7 +72,20 @@ in your database.
 If you are upgrading this module, check for upgrading instructions
 in case changes need to be made to your database.
 
-=item Edit your F</opt/rt4/etc/RT_SiteConfig.pm>
+=item Set up spam filter rules (see L</"CONFIGURATION"> for details.)
+
+=item Clear your mason cache
+
+    rm -rf /opt/rt5/var/mason_data/obj
+
+=item Restart your webserver
+
+=back
+
+=head1 CONFIGURATION
+
+Edit your F</opt/rt5/etc/RT_SiteConfig.pm>; a sample configuration
+is shown below:
 
     Plugin('RT::Extension::SpamFilter');
     Set(@MailPlugins, 'SpamFilter', 'Auth::MailFrom');
@@ -91,15 +104,24 @@ in case changes need to be made to your database.
         }
     );
 
+The C<@SpamFilters> array is an array of hashes.  Each hash
+must contain the following keys:
 
-=item Clear your mason cache
+=over
 
-    rm -rf /opt/rt4/var/mason_data/obj
+=item C<Field> is either 'Body' or the name of an email header.
 
-=item Restart your webserver
+=item C<Regex> is a regular expression to apply to the email header named
+by C<Field> (or the email body if C<Field> is 'Body')
+
+=item C<Score> is a number indicating how many points to add to the
+spam score if the rule matches.
 
 =back
 
+The C<$SpamFilterThreshold> is the score above which an incoming message
+is considered to be spam and placed in the spam list.
+
 =head1 AUTHOR
 
 Best Practical Solutions, LLC E<lt>modules at bestpractical.comE<gt>

commit 8b9c1b223f6c4e7d81cbe047c97cdc88e1572a56
Author: Dianne Skoll <dianne at bestpractical.com>
Date:   Wed Dec 16 14:51:06 2020 -0500

    Update display page to fit better with RT5 look-and-feel; use Bootstrap flexboxes instead of tables.

diff --git a/html/Tools/SpamFilter/Display.html b/html/Tools/SpamFilter/Display.html
index 39ef770..2b1abab 100644
--- a/html/Tools/SpamFilter/Display.html
+++ b/html/Tools/SpamFilter/Display.html
@@ -79,9 +79,7 @@
 </&>
 
 <&| /Widgets/TitleBox, title => loc('Content'), &>
-<pre>
-<% $email->Content %>
-</pre>
+% $m->comp('/Elements/ShowMessageStanza', Message     => $email->Content, );
 </&>
 
 <%init>
diff --git a/html/Tools/SpamFilter/Elements/ShowBasics b/html/Tools/SpamFilter/Elements/ShowBasics
index 3c231ac..abbd72e 100644
--- a/html/Tools/SpamFilter/Elements/ShowBasics
+++ b/html/Tools/SpamFilter/Elements/ShowBasics
@@ -46,32 +46,32 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<table>
-  <tr class="id">
-    <td class="label"><&|/l&>id</&>:</td>
-    <td class="value"><%$Spam->id %></td>
-  </tr>
-  <tr class="status">
-    <td class="label"><&|/l&>Status</&>:</td>
-    <td class="value"><% loc($Spam->Status) %></td>
-  </tr>
-  <tr class="Subject">
-    <td class="label"><&|/l&>Subject</&>:</td>
-    <td class="value"><% $Spam->GetHeader('Subject') || loc("(No subject)") %></td>
-  </tr>
-  <tr class="from">
-    <td class="label"><&|/l&>From</&>:</td>
-    <td class="value"><% $Spam->From %></td>
-  </tr>
-  <tr class="to">
-    <td class="label"><&|/l&>To</&>:</td>
-    <td class="value"><% $Spam->GetHeader('To') %></td>
-  </tr>
-  <tr class="date">
-    <td class="label"><&|/l&>Date</&>:</td>
-    <td class="value"><% $Spam->GetHeader('Date') %></td>
-  </tr>
-</table>
+<div>
+  <div class="id form-row">
+    <div class="label col-1"><&|/l&>id</&>:</div>
+    <div class="value col-11"><%$Spam->id %></div>
+  </div>
+  <div class="status form-row">
+    <div class="label col-1"><&|/l&>Status</&>:</div>
+    <div class="value col-11"><% loc($Spam->Status) %></div>
+  </div>
+  <div class="Subject form-row"">
+    <div class="label col-1"><&|/l&>Subject</&>:</div>
+    <div class="value col-11"><% $Spam->GetHeader('Subject') || loc("(No subject)") %></div>
+  </div>
+  <div class="from form-row"">
+    <div class="label col-1"><&|/l&>From</&>:</div>
+    <div class="value col-11"><% $Spam->From %></div>
+  </div>
+  <div class="to form-row"">
+    <div class="label col-1"><&|/l&>To</&>:</div>
+    <div class="value col-11"><% $Spam->GetHeader('To') %></div>
+  </div>
+  <div class="date form-row"">
+    <div class="label col-1"><&|/l&>Date</&>:</div>
+    <div class="value col-11"><% $Spam->GetHeader('Date') %></div>
+  </div>
+</div>
 <%ARGS>
 $Spam => undef
 </%ARGS>

commit 67d74a136e755f40ff5860899333120ac2873d06
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Thu Dec 17 10:05:29 2020 -0500

    Center content in a smaller container

diff --git a/html/Tools/SpamFilter/Display.html b/html/Tools/SpamFilter/Display.html
index 2b1abab..06efcc7 100644
--- a/html/Tools/SpamFilter/Display.html
+++ b/html/Tools/SpamFilter/Display.html
@@ -73,7 +73,7 @@
 </script>
 
 <& /Elements/ListActions, Actions => \@results &>
-
+<div id="spam-display-container" class="mx-auto max-width-md">
 <&| /Widgets/TitleBox, title => loc('The Basics'), &>
 <& /Tools/SpamFilter/Elements/ShowBasics, Spam => $email &>
 </&>
@@ -81,7 +81,7 @@
 <&| /Widgets/TitleBox, title => loc('Content'), &>
 % $m->comp('/Elements/ShowMessageStanza', Message     => $email->Content, );
 </&>
-
+</div>
 <%init>
 
 Abort( loc("No spam specified") ) unless $ARGS{id};

commit f4d0194ff769d90b18811a9c0d7a3ca09af53def
Merge: 4b4e22e 67d74a1
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Thu Dec 17 10:06:32 2020 -0500

    Merge branch 'update-for-rt5'


commit 9f3801d8dff97bcff30ec71c360a67b8676ac3cd
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Thu Dec 17 10:25:16 2020 -0500

    Add spam header example

diff --git a/README b/README
new file mode 100644
index 0000000..931e206
--- /dev/null
+++ b/README
@@ -0,0 +1,104 @@
+NAME
+    RT-Extension-SpamFilter - Spam Filter
+
+DESCRIPTION
+    This is for public RT systems, where everyone can create tickets. Admins
+    can define a list of rules, and if an email comes from a non-existing
+    user and reached the score threshold(scored by the rules), it will be
+    marked as spam and no tickets will be created.
+
+    Admins can manually handle those spams from /Tools/SpamFilter/List.html
+
+RT VERSION
+    Works with RT 4.0, 4.2, 4.4 and 5.0.
+
+INSTALLATION
+    perl Makefile.PL
+    make
+    make install
+        May need root permissions
+
+    make initdb
+        Only run this the first time you install this module.
+
+        If you run this twice, you may end up with duplicate data in your
+        database.
+
+        If you are upgrading this module, check for upgrading instructions
+        in case changes need to be made to your database.
+
+    Set up spam filter rules (see "CONFIGURATION" for details.)
+    Clear your mason cache
+            rm -rf /opt/rt5/var/mason_data/obj
+
+    Restart your webserver
+
+CONFIGURATION
+    Edit your /opt/rt5/etc/RT_SiteConfig.pm; a sample configuration is shown
+    below:
+
+        Plugin('RT::Extension::SpamFilter');
+        Set(@MailPlugins, 'SpamFilter', 'Auth::MailFrom');
+        Set($SpamFilterThreshold, 30);
+        Set(
+            @SpamFilters,
+            {
+                Field => 'Subject',
+                Regex => qr/urgent reply/i,
+                Score => 20,
+            },
+            {
+                Field => 'X-Gm-Spam',
+                Regex => qr/1/,
+                Score => 30, # Trust spam header and flag as spam
+            },
+            {
+                Field => 'Body',
+                Regex => qr/download the attachment/i,
+                Score => 10
+            }
+        );
+
+  @SpamFilters
+    The @SpamFilters array is an array of hashes. Each hash must contain the
+    following keys:
+
+    Field
+        Either 'Body' or the name of an email header.
+
+    Regex
+        A regular expression to apply to the email header named by Field (or
+        the email body if Field is 'Body').
+
+    Score
+        A number indicating how many points to add to the spam score if the
+        rule matches.
+
+    You can use the configuration above to check for provided spam headers
+    as shown in the example above. However, any score provided as a value in
+    a header currently isn't used. The configuration will detect the
+    presence of the spam header and then add the score you configure.
+
+  $SpamFilterThreshold
+    The $SpamFilterThreshold is the score above which an incoming message is
+    considered to be spam and placed in the spam list.
+
+AUTHOR
+    Best Practical Solutions, LLC <modules at bestpractical.com>
+
+BUGS
+    All bugs should be reported via email to
+
+        L<bug-RT-Extension-SpamFilter at rt.cpan.org|mailto:bug-RT-Extension-SpamFilter at rt.cpan.org>
+
+    or via the web at
+
+        L<rt.cpan.org|http://rt.cpan.org/Public/Dist/Display.html?Name=RT-Extension-SpamFilter>.
+
+LICENSE AND COPYRIGHT
+    This software is Copyright (c) 2014 Best Practical Solutions, LLC.
+
+    This is free software, licensed under:
+
+      The GNU General Public License, Version 2, June 1991
+
diff --git a/lib/RT/Extension/SpamFilter.pm b/lib/RT/Extension/SpamFilter.pm
index 21df99f..8f10b3b 100644
--- a/lib/RT/Extension/SpamFilter.pm
+++ b/lib/RT/Extension/SpamFilter.pm
@@ -97,6 +97,11 @@ is shown below:
             Regex => qr/urgent reply/i,
             Score => 20,
         },
+        {
+            Field => 'X-Gm-Spam',
+            Regex => qr/1/,
+            Score => 30, # Trust spam header and flag as spam
+        },
         {
             Field => 'Body',
             Regex => qr/download the attachment/i,
@@ -104,21 +109,36 @@ is shown below:
         }
     );
 
+=head2 C<@SpamFilters>
+
 The C<@SpamFilters> array is an array of hashes.  Each hash
 must contain the following keys:
 
 =over
 
-=item C<Field> is either 'Body' or the name of an email header.
+=item C<Field>
+
+Either 'Body' or the name of an email header.
 
-=item C<Regex> is a regular expression to apply to the email header named
-by C<Field> (or the email body if C<Field> is 'Body')
+=item C<Regex>
 
-=item C<Score> is a number indicating how many points to add to the
+A regular expression to apply to the email header named
+by C<Field> (or the email body if C<Field> is 'Body').
+
+=item C<Score>
+
+A number indicating how many points to add to the
 spam score if the rule matches.
 
 =back
 
+You can use the configuration above to check for provided spam headers
+as shown in the example above. However, any score provided as a value in a
+header currently isn't used. The configuration will detect the
+presence of the spam header and then add the score you configure.
+
+=head2 C<$SpamFilterThreshold>
+
 The C<$SpamFilterThreshold> is the score above which an incoming message
 is considered to be spam and placed in the spam list.
 

commit faaac0871d702333e687fd80393a96e4d1f02793
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Thu Dec 17 10:36:27 2020 -0500

    Update Module::Install

diff --git a/inc/Module/Install.pm b/inc/Module/Install.pm
index 7680c84..7ba98c2 100644
--- a/inc/Module/Install.pm
+++ b/inc/Module/Install.pm
@@ -17,7 +17,7 @@ package Module::Install;
 #     3. The ./inc/ version of Module::Install loads
 # }
 
-use 5.005;
+use 5.006;
 use strict 'vars';
 use Cwd        ();
 use File::Find ();
@@ -31,7 +31,7 @@ BEGIN {
 	# This is not enforced yet, but will be some time in the next few
 	# releases once we can make sure it won't clash with custom
 	# Module::Install extensions.
-	$VERSION = '1.08';
+	$VERSION = '1.19';
 
 	# Storage for the pseudo-singleton
 	$MAIN    = undef;
@@ -156,10 +156,10 @@ END_DIE
 sub autoload {
 	my $self = shift;
 	my $who  = $self->_caller;
-	my $cwd  = Cwd::cwd();
+	my $cwd  = Cwd::getcwd();
 	my $sym  = "${who}::AUTOLOAD";
 	$sym->{$cwd} = sub {
-		my $pwd = Cwd::cwd();
+		my $pwd = Cwd::getcwd();
 		if ( my $code = $sym->{$pwd} ) {
 			# Delegate back to parent dirs
 			goto &$code unless $cwd eq $pwd;
@@ -239,11 +239,13 @@ sub new {
 
 	# ignore the prefix on extension modules built from top level.
 	my $base_path = Cwd::abs_path($FindBin::Bin);
-	unless ( Cwd::abs_path(Cwd::cwd()) eq $base_path ) {
+	unless ( Cwd::abs_path(Cwd::getcwd()) eq $base_path ) {
 		delete $args{prefix};
 	}
 	return $args{_self} if $args{_self};
 
+	$base_path = VMS::Filespec::unixify($base_path) if $^O eq 'VMS';
+
 	$args{dispatch} ||= 'Admin';
 	$args{prefix}   ||= 'inc';
 	$args{author}   ||= ($^O eq 'VMS' ? '_author' : '.author');
@@ -322,7 +324,7 @@ sub find_extensions {
 	my ($self, $path) = @_;
 
 	my @found;
-	File::Find::find( sub {
+	File::Find::find( {no_chdir => 1, wanted => sub {
 		my $file = $File::Find::name;
 		return unless $file =~ m!^\Q$path\E/(.+)\.pm\Z!is;
 		my $subpath = $1;
@@ -336,9 +338,9 @@ sub find_extensions {
 		# correctly.  Otherwise, root through the file to locate the case-preserved
 		# version of the package name.
 		if ( $subpath eq lc($subpath) || $subpath eq uc($subpath) ) {
-			my $content = Module::Install::_read($subpath . '.pm');
+			my $content = Module::Install::_read($File::Find::name);
 			my $in_pod  = 0;
-			foreach ( split //, $content ) {
+			foreach ( split /\n/, $content ) {
 				$in_pod = 1 if /^=\w/;
 				$in_pod = 0 if /^=cut/;
 				next if ($in_pod || /^=cut/);  # skip pod text
@@ -351,7 +353,7 @@ sub find_extensions {
 		}
 
 		push @found, [ $file, $pkg ];
-	}, $path ) if -d $path;
+	}}, $path ) if -d $path;
 
 	@found;
 }
@@ -373,24 +375,14 @@ sub _caller {
 	return $call;
 }
 
-# Done in evals to avoid confusing Perl::MinimumVersion
-eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@;
 sub _read {
 	local *FH;
 	open( FH, '<', $_[0] ) or die "open($_[0]): $!";
+	binmode FH;
 	my $string = do { local $/; <FH> };
 	close FH or die "close($_[0]): $!";
 	return $string;
 }
-END_NEW
-sub _read {
-	local *FH;
-	open( FH, "< $_[0]"  ) or die "open($_[0]): $!";
-	my $string = do { local $/; <FH> };
-	close FH or die "close($_[0]): $!";
-	return $string;
-}
-END_OLD
 
 sub _readperl {
 	my $string = Module::Install::_read($_[0]);
@@ -411,30 +403,19 @@ sub _readpod {
 	return $string;
 }
 
-# Done in evals to avoid confusing Perl::MinimumVersion
-eval( $] >= 5.006 ? <<'END_NEW' : <<'END_OLD' ); die $@ if $@;
 sub _write {
 	local *FH;
 	open( FH, '>', $_[0] ) or die "open($_[0]): $!";
+	binmode FH;
 	foreach ( 1 .. $#_ ) {
 		print FH $_[$_] or die "print($_[0]): $!";
 	}
 	close FH or die "close($_[0]): $!";
 }
-END_NEW
-sub _write {
-	local *FH;
-	open( FH, "> $_[0]"  ) or die "open($_[0]): $!";
-	foreach ( 1 .. $#_ ) {
-		print FH $_[$_] or die "print($_[0]): $!";
-	}
-	close FH or die "close($_[0]): $!";
-}
-END_OLD
 
 # _version is for processing module versions (eg, 1.03_05) not
 # Perl versions (eg, 5.8.1).
-sub _version ($) {
+sub _version {
 	my $s = shift || 0;
 	my $d =()= $s =~ /(\.)/g;
 	if ( $d >= 2 ) {
@@ -450,12 +431,12 @@ sub _version ($) {
 	return $l + 0;
 }
 
-sub _cmp ($$) {
+sub _cmp {
 	_version($_[1]) <=> _version($_[2]);
 }
 
 # Cloned from Params::Util::_CLASS
-sub _CLASS ($) {
+sub _CLASS {
 	(
 		defined $_[0]
 		and
diff --git a/inc/Module/Install/Base.pm b/inc/Module/Install/Base.pm
index 3e63345..9fa42c2 100644
--- a/inc/Module/Install/Base.pm
+++ b/inc/Module/Install/Base.pm
@@ -4,7 +4,7 @@ package Module::Install::Base;
 use strict 'vars';
 use vars qw{$VERSION};
 BEGIN {
-	$VERSION = '1.08';
+	$VERSION = '1.19';
 }
 
 # Suspend handler for "redefined" warnings
diff --git a/inc/Module/Install/Can.pm b/inc/Module/Install/Can.pm
index 93f248d..d65c753 100644
--- a/inc/Module/Install/Can.pm
+++ b/inc/Module/Install/Can.pm
@@ -8,7 +8,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '1.08';
+	$VERSION = '1.19';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
@@ -121,6 +121,15 @@ END_C
 # Can we locate a (the) C compiler
 sub can_cc {
 	my $self   = shift;
+
+	if ($^O eq 'VMS') {
+		require ExtUtils::CBuilder;
+		my $builder = ExtUtils::CBuilder->new(
+		quiet => 1,
+		);
+		return $builder->have_compiler;
+	}
+
 	my @chunks = split(/ /, $Config::Config{cc}) or return;
 
 	# $Config{cc} may contain args; try to find out the program part
@@ -151,4 +160,4 @@ if ( $^O eq 'cygwin' ) {
 
 __END__
 
-#line 236
+#line 245
diff --git a/inc/Module/Install/Fetch.pm b/inc/Module/Install/Fetch.pm
index ecc0d53..3072b08 100644
--- a/inc/Module/Install/Fetch.pm
+++ b/inc/Module/Install/Fetch.pm
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '1.08';
+	$VERSION = '1.19';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
diff --git a/inc/Module/Install/Include.pm b/inc/Module/Install/Include.pm
index fc86e23..13fdcd0 100644
--- a/inc/Module/Install/Include.pm
+++ b/inc/Module/Install/Include.pm
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '1.08';
+	$VERSION = '1.19';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
diff --git a/inc/Module/Install/Makefile.pm b/inc/Module/Install/Makefile.pm
index c0978a4..13a4464 100644
--- a/inc/Module/Install/Makefile.pm
+++ b/inc/Module/Install/Makefile.pm
@@ -8,7 +8,7 @@ use Fcntl qw/:flock :seek/;
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '1.08';
+	$VERSION = '1.19';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
@@ -133,7 +133,7 @@ sub makemaker_args {
 	return $args;
 }
 
-# For mm args that take multiple space-seperated args,
+# For mm args that take multiple space-separated args,
 # append an argument to the current list.
 sub makemaker_append {
 	my $self = shift;
diff --git a/inc/Module/Install/Metadata.pm b/inc/Module/Install/Metadata.pm
index e4112f8..11bf971 100644
--- a/inc/Module/Install/Metadata.pm
+++ b/inc/Module/Install/Metadata.pm
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '1.08';
+	$VERSION = '1.19';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
@@ -347,7 +347,7 @@ sub name_from {
 		^ \s*
 		package \s*
 		([\w:]+)
-		\s* ;
+		[\s|;]*
 		/ixms
 	) {
 		my ($name, $module_name) = ($1, $1);
@@ -705,7 +705,7 @@ sub _write_mymeta_data {
 	my @yaml = Parse::CPAN::Meta::LoadFile('META.yml');
 	my $meta = $yaml[0];
 
-	# Overwrite the non-configure dependency hashs
+	# Overwrite the non-configure dependency hashes
 	delete $meta->{requires};
 	delete $meta->{build_requires};
 	delete $meta->{recommends};
diff --git a/inc/Module/Install/RTx.pm b/inc/Module/Install/RTx.pm
index 31db76d..2dd9489 100644
--- a/inc/Module/Install/RTx.pm
+++ b/inc/Module/Install/RTx.pm
@@ -6,9 +6,10 @@ use strict;
 use warnings;
 no warnings 'once';
 
+use Term::ANSIColor qw(:constants);
 use Module::Install::Base;
 use base 'Module::Install::Base';
-our $VERSION = '0.34_04';
+our $VERSION = '0.42';
 
 use FindBin;
 use File::Glob     ();
@@ -18,7 +19,8 @@ my @DIRS = qw(etc lib html static bin sbin po var);
 my @INDEX_DIRS = qw(lib bin sbin);
 
 sub RTx {
-    my ( $self, $name ) = @_;
+    my ( $self, $name, $extra_args ) = @_;
+    $extra_args ||= {};
 
     # Set up names
     my $fname = $name;
@@ -30,25 +32,37 @@ sub RTx {
         unless $self->version;
     $self->abstract("$name Extension")
         unless $self->abstract;
-    $self->readme_from( "lib/$fname.pm",
-                        { options => [ quotes => "none" ] } );
+    unless ( $extra_args->{no_readme_generation} ) {
+        $self->readme_from( "lib/$fname.pm",
+                            { options => [ quotes => "none" ] } );
+    }
     $self->add_metadata("x_module_install_rtx_version", $VERSION );
 
+    my $installdirs = $ENV{INSTALLDIRS};
+    for ( @ARGV ) {
+        if ( /INSTALLDIRS=(.*)/ ) {
+            $installdirs = $1;
+        }
+    }
+
     # Try to find RT.pm
-    my @prefixes = qw( /opt /usr/local /home /usr /sw );
+    my @prefixes = qw( /opt /usr/local /home /usr /sw /usr/share/request-tracker4);
+    $ENV{RTHOME} =~ s{/RT\.pm$}{} if defined $ENV{RTHOME};
+    $ENV{RTHOME} =~ s{/lib/?$}{}  if defined $ENV{RTHOME};
     my @try = $ENV{RTHOME} ? ($ENV{RTHOME}, "$ENV{RTHOME}/lib") : ();
     while (1) {
         my @look = @INC;
         unshift @look, grep {defined and -d $_} @try;
         push @look, grep {defined and -d $_}
-            map { ( "$_/rt4/lib", "$_/lib/rt4", "$_/lib" ) } @prefixes;
+            map { ( "$_/rt5/lib", "$_/lib/rt5", "$_/rt4/lib", "$_/lib/rt4", "$_/lib" ) } @prefixes;
         last if eval {local @INC = @look; require RT; $RT::LocalLibPath};
 
         warn
             "Cannot find the location of RT.pm that defines \$RT::LocalPath in: @look\n";
-        $_ = $self->prompt("Path to directory containing your RT.pm:") or exit;
-        $_ =~ s{(/lib)?/RT\.pm$}{};
-        @try = ("$_/rt4/lib", "$_/lib/rt4", "$_/lib");
+        my $given = $self->prompt("Path to directory containing your RT.pm:") or exit;
+        $given =~ s{/RT\.pm$}{};
+        $given =~ s{/lib/?$}{};
+        @try = ($given, "$given/lib");
     }
 
     print "Using RT configuration from $INC{'RT.pm'}:\n";
@@ -59,11 +73,35 @@ sub RTx {
     unshift @INC, $lib_path;
 
     # Set a baseline minimum version
-    $self->requires_rt('4.0.0');
+    unless ( $extra_args->{deprecated_rt} ) {
+        $self->requires_rt('4.0.0');
+    }
+
+    my $package = $name;
+    $package =~ s/-/::/g;
+    if ( $RT::CORED_PLUGINS{$package} ) {
+        my ($base_version) = $RT::VERSION =~ /(\d+\.\d+\.\d+)/;
+        die RED, <<"EOT";
+
+**** Error: Your installed version of RT ($RT::VERSION) already
+            contains this extension in core, so you don't need to
+            install it.
+
+            Check https://docs.bestpractical.com/rt/$base_version/RT_Config.html
+            to configure it.
+
+EOT
+    }
 
     # Installation locations
     my %path;
-    $path{$_} = $RT::LocalPluginPath . "/$name/$_"
+    my $plugin_path;
+    if ( $installdirs && $installdirs eq 'vendor' ) {
+        $plugin_path = $RT::PluginPath;
+    } else {
+        $plugin_path = $RT::LocalPluginPath;
+    }
+    $path{$_} = $plugin_path . "/$name/$_"
         foreach @DIRS;
 
     # Copy RT 4.2.0 static files into NoAuth; insufficient for
@@ -77,7 +115,7 @@ sub RTx {
     my %index = map { $_ => 1 } @INDEX_DIRS;
     $self->no_index( directory => $_ ) foreach grep !$index{$_}, @DIRS;
 
-    my $args = join ', ', map "q($_)", map { ($_, $path{$_}) }
+    my $args = join ', ', map "q($_)", map { ($_, "\$(DESTDIR)$path{$_}") }
         sort keys %path;
 
     printf "%-10s => %s\n", $_, $path{$_} for sort keys %path;
@@ -92,11 +130,29 @@ lexicons ::
 .
     }
 
+    my $remove_files;
+    if( $extra_args->{'remove_files'} ){
+        $self->include('Module::Install::RTx::Remove');
+        our @remove_files;
+        eval { require "etc/upgrade/remove_files" }
+          or print "No remove file located, no files to remove\n";
+        $remove_files = join ",", map {"q(\$(DESTDIR)$plugin_path/$name/$_)"} @remove_files;
+    }
+
     $self->include('Module::Install::RTx::Runtime') if $self->admin;
     $self->include_deps( 'YAML::Tiny', 0 ) if $self->admin;
     my $postamble = << ".";
 install ::
 \t\$(NOECHO) \$(PERL) -Ilib -I"$local_lib_path" -I"$lib_path" -Iinc -MModule::Install::RTx::Runtime -e"RTxPlugin()"
+.
+
+    if( $remove_files ){
+        $postamble .= << ".";
+\t\$(NOECHO) \$(PERL) -MModule::Install::RTx::Remove -e \"RTxRemove([$remove_files])\"
+.
+    }
+
+    $postamble .= << ".";
 \t\$(NOECHO) \$(PERL) -MExtUtils::Install -e \"install({$args})\"
 .
 
@@ -123,6 +179,7 @@ install ::
     if ( $path{lib} ) {
         $self->makemaker_args( INSTALLSITELIB => $path{'lib'} );
         $self->makemaker_args( INSTALLARCHLIB => $path{'lib'} );
+        $self->makemaker_args( INSTALLVENDORLIB => $path{'lib'} )
     } else {
         $self->makemaker_args( PM => { "" => "" }, );
     }
@@ -131,6 +188,13 @@ install ::
     $self->makemaker_args( INSTALLSITEMAN3DIR => "$RT::LocalPath/man/man3" );
     $self->makemaker_args( INSTALLSITEARCH => "$RT::LocalPath/man" );
 
+    # INSTALLDIRS=vendor should install manpages into /usr/share/man.
+    # That is the default path in most distributions. Need input from
+    # Redhat, Centos etc.
+    $self->makemaker_args( INSTALLVENDORMAN1DIR => "/usr/share/man/man1" );
+    $self->makemaker_args( INSTALLVENDORMAN3DIR => "/usr/share/man/man3" );
+    $self->makemaker_args( INSTALLVENDORARCH => "/usr/share/man" );
+
     if (%has_etc) {
         print "For first-time installation, type 'make initdb'.\n";
         my $initdb = '';
@@ -176,7 +240,7 @@ sub requires_rt {
     my @sorted = sort RT::Handle::cmp_version $version,$RT::VERSION;
 
     if ($sorted[-1] eq $version) {
-        die <<"EOT";
+        die RED, <<"EOT";
 
 **** Error: This extension requires RT $version. Your installed version
             of RT ($RT::VERSION) is too old.
@@ -190,7 +254,7 @@ sub requires_rt_plugin {
     my ( $plugin ) = @_;
 
     if ($self->is_admin) {
-        my $plugins = $self->{values}{"x_requires_rt_plugins"} || [];
+        my $plugins = $self->Meta->{values}{"x_requires_rt_plugins"} || [];
         push @{$plugins}, $plugin;
         $self->add_metadata("x_requires_rt_plugins", $plugins);
     }
@@ -202,12 +266,12 @@ sub requires_rt_plugin {
         unshift @INC, $path;
     } else {
         my $name = $self->name;
-        warn <<"EOT";
+        my $msg = <<"EOT";
 
 **** Warning: $name requires that the $plugin plugin be installed and
               enabled; it does not appear to be installed.
-
 EOT
+        warn RED, $msg, RESET, "\n";
     }
     $self->requires(@_);
 }
@@ -217,9 +281,8 @@ sub rt_too_new {
     my $name = $self->name;
     $msg ||= <<EOT;
 
-**** Error: Your installed version of RT (%s) is too new; this extension
-            only works with versions older than %s.
-
+**** Warning: Your installed version of RT (%s) is too new; this extension
+              has not been tested on your version of RT and may not work as expected.
 EOT
     $self->add_metadata("x_rt_too_new", $version) if $self->is_admin;
 
@@ -227,7 +290,7 @@ EOT
     my @sorted = sort RT::Handle::cmp_version $version,$RT::VERSION;
 
     if ($sorted[0] eq $version) {
-        die sprintf($msg,$RT::VERSION,$version);
+        warn RED, sprintf($msg,$RT::VERSION), RESET, "\n";
     }
 }
 
@@ -250,4 +313,4 @@ sub _load_rt_handle {
 
 __END__
 
-#line 369
+#line 484
diff --git a/inc/Module/Install/RTx/Runtime.pm b/inc/Module/Install/RTx/Runtime.pm
index 937949f..ae07502 100644
--- a/inc/Module/Install/RTx/Runtime.pm
+++ b/inc/Module/Install/RTx/Runtime.pm
@@ -33,6 +33,7 @@ sub RTxDatabase {
 
     my $lib_path = File::Basename::dirname($INC{'RT.pm'});
     my @args = (
+        "-I.",
         "-Ilib",
         "-I$RT::LocalLibPath",
         "-I$lib_path",
diff --git a/inc/Module/Install/ReadmeFromPod.pm b/inc/Module/Install/ReadmeFromPod.pm
index b5e03c3..3738232 100644
--- a/inc/Module/Install/ReadmeFromPod.pm
+++ b/inc/Module/Install/ReadmeFromPod.pm
@@ -7,12 +7,41 @@ use warnings;
 use base qw(Module::Install::Base);
 use vars qw($VERSION);
 
-$VERSION = '0.22';
+$VERSION = '0.30';
+
+{
+
+    # these aren't defined until after _require_admin is run, so
+    # define them so prototypes are available during compilation.
+    sub io;
+    sub capture(&;@);
+
+#line 28
+
+    my $done = 0;
+
+    sub _require_admin {
+
+	# do this once to avoid redefinition warnings from IO::All
+	return if $done;
+
+	require IO::All;
+	IO::All->import( '-binary' );
+
+	require Capture::Tiny;
+	Capture::Tiny->import ( 'capture' );
+
+	return;
+    }
+
+}
 
 sub readme_from {
   my $self = shift;
   return unless $self->is_admin;
 
+  _require_admin;
+
   # Input file
   my $in_file  = shift || $self->_all_from
     or die "Can't determine file to make readme_from";
@@ -50,6 +79,8 @@ sub readme_from {
     $out_file = $self->_readme_htm($in_file, $out_file, $options);
   } elsif ($format eq 'man') {
     $out_file = $self->_readme_man($in_file, $out_file, $options);
+  } elsif ($format eq 'md') {
+    $out_file = $self->_readme_md($in_file, $out_file, $options);
   } elsif ($format eq 'pdf') {
     $out_file = $self->_readme_pdf($in_file, $out_file, $options);
   }
@@ -67,10 +98,10 @@ sub _readme_txt {
   $out_file ||= 'README';
   require Pod::Text;
   my $parser = Pod::Text->new( @$options );
-  open my $out_fh, '>', $out_file or die "Could not write file $out_file:\n$!\n";
+  my $io = io->file($out_file)->open(">");
+  my $out_fh = $io->io_handle;
   $parser->output_fh( *$out_fh );
   $parser->parse_file( $in_file );
-  close $out_fh;
   return $out_file;
 }
 
@@ -79,11 +110,14 @@ sub _readme_htm {
   my ($self, $in_file, $out_file, $options) = @_;
   $out_file ||= 'README.htm';
   require Pod::Html;
-  Pod::Html::pod2html(
-    "--infile=$in_file",
-    "--outfile=$out_file",
-    @$options,
-  );
+  my ($o) = capture {
+    Pod::Html::pod2html(
+      "--infile=$in_file",
+      "--outfile=-",
+      @$options,
+    );
+  };
+  io->file($out_file)->print($o);
   # Remove temporary files if needed
   for my $file ('pod2htmd.tmp', 'pod2htmi.tmp') {
     if (-e $file) {
@@ -99,7 +133,10 @@ sub _readme_man {
   $out_file ||= 'README.1';
   require Pod::Man;
   my $parser = Pod::Man->new( @$options );
-  $parser->parse_from_file($in_file, $out_file);
+  my $io = io->file($out_file)->open(">");
+  my $out_fh = $io->io_handle;
+  $parser->output_fh( *$out_fh );
+  $parser->parse_file( $in_file );
   return $out_file;
 }
 
@@ -111,11 +148,20 @@ sub _readme_pdf {
     or die "Could not generate $out_file because pod2pdf could not be found\n";
   my $parser = App::pod2pdf->new( @$options );
   $parser->parse_from_file($in_file);
-  open my $out_fh, '>', $out_file or die "Could not write file $out_file:\n$!\n";
-  select $out_fh;
-  $parser->output;
-  select STDOUT;
-  close $out_fh;
+  my ($o) = capture { $parser->output };
+  io->file($out_file)->print($o);
+  return $out_file;
+}
+
+sub _readme_md {
+  my ($self, $in_file, $out_file, $options) = @_;
+  $out_file ||= 'README.md';
+  require Pod::Markdown;
+  my $parser = Pod::Markdown->new( @$options );
+  my $io = io->file($out_file)->open(">");
+  my $out_fh = $io->io_handle;
+  $parser->output_fh( *$out_fh );
+  $parser->parse_file( $in_file );
   return $out_file;
 }
 
@@ -134,5 +180,5 @@ sub _all_from {
 
 __END__
 
-#line 254
+#line 316
 
diff --git a/inc/Module/Install/Win32.pm b/inc/Module/Install/Win32.pm
index e529382..f7aa615 100644
--- a/inc/Module/Install/Win32.pm
+++ b/inc/Module/Install/Win32.pm
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '1.08';
+	$VERSION = '1.19';
 	@ISA     = 'Module::Install::Base';
 	$ISCORE  = 1;
 }
diff --git a/inc/Module/Install/WriteAll.pm b/inc/Module/Install/WriteAll.pm
index 2c74308..2db861a 100644
--- a/inc/Module/Install/WriteAll.pm
+++ b/inc/Module/Install/WriteAll.pm
@@ -6,7 +6,7 @@ use Module::Install::Base ();
 
 use vars qw{$VERSION @ISA $ISCORE};
 BEGIN {
-	$VERSION = '1.08';
+	$VERSION = '1.19';
 	@ISA     = qw{Module::Install::Base};
 	$ISCORE  = 1;
 }
diff --git a/inc/YAML/Tiny.pm b/inc/YAML/Tiny.pm
index 1be0cb1..fb157a6 100644
--- a/inc/YAML/Tiny.pm
+++ b/inc/YAML/Tiny.pm
@@ -2,16 +2,12 @@
 use 5.008001; # sane UTF-8 support
 use strict;
 use warnings;
-package YAML::Tiny;
-BEGIN {
-  $YAML::Tiny::AUTHORITY = 'cpan:ADAMK';
-}
-# git description: v1.61-3-g0a82466
-$YAML::Tiny::VERSION = '1.62';
+package YAML::Tiny; # git description: v1.72-7-g8682f63
 # XXX-INGY is 5.8.1 too old/broken for utf8?
 # XXX-XDG Lancaster consensus was that it was sufficient until
 # proven otherwise
 
+our $VERSION = '1.73';
 
 #####################################################################
 # The YAML::Tiny API.
@@ -300,10 +296,11 @@ Did you decode with lax ":utf8" instead of strict ":encoding(UTF-8)"?
             }
         }
     };
-    if ( ref $@ eq 'SCALAR' ) {
-        $self->_error(${$@});
-    } elsif ( $@ ) {
-        $self->_error($@);
+    my $err = $@;
+    if ( ref $err eq 'SCALAR' ) {
+        $self->_error(${$err});
+    } elsif ( $err ) {
+        $self->_error($err);
     }
 
     return $self;
@@ -377,7 +374,7 @@ sub _load_scalar {
     while ( @$lines ) {
         $lines->[0] =~ /^(\s*)/;
         last unless length($1) >= $indent->[-1];
-        push @multiline, substr(shift(@$lines), length($1));
+        push @multiline, substr(shift(@$lines), $indent->[-1]);
     }
 
     my $j = (substr($string, 0, 1) eq '>') ? ' ' : "\n";
@@ -515,6 +512,10 @@ sub _load_hash {
             die \"YAML::Tiny failed to classify line '$lines->[0]'";
         }
 
+        if ( exists $hash->{$key} ) {
+            warn "YAML::Tiny found a duplicate key '$key' in line '$lines->[0]'";
+        }
+
         # Do we have a value?
         if ( length $lines->[0] ) {
             # Yes
@@ -569,10 +570,8 @@ sub _dump_file {
     if ( _can_flock() ) {
         # Open without truncation (truncate comes after lock)
         my $flags = Fcntl::O_WRONLY()|Fcntl::O_CREAT();
-        sysopen( $fh, $file, $flags );
-        unless ( $fh ) {
-            $self->_error("Failed to open file '$file' for writing: $!");
-        }
+        sysopen( $fh, $file, $flags )
+            or $self->_error("Failed to open file '$file' for writing: $!");
 
         # Use no translation and strict UTF-8
         binmode( $fh, ":raw:encoding(UTF-8)");
@@ -828,9 +827,10 @@ sub _can_flock {
 #####################################################################
 # Use Scalar::Util if possible, otherwise emulate it
 
+use Scalar::Util ();
 BEGIN {
     local $@;
-    if ( eval { require Scalar::Util; Scalar::Util->VERSION(1.18); } ) {
+    if ( eval { Scalar::Util->VERSION(1.18); } ) {
         *refaddr = *Scalar::Util::refaddr;
     }
     else {
@@ -852,8 +852,7 @@ END_PERL
     }
 }
 
-
-
+delete $YAML::Tiny::{refaddr};
 
 1;
 
@@ -870,4 +869,4 @@ END_PERL
 
 __END__
 
-#line 1488
+#line 1487
diff --git a/inc/unicore/Name.pm b/inc/unicore/Name.pm
deleted file mode 100644
index d72eb6e..0000000
--- a/inc/unicore/Name.pm
+++ /dev/null
@@ -1,417 +0,0 @@
-#line 1
-# !!!!!!!   DO NOT EDIT THIS FILE   !!!!!!!
-# This file is machine-generated by lib/unicore/mktables from the Unicode
-# database, Version 6.3.0.  Any changes made here will be lost!
-
-
-# !!!!!!!   INTERNAL PERL USE ONLY   !!!!!!!
-# This file is for internal use by core Perl only.  The format and even the
-# name or existence of this file are subject to change without notice.  Don't
-# use it directly.  Use Unicode::UCD to access the Unicode character data
-# base.
-
-
-package charnames;
-
-# This module contains machine-generated tables and code for the
-# algorithmically-determinable Unicode character names.  The following
-# routines can be used to translate between name and code point and vice versa
-
-{ # Closure
-
-    # Matches legal code point.  4-6 hex numbers, If there are 6, the first
-    # two must be 10; if there are 5, the first must not be a 0.  Written this
-    # way to decrease backtracking.  The first regex allows the code point to
-    # be at the end of a word, but to work properly, the word shouldn't end
-    # with a valid hex character.  The second one won't match a code point at
-    # the end of a word, and doesn't have the run-on issue
-    my $run_on_code_point_re = qr/(?^aax: (?: 10[0-9A-F]{4} | [1-9A-F][0-9A-F]{4} | [0-9A-F]{4} ) \b)/;
-    my $code_point_re = qr/(?^aa:\b(?^aax: (?: 10[0-9A-F]{4} | [1-9A-F][0-9A-F]{4} | [0-9A-F]{4} ) \b))/;
-
-    # In the following hash, the keys are the bases of names which include
-    # the code point in the name, like CJK UNIFIED IDEOGRAPH-4E01.  The value
-    # of each key is another hash which is used to get the low and high ends
-    # for each range of code points that apply to the name.
-    my %names_ending_in_code_point = (
-'CJK COMPATIBILITY IDEOGRAPH' => 
-{
-'high' => 
-[
-64109,
-64217,
-195101,
-],
-'low' => 
-[
-63744,
-64112,
-194560,
-],
-},
-'CJK UNIFIED IDEOGRAPH' => 
-{
-'high' => 
-[
-19893,
-40908,
-173782,
-177972,
-178205,
-],
-'low' => 
-[
-13312,
-19968,
-131072,
-173824,
-177984,
-],
-},
-
-    );
-
-    # The following hash is a copy of the previous one, except is for loose
-    # matching, so each name has blanks and dashes squeezed out
-    my %loose_names_ending_in_code_point = (
-'CJKCOMPATIBILITYIDEOGRAPH' => 
-{
-'high' => 
-[
-64109,
-64217,
-195101,
-],
-'low' => 
-[
-63744,
-64112,
-194560,
-],
-},
-'CJKUNIFIEDIDEOGRAPH' => 
-{
-'high' => 
-[
-19893,
-40908,
-173782,
-177972,
-178205,
-],
-'low' => 
-[
-13312,
-19968,
-131072,
-173824,
-177984,
-],
-},
-
-    );
-
-    # And the following array gives the inverse mapping from code points to
-    # names.  Lowest code points are first
-    my @code_points_ending_in_code_point = (
-
-{
-'high' => 19893,
-'low' => 13312,
-'name' => 'CJK UNIFIED IDEOGRAPH',
-},
-{
-'high' => 40908,
-'low' => 19968,
-'name' => 'CJK UNIFIED IDEOGRAPH',
-},
-{
-'high' => 64109,
-'low' => 63744,
-'name' => 'CJK COMPATIBILITY IDEOGRAPH',
-},
-{
-'high' => 64217,
-'low' => 64112,
-'name' => 'CJK COMPATIBILITY IDEOGRAPH',
-},
-{
-'high' => 173782,
-'low' => 131072,
-'name' => 'CJK UNIFIED IDEOGRAPH',
-},
-{
-'high' => 177972,
-'low' => 173824,
-'name' => 'CJK UNIFIED IDEOGRAPH',
-},
-{
-'high' => 178205,
-'low' => 177984,
-'name' => 'CJK UNIFIED IDEOGRAPH',
-},
-{
-'high' => 195101,
-'low' => 194560,
-'name' => 'CJK COMPATIBILITY IDEOGRAPH',
-},
-,
-
-    );
-
-    # Convert from code point to Jamo short name for use in composing Hangul
-    # syllable names
-    my %Jamo = (
-4352 => 'G',
-4353 => 'GG',
-4354 => 'N',
-4355 => 'D',
-4356 => 'DD',
-4357 => 'R',
-4358 => 'M',
-4359 => 'B',
-4360 => 'BB',
-4361 => 'S',
-4362 => 'SS',
-4363 => '',
-4364 => 'J',
-4365 => 'JJ',
-4366 => 'C',
-4367 => 'K',
-4368 => 'T',
-4369 => 'P',
-4370 => 'H',
-4449 => 'A',
-4450 => 'AE',
-4451 => 'YA',
-4452 => 'YAE',
-4453 => 'EO',
-4454 => 'E',
-4455 => 'YEO',
-4456 => 'YE',
-4457 => 'O',
-4458 => 'WA',
-4459 => 'WAE',
-4460 => 'OE',
-4461 => 'YO',
-4462 => 'U',
-4463 => 'WEO',
-4464 => 'WE',
-4465 => 'WI',
-4466 => 'YU',
-4467 => 'EU',
-4468 => 'YI',
-4469 => 'I',
-4520 => 'G',
-4521 => 'GG',
-4522 => 'GS',
-4523 => 'N',
-4524 => 'NJ',
-4525 => 'NH',
-4526 => 'D',
-4527 => 'L',
-4528 => 'LG',
-4529 => 'LM',
-4530 => 'LB',
-4531 => 'LS',
-4532 => 'LT',
-4533 => 'LP',
-4534 => 'LH',
-4535 => 'M',
-4536 => 'B',
-4537 => 'BS',
-4538 => 'S',
-4539 => 'SS',
-4540 => 'NG',
-4541 => 'J',
-4542 => 'C',
-4543 => 'K',
-4544 => 'T',
-4545 => 'P',
-4546 => 'H',
-
-    );
-
-    # Leading consonant (can be null)
-    my %Jamo_L = (
-'' => 11,
-'B' => 7,
-'BB' => 8,
-'C' => 14,
-'D' => 3,
-'DD' => 4,
-'G' => 0,
-'GG' => 1,
-'H' => 18,
-'J' => 12,
-'JJ' => 13,
-'K' => 15,
-'M' => 6,
-'N' => 2,
-'P' => 17,
-'R' => 5,
-'S' => 9,
-'SS' => 10,
-'T' => 16,
-
-    );
-
-    # Vowel
-    my %Jamo_V = (
-'A' => 0,
-'AE' => 1,
-'E' => 5,
-'EO' => 4,
-'EU' => 18,
-'I' => 20,
-'O' => 8,
-'OE' => 11,
-'U' => 13,
-'WA' => 9,
-'WAE' => 10,
-'WE' => 15,
-'WEO' => 14,
-'WI' => 16,
-'YA' => 2,
-'YAE' => 3,
-'YE' => 7,
-'YEO' => 6,
-'YI' => 19,
-'YO' => 12,
-'YU' => 17,
-
-    );
-
-    # Optional trailing consonant
-    my %Jamo_T = (
-'B' => 17,
-'BS' => 18,
-'C' => 23,
-'D' => 7,
-'G' => 1,
-'GG' => 2,
-'GS' => 3,
-'H' => 27,
-'J' => 22,
-'K' => 24,
-'L' => 8,
-'LB' => 11,
-'LG' => 9,
-'LH' => 15,
-'LM' => 10,
-'LP' => 14,
-'LS' => 12,
-'LT' => 13,
-'M' => 16,
-'N' => 4,
-'NG' => 21,
-'NH' => 6,
-'NJ' => 5,
-'P' => 26,
-'S' => 19,
-'SS' => 20,
-'T' => 25,
-
-    );
-
-    # Computed re that splits up a Hangul name into LVT or LV syllables
-    my $syllable_re = qr/(|B|BB|C|D|DD|G|GG|H|J|JJ|K|M|N|P|R|S|SS|T)(A|AE|E|EO|EU|I|O|OE|U|WA|WAE|WE|WEO|WI|YA|YAE|YE|YEO|YI|YO|YU)(B|BS|C|D|G|GG|GS|H|J|K|L|LB|LG|LH|LM|LP|LS|LT|M|N|NG|NH|NJ|P|S|SS|T)?/;
-
-    my $HANGUL_SYLLABLE = "HANGUL SYLLABLE ";
-    my $loose_HANGUL_SYLLABLE = "HANGULSYLLABLE";
-
-    # These constants names and values were taken from the Unicode standard,
-    # version 5.1, section 3.12.  They are used in conjunction with Hangul
-    # syllables
-    my $SBase = 0xAC00;
-    my $LBase = 0x1100;
-    my $VBase = 0x1161;
-    my $TBase = 0x11A7;
-    my $SCount = 11172;
-    my $LCount = 19;
-    my $VCount = 21;
-    my $TCount = 28;
-    my $NCount = $VCount * $TCount;
-
-    sub name_to_code_point_special {
-        my ($name, $loose) = @_;
-
-        # Returns undef if not one of the specially handled names; otherwise
-        # returns the code point equivalent to the input name
-        # $loose is non-zero if to use loose matching, 'name' in that case
-        # must be input as upper case with all blanks and dashes squeezed out.
-
-        if ((! $loose && $name =~ s/$HANGUL_SYLLABLE//)
-            || ($loose && $name =~ s/$loose_HANGUL_SYLLABLE//))
-        {
-            return if $name !~ qr/^$syllable_re$/;
-            my $L = $Jamo_L{$1};
-            my $V = $Jamo_V{$2};
-            my $T = (defined $3) ? $Jamo_T{$3} : 0;
-            return ($L * $VCount + $V) * $TCount + $T + $SBase;
-        }
-
-        # Name must end in 'code_point' for this to handle.
-        return if (($loose && $name !~ /^ (.*?) ($run_on_code_point_re) $/x)
-                   || (! $loose && $name !~ /^ (.*) ($code_point_re) $/x));
-
-        my $base = $1;
-        my $code_point = CORE::hex $2;
-        my $names_ref;
-
-        if ($loose) {
-            $names_ref = \%loose_names_ending_in_code_point;
-        }
-        else {
-            return if $base !~ s/-$//;
-            $names_ref = \%names_ending_in_code_point;
-        }
-
-        # Name must be one of the ones which has the code point in it.
-        return if ! $names_ref->{$base};
-
-        # Look through the list of ranges that apply to this name to see if
-        # the code point is in one of them.
-        for (my $i = 0; $i < scalar @{$names_ref->{$base}{'low'}}; $i++) {
-            return if $names_ref->{$base}{'low'}->[$i] > $code_point;
-            next if $names_ref->{$base}{'high'}->[$i] < $code_point;
-
-            # Here, the code point is in the range.
-            return $code_point;
-        }
-
-        # Here, looked like the name had a code point number in it, but
-        # did not match one of the valid ones.
-        return;
-    }
-
-    sub code_point_to_name_special {
-        my $code_point = shift;
-
-        # Returns the name of a code point if algorithmically determinable;
-        # undef if not
-
-        # If in the Hangul range, calculate the name based on Unicode's
-        # algorithm
-        if ($code_point >= $SBase && $code_point <= $SBase + $SCount -1) {
-            use integer;
-            my $SIndex = $code_point - $SBase;
-            my $L = $LBase + $SIndex / $NCount;
-            my $V = $VBase + ($SIndex % $NCount) / $TCount;
-            my $T = $TBase + $SIndex % $TCount;
-            $name = "$HANGUL_SYLLABLE$Jamo{$L}$Jamo{$V}";
-            $name .= $Jamo{$T} if $T != $TBase;
-            return $name;
-        }
-
-        # Look through list of these code points for one in range.
-        foreach my $hash (@code_points_ending_in_code_point) {
-            return if $code_point < $hash->{'low'};
-            if ($code_point <= $hash->{'high'}) {
-                return sprintf("%s-%04X", $hash->{'name'}, $code_point);
-            }
-        }
-        return;            # None found
-    }
-} # End closure
-
-1;

commit d36bb4c9cb51eb0e9d2ce820565846d37af0b1bd
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Thu Dec 17 10:36:45 2020 -0500

    Version 0.02

diff --git a/Changes b/Changes
index ba4d89d..e79fa54 100644
--- a/Changes
+++ b/Changes
@@ -1,4 +1,8 @@
 Revision history for RT-Extension-SpamFilter
 
-0.01 [Release Date]
+0.02 2020-12-17
+ - Updates for RT 5
+ - Improve documentation
+
+0.01 2015-11-03
  - Initial version
diff --git a/META.yml b/META.yml
index 49794b7..7a1f56f 100644
--- a/META.yml
+++ b/META.yml
@@ -1,14 +1,14 @@
 ---
-abstract: 'RT Extension-SpamFilter Extension'
+abstract: 'RT-Extension-SpamFilter Extension'
 author:
   - 'Best Practical Solutions, LLC <modules at bestpractical.com>'
 build_requires:
-  ExtUtils::MakeMaker: 6.36
+  ExtUtils::MakeMaker: 6.59
 configure_requires:
-  ExtUtils::MakeMaker: 6.36
+  ExtUtils::MakeMaker: 6.59
 distribution_type: module
 dynamic_config: 1
-generated_by: 'Module::Install version 1.08'
+generated_by: 'Module::Install version 1.19'
 license: gplv2
 meta-spec:
   url: http://module-build.sourceforge.net/META-spec-v1.4.html
@@ -19,7 +19,12 @@ no_index:
     - etc
     - html
     - inc
+requires:
+  perl: 5.8.3
 resources:
   license: http://opensource.org/licenses/gpl-license.php
   repository: https://github.com/bestpractical/rt-extension-spamfilter
-version: '0.01'
+version: '0.02'
+x_module_install_rtx_version: '0.42'
+x_requires_rt: 4.0.0
+x_rt_too_new: 5.2.0
diff --git a/lib/RT/Extension/SpamFilter.pm b/lib/RT/Extension/SpamFilter.pm
index 8f10b3b..f90af15 100644
--- a/lib/RT/Extension/SpamFilter.pm
+++ b/lib/RT/Extension/SpamFilter.pm
@@ -3,7 +3,7 @@ use warnings;
 
 package RT::Extension::SpamFilter;
 
-our $VERSION = '0.01';
+our $VERSION = '0.02';
 
 sub MessageScore {
     my $class = shift;

-----------------------------------------------------------------------


More information about the Bps-public-commit mailing list