1# BEGIN BPS TAGGED BLOCK {{{
2#
3# COPYRIGHT:
4#
5# This software is Copyright (c) 1996-2021 Best Practical Solutions, LLC
6#                                          <sales@bestpractical.com>
7#
8# (Except where explicitly superseded by other copyright notices)
9#
10#
11# LICENSE:
12#
13# This work is made available to you under the terms of Version 2 of
14# the GNU General Public License. A copy of that license should have
15# been provided with this software, but in any event can be snarfed
16# from www.gnu.org.
17#
18# This work is distributed in the hope that it will be useful, but
19# WITHOUT ANY WARRANTY; without even the implied warranty of
20# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21# General Public License for more details.
22#
23# You should have received a copy of the GNU General Public License
24# along with this program; if not, write to the Free Software
25# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26# 02110-1301 or visit their web page on the internet at
27# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
28#
29#
30# CONTRIBUTION SUBMISSION POLICY:
31#
32# (The following paragraph is not intended to limit the rights granted
33# to you to modify and distribute this software under the terms of
34# the GNU General Public License and is only of importance to you if
35# you choose to contribute your changes and enhancements to the
36# community by submitting them to Best Practical Solutions, LLC.)
37#
38# By intentionally submitting any modifications, corrections or
39# derivatives to this work, or any other work intended for use with
40# Request Tracker, to Best Practical Solutions, LLC, you confirm that
41# you are the copyright holder for those contributions and you grant
42# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
43# royalty-free, perpetual, license to use, copy, create derivative
44# works based on those contributions, and sublicense and distribute
45# those contributions and any derivatives thereof.
46#
47# END BPS TAGGED BLOCK }}}
48
49package RT::Shredder::Plugin::Attachments;
50
51use strict;
52use warnings FATAL => 'all';
53use base qw(RT::Shredder::Plugin::Base::Search);
54
55=head1 NAME
56
57RT::Shredder::Plugin::Attachments - search plugin for wiping attachments.
58
59=head1 ARGUMENTS
60
61=head2 files_only - boolean value
62
63Search only file attachments.
64
65=head2 file - mask
66
67Search files with specific file name only.
68
69Example: '*.xl?' or '*.gif'
70
71=head2 longer - attachment content size
72
73Search attachments which content is longer than specified.
74You can use trailing 'K' or 'M' character to specify size in
75kilobytes or megabytes.
76
77=cut
78
79sub SupportArgs { return $_[0]->SUPER::SupportArgs, qw(files_only file longer) }
80
81sub TestArgs
82{
83    my $self = shift;
84    my %args = @_;
85    my $queue;
86    if( $args{'file'} ) {
87        unless( $args{'file'} =~ /^[\w\. *?]+$/) {
88            return( 0, "Files mask '$args{file}' has invalid characters" );
89        }
90        $args{'file'} = $self->ConvertMaskToSQL( $args{'file'} );
91    }
92    if( $args{'longer'} ) {
93        unless( $args{'longer'} =~ /^\d+\s*[mk]?$/i ) {
94            return( 0, "Invalid file size argument '$args{longer}'" );
95        }
96    }
97    return $self->SUPER::TestArgs( %args );
98}
99
100sub Run
101{
102    my $self = shift;
103    my @conditions = ();
104    my @values = ();
105    if( $self->{'opt'}{'file'} ) {
106        my $mask = $self->{'opt'}{'file'};
107        push @conditions, "( Filename LIKE ? )";
108        push @values, $mask;
109    }
110    if( $self->{'opt'}{'files_only'} ) {
111        push @conditions, "( LENGTH(Filename) > 0 )";
112    }
113    if( $self->{'opt'}{'longer'} ) {
114        my $size = $self->{'opt'}{'longer'};
115        $size =~ s/([mk])//i;
116        $size *= 1024 if $1 && lc $1 eq 'k';
117        $size *= 1024*1024 if $1 && lc $1 eq 'm';
118        push @conditions, "( LENGTH(Content) > ? )";
119        push @values, $size;
120    }
121    return (0, "At least one condition should be provided" ) unless @conditions;
122    my $query = "SELECT id FROM Attachments WHERE ". join ' AND ', @conditions;
123    if( $self->{'opt'}{'limit'} ) {
124        $RT::Handle->ApplyLimits( \$query, $self->{'opt'}{'limit'} );
125    }
126    my $sth = $RT::Handle->SimpleQuery( $query, @values );
127    return (0, "Internal error: '$sth'. Please send bug report.") unless $sth;
128
129    my @objs;
130    while( my $row = $sth->fetchrow_arrayref ) {
131        push @objs, $row->[0];
132    }
133    return (0, "Internal error: '". $sth->err ."'. Please send bug report.") if $sth->err;
134
135    @objs = map {"RT::Attachment-$_"} @objs;
136
137    return (1, @objs);
138}
139
1401;
141
142