#!/usr/bin/perl -w

my $print_cc = 0;

my $reference = 0;
my $noreference = 0;
my $trace_devel = 0;
my $trace_kernel = 0;
my $found_signed = 0;

while ($#ARGV >= 0 && $ARGV[0] =~ /^-/) {
	my $arg = shift @ARGV;
	if ($arg eq "-n") {
		$noreference = 1;
	} elsif ($arg eq "-r") {
		$reference = 1;
	} else {
		die "unknown option $arg";
	}
}

$#ARGV < 1 && die "usage: add-links.pl mbox output";

sub process_output {
	my ($last_cc, $link, $first_cc, $ref, $ref_output, $ref_ignore, $ref_cc) = @_;

	my @output = @{$ref_output};
	my %ignore = %{$ref_ignore};
	my @cc = @{$ref_cc};

	if (!$first_cc) {
		$last_cc++;
		$first_cc = $last_cc;
	}
	for (my $i = 0; $i <= $#output; $i++) {
		if ($print_cc && $i == $first_cc) {
			foreach my $fullemail (@cc) {
				my $email = $fullemail;
				$email =~ s/.*<(.*)>/$1/;
				if (!defined($ignore{$email})) {
					print OUT "Cc: $fullemail\n";
				}
			}
		}
		if ($i == $last_cc) {
			print OUT "Link: https://patch.msgid.link/$ref\n";
			print "Link: https://patch.msgid.link/$ref\n";
		}
		print OUT $output[$i];
	}
	$found_signed || die "No Signed-off-by";
}

sub process_email {
	my $ref = "";
	my $in_mail = 1;
	my $in_header = 1;
	my $first = 1;
	my $in_to = 0;
	my $last_email;
	my $last_cc = 0;
	my $first_by = 0;
	my $last_by = 0;
	my $in_messageid = 0;
	my $first_cc = 0;
	my $link = 0;
	my %ignore;
	my @output;
	my @cc;

	while (<IN>) {
		if (/^From /) {
			if ($in_mail && !$first) {
				die "email found with no SoB";
			}
			if (!$first) {
			    process_output($last_cc, $link, $first_cc, $ref,
					   \@output, \%ignore, \@cc);
			}

			$ref = "";
			$in_mail = 1;
			$in_header = 1;
			$in_to = 1;
			$last_cc = 0;
			$first_by = 0;
			$last_by = 0;
			$first_cc = 0;
			$in_messageid = 0;
			$link = 0;
			undef @output;
			undef %ignore;
			undef @cc;

			$output[$#output+1] = $_;

		} elsif ($in_mail && /linux-trace-kernel\@vger.kernel.org/) {
			$trace_kernel = 1;
			$output[$#output+1] = $_;

		} elsif ($in_mail && (/linux-kernel\@vger.kernel.org/ || /linux-trace-kernel\@vger.kernel.org/)) {
			$reference = 1;
			$output[$#output+1] = $_;

		} elsif ($in_mail && /linux-trace-devel\@vger.kernel.org/) {
			$trace_devel = 1;
			$output[$#output+1] = $_;

		} elsif (/^Message-ID:\s*$/i) {
			$in_messageid = 1;
			$output[$#output+1] = $_;
		} elsif ($in_messageid) {
			$in_messageid = 0;
			if (length($ref)) {
				die "found two Message-ids?? $ref and $1";
			}
			$output[$#output+1] = $_;
			chomp;
			$ref = $_;
			$ref =~ s/^\s*(\S*).*/$1/;
		} elsif (/^Message-ID:\s*(\S*)/i) {
			if (length($ref)) {
				die "found two Message-ids?? $ref and $1";
			}
			$ref = $1;

			$output[$#output+1] = $_;
		} elsif ($in_mail && /Signed-off-by:/) {
			$output[$#output+1] = $_;
			if (($reference || $trace_kernel || $trace_devel) && !$noreference) {
				if (!length($ref)) {
					die "SoB found without Message-Id";
				}
				$ref =~ s/[<>]//g;
			}
			$found_signed = 1;
		} elsif ($in_mail && /Cc: .*(s?rostedt)\@/) {
			# ignore Cc's to me
		} elsif ($in_mail && /Cc: .*linux-kernel\@vger.kernel.org/) {
			# ignore Cc's to linux-kernel
		} elsif ($in_mail && /Cc: .*linux-trace-devel\@vger.kernel.org/) {
			# ignore Cc's to linux-trace-devel
		} elsif ($in_mail && /Cc: .*linux-trace-kernel\@vger.kernel.org/) {
			# ignore Cc's to linux-trace-kernel
		} elsif ($in_mail && /^\+\+\+/) {
			$in_mail = 0;
			$output[$#output+1] = $_;
		} else {
			$output[$#output+1] = $_;
		}
		if (/^\s*$/) {
			$in_header = 0;
		}
		# context type causes issues.
		if ($in_header && ( /^Content-Type/ || /^Content-Transfer-Encoding/)) {
			next;
		}
		if ($in_header && /^To:/) {
			$in_to = 1;
		} elsif (/^\S/) {
			$in_to = 0;
			undef $last_email;
		}
		if ($in_header && /^Cc:/) {
			$in_cc = 1;
		} elsif (/^\S/) {
			$in_cc = 0;
			undef $last_email;
		}
		if (!$in_header && /^(\S*-by|Cc|cc|CC):\s*(.*\@.*?)\s*$/) {
			my $tag = $1;
			my $email = $2;
			$email =~ s/.*<(.*)>/$1/;
			$ignore{$email} = 1;
			if (!$first_by) {
				$first_by = $#output+1;
			}
			if ($tag eq "Cc") {
				if (!$first_cc) {
#					$first_by = $#output+1;
					$first_cc = $#output+1;
				}
				$last_cc = $#output+1;
			}
			$last_by = $#output;
		}
		if (!$in_header && /^Fixes:\s+[[:xdigit:]]+\s+\(*".*"\)*\s*$/) {
			if (!$first_by) {
				$first_by = $#output+1;
			}
		}
		if ($first_by && !$last_cc) {
			$last_cc = $first_by - 1;
		}
		if (!$in_header && !$first_by && /^Link:/) {
			$link = $#output;
		}
		if (!$in_header && !$first_by && /^\s*$/) {
			$last_cc = $#output;
		}
		if ($in_cc || $in_to) {
			chomp;
			my $line = $_;
			$line =~ s/^Cc://;
			$line =~ s/^To://;
			$line =~ s/^\s*//;

			my @emails = split /,\s*/, $line;
			foreach my $email (@emails) {
				if (defined($last_email)) {
					$email = "$last_email $email";
					undef $last_email;
				}
				next if ($email =~ /linux-kernel\@vger\.kernel\.org/);
				next if ($email =~ /linux-trace-devel\@vger\.kernel\.org/);
				next if ($email =~ /linux-trace-kernel\@vger\.kernel\.org/);
				next if ($email =~ /rostedt/);
				next if ($email =~ /^[^<]*\@[^>]*$/ && $email !~ /stable/);
				if ($email =~ /\@/) {
					$cc[$#cc+1] = $email;
				} elsif ($email eq $emails[$#emails]) {
					$last_email = $email;
				}
			}
		}
		if (/\S/) {
			$first = 0;
		}
	}

	process_output($last_cc, $link, $first_cc, $ref,
		       \@output, \%ignore, \@cc);

}

sub process_file {
	my ($file, $outfile) = @_;

	open(IN, "$file") || die "can not read $file";
	open(OUT, ">$outfile") || die "can not write $outfile";
	process_email();
	close(IN);
	close(OUT);
}

while ($#ARGV >= 0) {
	process_file $ARGV[0], $ARGV[1];
	shift;
	shift;
}

