# changes-file -- lintian check script -*- perl -*-

# Copyright (C) 1998 Christian Schwarz and Richard Braakman
#
# This program is free software.  It is distributed under the terms of
# the GNU General Public License as published by the 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.
#
# 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 http://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 Lintian::changes_file;
use strict;
use warnings;

use Util;
use Lintian::Tags qw(tag);
use Lintian::Check qw(check_maintainer);

our $CHECK_CHECKSUMS = $main::check_checksums;

sub run {

my $pkg = shift;
my $type = shift;
my $info = shift;

# If we don't have a Format key, something went seriously wrong.
# Tag the file and skip remaining processing.
if (!$info->field('format')) {
    tag 'malformed-changes-file';
    return 0;
}

# Description is mandated by dak, but only makes sense if binary
# packages are included.  Don't tag pure source uploads.
if (!$info->field('description') && $info->field('architecture') ne 'source') {
    tag 'no-description-in-changes-file';
}

# check distribution field
if (defined $info->field('distribution')) {
    my $ubuntu_dists = Lintian::Data->new ('changelog-file/ubuntu-dists');
    my $ubuntu_regex = join('|', $ubuntu_dists->all);
    my @distributions = split /\s+/o, $info->field('distribution');
    for my $distribution (@distributions) {
	if ($distribution eq 'UNRELEASED') {
	    # ignore
	} elsif ($info->field('version') =~ /ubuntu|$ubuntu_regex/
	    or $distribution =~ /$ubuntu_regex/) {
		if ($distribution !~ /^(?:$ubuntu_regex)(?:-(?:proposed|updates|backports|security))?$/ ) {
		    tag 'bad-ubuntu-distribution-in-changes-file',
			$distribution;
		}
	} elsif (! (($distribution eq 'oldstable')
		     or ($distribution eq 'stable')
		     or ($distribution eq 'testing')
		     or ($distribution eq 'unstable')
		     or ($distribution eq 'experimental')
		     or ($distribution =~ /^\w+-backports$/)
		     or ($distribution =~ /^\w+-proposed-updates$/)
		     or ($distribution =~ /^\w+-security$/)
		     or ($distribution =~ /^\w+-volatile$/))
		) {
	    # bad distribution entry
	    tag 'bad-distribution-in-changes-file', $distribution;
	}
    }

    if ($#distributions > 0) {
	tag 'multiple-distributions-in-changes-file',
	    $info->field('distribution');
    }
}

    # Urgency is only recommended by Policy.
    if (!$info->field('urgency')) {
	tag 'no-urgency-in-changes-file';
    } else {
	my $urgency = lc $info->field('urgency');
	$urgency =~ s/ .*//o;
	unless ($urgency =~ /^(?:low|medium|high|critical|emergency)$/io) {
	    tag 'bad-urgency-in-changes-file', $info->field('urgency');
	}
    }

    # Changed-By is optional in Policy, but if set, must be
    # syntactically correct.  It's also used by dak.
    if ($info->field('changed-by')) {
	check_maintainer($info->field('changed-by'), 'changed-by');
    }

    my $files = $info->files;
    foreach my $file (keys %$files) {
        my $file_info = $files->{$file};

	# check section
	if (($file_info->{section} eq 'non-free') or
	    ($file_info->{section} eq 'contrib')) {
	    tag 'bad-section-in-changes-file', $file, $file_info->{section};
	}

	foreach my $alg (qw(sha1 sha256)) {
	    my $checksum_info = $file_info->{checksums}{$alg};
	    if (defined $checksum_info) {
		if ($file_info->{size} != $checksum_info->{filesize}) {
		    tag 'file-size-mismatch-in-changes-file', $file,
			$file_info->{size} . ' != ' .
			$checksum_info->{filesize};
		}
	    }
	}

	# check size
	my $path = readlink('changes');
	$path =~ s#/[^/]+$##;
	my $filename = "$path/$file";
	my $size = -s $filename;

	if ($size ne $file_info->{size}) {
	    tag 'file-size-mismatch-in-changes-file', $file,
		 $file_info->{size} . " != $size";
	}

	# check checksums
	if ($CHECK_CHECKSUMS or $file =~ m/\.dsc$/o) {
	    foreach my $alg (qw(md5 sha1 sha256)) {
		next unless exists $file_info->{checksums}{$alg};

		my $real_checksum = get_file_checksum($alg, $filename);

		if ($real_checksum ne $file_info->{checksums}{$alg}{sum}) {
		    tag 'checksum-mismatch-in-changes-file', $alg, $file;
		}
	    }
	}
    }
}

1;

# Local Variables:
# indent-tabs-mode: t
# cperl-indent-level: 4
# End:
# vim: sw=4 ts=8 noet fdm=marker
