# duck - check for DEP-3 patch files
# Copyright (C) 2016 Simon Kainz <skainz@debian.org>
# Copyright (C) 2022 Baptiste Beauplat <lyknode@cilg.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# he Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# On Debian GNU/Linux systems, the complete text of the GNU General
# Public License can be found in `/usr/share/common-licenses/GPL-2'.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, you can find it on the World Wide
# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
# MA 02110-1301, USA.

package DUCK::patch_files;

use strict;
use warnings;
use autodie;
use Data::Dumper;
use Parse::DebControl qw(parse_file);
use Regexp::Common qw /URI Email::Address/;
use Mail::Address;
use Path::Class;
use File::Basename;
use DUCK;

my @patchdirs;
my @patchfiles;
my @extract_patch = (
    "Origin",
    "Bug",
    "Forwarded",
    "Applied-Upstream",
    "Author",
    "From",
    "Reviewed-by",
    "Acked-by"
);
my %options = (
    "P" => "  -P\t\tskip processing of patch files"
);

sub opts() {
    return keys %options;
}

sub desc() {
    my $r;

    foreach (sort keys %options) {
        $r .= $options{$_} . "\n";
    }

    return $r;
}

sub run() {
    my ($sname, $params, $entries_ref) = @_;
    my %opt = %$params;
    my $extract_patch_hash;

    foreach my $a (@extract_patch) {
        $extract_patch_hash->{$a} = 1;
    }

    if (!$opt{P}) {
        ########## processing patch files
        # get list of dirs which contain a series file
        dir('.')->recurse(
            callback => sub {
                my $file = shift;

                if ($file =~ /\/series$/) {
                    my $dirname = dirname($file);

                    # print "found series: $file in $dirname\n";
                    push @patchdirs, $dirname;
                }
            }
        );

        # iterate over all patchdirs, process all files found
        foreach my $patchdir (@patchdirs) {
            my $dirhandle = dir($patchdir)->open;

            while (my $patchfile = $dirhandle->read) {
                open my $pf, "<", $patchdir . "/" . $patchfile;

                my @pf_raw = <$pf>;

                close($pf);

                my $linenum = 0;

                foreach my $pline (@pf_raw) {
                    $linenum++;
                    chomp $pline;

                    last if ($pline =~ /---/);

                    (my $pfield, my $pdata) = split /:\s+/, $pline;

                    if ($pfield) {
                        foreach my $ex (@extract_patch) {
                            if ($pfield =~ /$ex/) {
                                if ($pdata) {
                                    my $cc = DUCK->extract_url($pdata);

                                    if ($cc) {
                                        push(
                                            @$entries_ref,
                                            [
                                                "$patchdir/$patchfile:"
                                                    . $linenum,
                                                "URL",
                                                $cc,
                                                $cc,
                                                {
                                                    filename =>
                                                        "$patchdir/$patchfile",
                                                    linenumber  => $linenum,
                                                    checkmethod => "URL",
                                                    url         => $cc,
                                                    certainty   => "possible"
                                                }
                                            ]
                                        );

                                        next;
                                    }

                                    if ($pdata =~ /@/) {
                                        my $pdata_line_mangled = $pdata;

                                        $pdata_line_mangled =~
                                            s/[\*\#|<>\(\)\/]/ /g;
                                        $pdata_line_mangled =~ s/\s\s*/ /g;

                                        next unless length($pdata_line_mangled);

                                        my @emails = ($pdata_line_mangled =~
                                                /$RE{Email}{Address}{-keep}/go);

                                        if (@emails
                                            && (!($pdata =~ /Message-id:/i)))
                                        {
                                            my @parsed = map $_->address,
                                                Mail::Address->parse(@emails);

                                            foreach my $e (@parsed) {
                                                if (
                                                    !split(
                                                        '.', (split('@', $e))[1]
                                                    )
                                                    )
                                                {
                                                    next;
                                                }

                                                my $e_a = $e;

                                                push(
                                                    @$entries_ref,
                                                    [
                                                        "$patchdir/$patchfile:"
                                                            . $linenum,
                                                        "Email",
                                                        $e_a,
                                                        $pdata,
                                                        {
                                                            filename =>
                                                                "$patchdir/$patchfile",
                                                            linenumber =>
                                                                $linenum,
                                                            checkmethod =>
                                                                "Email",
                                                            url =>
                                                                $pdata_line_mangled,
                                                            certainty =>
                                                                "possible"
                                                        }
                                                    ]
                                                );
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    return;
}

1;
