2001-07-04 08:41:27 +04:00
#!/usr/bonsaitools/bin/perl -wT
1998-09-16 01:49:26 +04:00
# -*- Mode: perl; indent-tabs-mode: nil -*-
1998-08-26 10:14:20 +04:00
#
1999-11-02 02:33:56 +03:00
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
1998-08-26 10:14:20 +04:00
# The Original Code is the Bugzilla Bug Tracking System.
1999-11-02 02:33:56 +03:00
#
1998-08-26 10:14:20 +04:00
# The Initial Developer of the Original Code is Netscape Communications
1999-11-02 02:33:56 +03:00
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
1999-05-12 09:22:36 +04:00
# Contributor(s): Terry Weissman <terry@mozilla.org>,
2000-03-29 01:31:24 +04:00
# Bryce Nesbitt <bryce-mozilla@nextbus.com>
# Dan Mosedale <dmose@mozilla.org>
2001-01-24 23:26:24 +03:00
# Alan Raetz <al_raetz@yahoo.com>
2001-05-24 07:10:49 +04:00
# Jacob Steenhagen <jake@actex.net>
2001-08-12 03:16:16 +04:00
# Matthew Tuck <matty@chariot.net.au>
1999-05-11 03:15:09 +04:00
1998-09-16 01:49:26 +04:00
use strict;
2001-07-04 08:41:27 +04:00
use lib ".";
1998-08-26 10:14:20 +04:00
1998-09-16 01:49:26 +04:00
require "globals.pl";
1998-08-26 10:14:20 +04:00
2000-03-29 01:31:24 +04:00
use RelationSet;
2001-07-04 08:41:27 +04:00
# Shut up misguided -w warnings about "used only once".
sub processmail_sillyness {
my $zz;
2002-07-03 02:18:49 +04:00
$zz = $::unconfirmedstate;
2001-07-04 08:41:27 +04:00
}
1998-09-16 01:49:26 +04:00
$| = 1;
1998-08-26 10:14:20 +04:00
1998-09-16 01:49:26 +04:00
umask(0);
1999-05-12 09:22:36 +04:00
my $nametoexclude = "";
2001-05-24 07:10:49 +04:00
my %nomail;
1998-09-16 01:49:26 +04:00
2001-01-24 23:26:24 +03:00
my @excludedAddresses = ();
# disable email flag for offline debugging work
my $enableSendMail = 1;
2001-02-14 23:41:26 +03:00
my %force;
@{$force{'QAcontact'}} = ();
@{$force{'Owner'}} = ();
@{$force{'Reporter'}} = ();
@{$force{'CClist'}} = ();
2001-04-07 21:09:28 +04:00
@{$force{'Voter'}} = ();
2000-01-14 01:23:25 +03:00
1998-08-26 10:14:20 +04:00
1999-08-04 19:07:28 +04:00
my %seen;
2000-01-22 07:24:42 +03:00
my @sentlist;
sub FormatTriple {
my ($a, $b, $c) = (@_);
$^A = "";
my $temp = formline << 'END', $a, $b, $c;
2000-08-29 21:01:54 +04:00
^>>>>>>>>>>>>>>>>>>|^<<<<<<<<<<<<<<<<<<<<<<<<<<<|^<<<<<<<<<<<<<<<<<<<<<<<<<<<~~
2000-01-22 07:24:42 +03:00
END
; # This semicolon appeases my emacs editor macros. :-)
return $^A;
}
sub FormatDouble {
my ($a, $b) = (@_);
$a .= ":";
$^A = "";
my $temp = formline << 'END', $a, $b;
^>>>>>>>>>>>>>>>>>> ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~~
END
; # This semicolon appeases my emacs editor macros. :-)
return $^A;
}
2001-05-24 07:10:49 +04:00
sub ProcessOneBug {
2000-01-22 07:24:42 +03:00
my ($id) = (@_);
my @headerlist;
my %values;
my %defmailhead;
my %fielddescription;
my $msg = "";
SendSQL("SELECT name, description, mailhead FROM fielddefs " .
"ORDER BY sortkey");
while (MoreSQLData()) {
my ($field, $description, $mailhead) = (FetchSQLData());
push(@headerlist, $field);
$defmailhead{$field} = $mailhead;
$fielddescription{$field} = $description;
}
SendSQL("SELECT " . join(',', @::log_columns) . ", lastdiffed, now() " .
"FROM bugs WHERE bug_id = $id");
my @row = FetchSQLData();
foreach my $i (@::log_columns) {
$values{$i} = shift(@row);
}
my ($start, $end) = (@row);
2001-07-04 08:41:27 +04:00
# $start and $end are considered safe because users can't touch them
2001-10-23 19:44:53 +04:00
trick_taint($start);
trick_taint($end);
2001-07-04 08:41:27 +04:00
2000-03-29 01:31:24 +04:00
my $ccSet = new RelationSet();
$ccSet->mergeFromDB("SELECT who FROM cc WHERE bug_id = $id");
$values{'cc'} = $ccSet->toString();
2000-01-24 08:41:40 +03:00
2001-08-12 03:16:16 +04:00
my @voterList;
2000-01-24 08:41:40 +03:00
SendSQL("SELECT profiles.login_name FROM votes, profiles " .
"WHERE votes.bug_id = $id AND profiles.userid = votes.who");
while (MoreSQLData()) {
2001-08-12 03:16:16 +04:00
push(@voterList, FetchOneColumn());
2000-01-24 08:41:40 +03:00
}
2000-01-22 07:24:42 +03:00
$values{'assigned_to'} = DBID_to_name($values{'assigned_to'});
$values{'reporter'} = DBID_to_name($values{'reporter'});
if ($values{'qa_contact'}) {
$values{'qa_contact'} = DBID_to_name($values{'qa_contact'});
}
my @diffs;
SendSQL("SELECT profiles.login_name, fielddefs.description, " .
2001-08-31 07:54:37 +04:00
" bug_when, removed, added, attach_id " .
2000-01-22 07:24:42 +03:00
"FROM bugs_activity, fielddefs, profiles " .
"WHERE bug_id = $id " .
" AND fielddefs.fieldid = bugs_activity.fieldid " .
" AND profiles.userid = who " .
" AND bug_when > '$start' " .
" AND bug_when <= '$end' " .
"ORDER BY bug_when"
);
while (MoreSQLData()) {
my @row = FetchSQLData();
push(@diffs, \@row);
}
my $difftext = "";
my $lastwho = "";
foreach my $ref (@diffs) {
2001-08-31 07:54:37 +04:00
my ($who, $what, $when, $old, $new, $attachid) = (@$ref);
2000-01-22 07:24:42 +03:00
if ($who ne $lastwho) {
$lastwho = $who;
2000-09-13 21:45:48 +04:00
$difftext .= "\n$who" . Param('emailsuffix') . " changed:\n\n";
2001-07-20 19:18:30 +04:00
$difftext .= FormatTriple("What ", "Removed", "Added");
2000-01-22 07:24:42 +03:00
$difftext .= ('-' x 76) . "\n";
}
2002-01-30 17:14:12 +03:00
$what =~ s/^Attachment/Attachment #$attachid/ if $attachid;
2000-01-22 07:24:42 +03:00
$difftext .= FormatTriple($what, $old, $new);
}
$difftext = trim($difftext);
2000-01-23 04:03:15 +03:00
my $deptext = "";
my $resid =
2001-08-30 07:14:24 +04:00
SendSQL("SELECT bugs_activity.bug_id, bugs.short_desc, fielddefs.name, " .
2001-07-20 19:18:30 +04:00
" removed, added " .
2001-08-30 07:14:24 +04:00
"FROM bugs_activity, bugs, dependencies, fielddefs ".
2000-01-23 04:03:15 +03:00
"WHERE bugs_activity.bug_id = dependencies.dependson " .
2001-08-30 07:14:24 +04:00
" AND bugs.bug_id = bugs_activity.bug_id ".
2000-01-23 04:03:15 +03:00
" AND dependencies.blocked = $id " .
" AND fielddefs.fieldid = bugs_activity.fieldid" .
" AND (fielddefs.name = 'bug_status' " .
" OR fielddefs.name = 'resolution') " .
" AND bug_when > '$start' " .
" AND bug_when <= '$end' " .
"ORDER BY bug_when, bug_id");
my $thisdiff = "";
my $lastbug = "";
my $interestingchange = 0;
2002-01-16 06:25:52 +03:00
my $depbug = 0;
my @depbugs;
2000-01-23 04:03:15 +03:00
while (MoreSQLData()) {
2002-01-16 06:25:52 +03:00
my ($summary, $what, $old, $new);
($depbug, $summary, $what, $old, $new) = (FetchSQLData());
if ($depbug ne $lastbug) {
2000-01-23 04:03:15 +03:00
if ($interestingchange) {
$deptext .= $thisdiff;
}
2002-01-16 06:25:52 +03:00
$lastbug = $depbug;
2002-01-11 00:47:04 +03:00
my $urlbase = Param("urlbase");
2000-01-23 04:03:15 +03:00
$thisdiff =
2002-01-16 06:25:52 +03:00
"\nBug $id depends on bug $depbug, which changed state.\n\n" .
"Bug $depbug Summary: $summary\n" .
"${urlbase}show_bug.cgi?id=$depbug\n\n";
2000-01-23 04:03:15 +03:00
$thisdiff .= FormatTriple("What ", "Old Value", "New Value");
$thisdiff .= ('-' x 76) . "\n";
$interestingchange = 0;
}
$thisdiff .= FormatTriple($fielddescription{$what}, $old, $new);
if ($what eq 'bug_status' && IsOpenedState($old) ne IsOpenedState($new)) {
$interestingchange = 1;
}
2002-01-16 06:25:52 +03:00
push(@depbugs, $depbug);
2000-01-23 04:03:15 +03:00
}
2002-01-16 06:25:52 +03:00
2000-01-23 04:03:15 +03:00
if ($interestingchange) {
$deptext .= $thisdiff;
}
$deptext = trim($deptext);
if ($deptext) {
$difftext = trim($difftext . "\n\n" . $deptext);
}
2002-08-20 01:17:28 +04:00
my ($newcomments, $anyprivate) = GetLongDescriptionAsText($id, $start, $end);
2000-01-22 07:24:42 +03:00
2001-05-24 07:10:49 +04:00
#
# Start of email filtering code
#
my $count = 0;
2001-01-24 23:26:24 +03:00
2002-07-03 02:18:49 +04:00
# Get a list of the reasons a user might receive email about the bug.
my @currentEmailAttributes =
getEmailAttributes(\%values, \@diffs, $newcomments);
2001-05-24 07:10:49 +04:00
my (@assigned_toList,@reporterList,@qa_contactList,@ccList) = ();
2001-01-24 23:26:24 +03:00
2001-05-24 07:10:49 +04:00
#open(LOG, ">>/tmp/maillog");
#print LOG "\nBug ID: $id CurrentEmailAttributes:";
#print LOG join(',', @currentEmailAttributes) . "\n";
2001-04-07 21:09:28 +04:00
2001-05-24 07:10:49 +04:00
@excludedAddresses = (); # zero out global list
2001-01-24 23:26:24 +03:00
2001-05-24 07:10:49 +04:00
@assigned_toList = filterEmailGroup('Owner',
\@currentEmailAttributes,
$values{'assigned_to'});
@reporterList = filterEmailGroup('Reporter',
\@currentEmailAttributes,
$values{'reporter'});
if (Param('useqacontact') && $values{'qa_contact'}) {
@qa_contactList = filterEmailGroup('QAcontact',
\@currentEmailAttributes,
$values{'qa_contact'});
} else {
@qa_contactList = ();
}
2001-01-24 23:26:24 +03:00
2001-05-24 07:10:49 +04:00
@ccList = filterEmailGroup('CClist', \@currentEmailAttributes,
$values{'cc'});
2001-01-24 23:26:24 +03:00
2001-08-12 03:16:16 +04:00
@voterList = filterEmailGroup('Voter', \@currentEmailAttributes,
join(',',@voterList));
2001-01-24 23:26:24 +03:00
2001-05-24 07:10:49 +04:00
my @emailList = (@assigned_toList, @reporterList,
2001-08-12 03:16:16 +04:00
@qa_contactList, @ccList, @voterList);
2001-01-24 23:26:24 +03:00
2001-05-24 07:10:49 +04:00
# only need one entry per person
my @allEmail = ();
my %AlreadySeen = ();
2002-07-11 12:05:05 +04:00
my $checkperson = "";
2001-05-24 07:10:49 +04:00
foreach my $person (@emailList) {
2002-07-11 12:05:05 +04:00
# don't modify the original so it sends out with the right case
# based on who came first.
$checkperson = lc($person);
if ( !($AlreadySeen{$checkperson}) ) {
2001-05-24 07:10:49 +04:00
push(@allEmail,$person);
2002-07-11 12:05:05 +04:00
$AlreadySeen{$checkperson}++;
2001-01-24 23:26:24 +03:00
}
2001-05-24 07:10:49 +04:00
}
2001-01-24 23:26:24 +03:00
2001-05-24 07:10:49 +04:00
#print LOG "\nbug $id email sent: " . join(',', @allEmail) . "\n";
@excludedAddresses = filterExcludeList(\@excludedAddresses,
\@allEmail);
2000-09-16 02:39:35 +04:00
2001-05-24 07:10:49 +04:00
# print LOG "excluded: " . join(',',@excludedAddresses) . "\n\n";
foreach my $person ( @allEmail ) {
2001-08-12 03:16:16 +04:00
my @reasons;
2001-05-24 07:10:49 +04:00
$count++;
2001-08-12 03:16:16 +04:00
push(@reasons, 'AssignedTo') if lsearch(\@assigned_toList, $person) != -1;
push(@reasons, 'Reporter') if lsearch(\@reporterList, $person) != -1;
push(@reasons, 'QAContact') if lsearch(\@qa_contactList, $person) != -1;
push(@reasons, 'CC') if lsearch(\@ccList, $person) != -1;
push(@reasons, 'Voter') if lsearch(\@voterList, $person) != -1;
2001-05-24 07:10:49 +04:00
if ( !defined(NewProcessOnePerson($person, $count, \@headerlist,
2001-08-12 03:16:16 +04:00
\@reasons, \%values,
\%defmailhead,
2001-05-24 07:10:49 +04:00
\%fielddescription, $difftext,
2002-08-20 01:17:28 +04:00
$newcomments, $anyprivate,
$start, $id,
2002-01-16 06:25:52 +03:00
\@depbugs)))
{
2001-05-24 07:10:49 +04:00
# if a value is not returned, this means that the person
# was not sent mail. add them to the excludedAddresses list.
# it will be filtered later for dups.
#
push @excludedAddresses, $person;
2001-01-24 23:26:24 +03:00
}
2000-03-29 01:31:24 +04:00
}
2000-01-22 07:24:42 +03:00
2001-05-24 07:10:49 +04:00
2000-03-29 01:31:24 +04:00
SendSQL("UPDATE bugs SET lastdiffed = '$end', delta_ts = delta_ts " .
"WHERE bug_id = $id");
2001-05-24 07:10:49 +04:00
# Filter the exclude list for dupes one last time
@excludedAddresses = filterExcludeList(\@excludedAddresses,
\@sentlist);
if (@sentlist) {
print "<b>Email sent to:</b> " . join(", ", @sentlist) ."<br>\n";
} else {
print "<b>Email sent to:</b> no one<br>\n";
}
if (@excludedAddresses) {
print "<b>Excluding:</b> " . join(", ", @excludedAddresses) . "\n";
}
print "<br><center>If you wish to tweak the kinds of mail Bugzilla sends you, you can";
2002-03-24 15:45:33 +03:00
print " <a href=\"userprefs.cgi?tab=email\">change your preferences</a></center>\n";
2001-05-24 07:10:49 +04:00
2000-03-29 01:31:24 +04:00
}
2000-01-22 07:24:42 +03:00
2001-01-24 23:26:24 +03:00
# When one person is in different fields on one bug, they may be
# excluded from email because of one relationship to the bug (eg
# they're the QA contact) but included because of another (eg they
# also reported the bug). Inclusion takes precedence, so this
# function looks for and removes any users from the exclude list who
# are also on the include list. Additionally, it removes duplicate
# entries from the exclude list.
#
# Arguments are the exclude list and the include list; the cleaned up
# exclude list is returned.
#
sub filterExcludeList ($$) {
if ($#_ != 1) {
die ("filterExcludeList called with wrong number of args");
}
my ($refExcluded, $refAll) = @_;
my @excludedAddrs = @$refExcluded;
my @allEmail = @$refAll;
my @tmpList = @excludedAddrs;
my (@result,@uniqueResult) = ();
my %alreadySeen;
foreach my $excluded (@tmpList) {
push (@result,$excluded);
foreach my $included (@allEmail) {
# match found, so we remove the entry
2002-07-11 12:05:05 +04:00
if (lc($included) eq lc($excluded)) {
2001-01-24 23:26:24 +03:00
pop(@result);
2001-06-02 07:19:26 +04:00
last;
2001-01-24 23:26:24 +03:00
}
}
}
# only need one entry per person
2002-07-11 12:05:05 +04:00
my $checkperson = "";
2001-01-24 23:26:24 +03:00
foreach my $person (@result) {
2002-07-11 12:05:05 +04:00
$checkperson = lc($person);
if ( !($alreadySeen{$checkperson}) ) {
2001-01-24 23:26:24 +03:00
push(@uniqueResult,$person);
2002-07-11 12:05:05 +04:00
$alreadySeen{$checkperson}++;
2001-01-24 23:26:24 +03:00
}
}
return @uniqueResult;
}
# if the Status was changed to Resolved or Verified
# set the Resolved flag
#
# else if Severity, Status OR Priority fields have any change
# set the Status flag
#
# else if Keywords has changed
# set the Keywords flag
#
# else if CC has changed
# set the CC flag
#
# if the Comments field shows an attachment
# set the Attachment flag
#
# else if Comments exist
# set the Comments flag
#
# if no flags are set and there was some other field change
# set the Status flag
#
2002-07-03 02:18:49 +04:00
sub getEmailAttributes (\%\@$) {
2001-01-24 23:26:24 +03:00
2002-07-03 02:18:49 +04:00
my ($bug, $fieldDiffs, $commentField) = @_;
2001-01-24 23:26:24 +03:00
my (@flags,@uniqueFlags,%alreadySeen) = ();
2002-07-03 02:18:49 +04:00
# Add a flag if the status of the bug is "unconfirmed".
if ($bug->{'bug_status'} eq $::unconfirmedstate) {
push (@flags, 'Unconfirmed')
};
foreach my $ref (@$fieldDiffs) {
2001-01-24 23:26:24 +03:00
my ($who, $fieldName, $when, $old, $new) = (@$ref);
#print qq{field: $fieldName $new<br>};
# the STATUS will be flagged for Severity, Status and
# Priority changes
#
2002-05-23 12:08:53 +04:00
if ( $fieldName eq 'Status' && ($new eq 'RESOLVED' || $new eq 'VERIFIED')) {
push (@flags, 'Resolved');
2001-01-24 23:26:24 +03:00
}
elsif ( $fieldName eq 'Severity' || $fieldName eq 'Status' ||
$fieldName eq 'Priority' ) {
push (@flags, 'Status');
} elsif ( $fieldName eq 'Keywords') {
push (@flags, 'Keywords');
} elsif ( $fieldName eq 'CC') {
push (@flags, 'CC');
}
2001-04-07 20:36:45 +04:00
# These next few lines are for finding out who's been added
# to the Owner, QA, CC, etc. fields. It does not effect
# the @flags array at all, but is run here because it does
# effect filtering later and we're already in the loop.
if ($fieldName eq 'Owner') {
push (@{$force{'Owner'}}, $new);
} elsif ($fieldName eq 'QAContact') {
push (@{$force{'QAContact'}}, $new);
} elsif ($fieldName eq 'CC') {
2001-07-20 19:18:30 +04:00
my @added = split (/[ ,]/, $new);
2001-04-07 20:36:45 +04:00
push (@{$force{'CClist'}}, @added);
}
2001-01-24 23:26:24 +03:00
}
if ( $commentField =~ /Created an attachment \(/ ) {
push (@flags, 'Attachments');
}
2001-04-04 00:54:53 +04:00
elsif ( ($commentField ne '') && !(scalar(@flags) == 1 && $flags[0] eq 'Resolved')) {
2001-01-24 23:26:24 +03:00
push (@flags, 'Comments');
}
# default fallthrough for any unflagged change is 'Other'
2002-07-03 02:18:49 +04:00
if ( @flags == 0 && @$fieldDiffs != 0 ) {
2001-01-24 23:26:24 +03:00
push (@flags, 'Other');
}
# only need one flag per attribute type
foreach my $flag (@flags) {
if ( !($alreadySeen{$flag}) ) {
push(@uniqueFlags,$flag);
$alreadySeen{$flag}++;
}
}
#print "\nEmail Attributes: ", join(' ,',@uniqueFlags), "<br>\n";
# catch-all default, just in case the above logic is faulty
if ( @uniqueFlags == 0) {
push (@uniqueFlags, 'Comments');
}
return @uniqueFlags;
}
sub filterEmailGroup ($$$) {
2002-07-03 02:18:49 +04:00
# This function figures out who should receive email about the bug
# based on the user's role with regard to the bug (assignee, reporter
# etc.), the changes that occurred (new comments, attachment added,
# status changed etc.) and the user's email preferences.
2001-01-24 23:26:24 +03:00
2002-07-03 02:18:49 +04:00
# Returns a filtered list of those users who would receive email
# about these changes, and adds the names of those users who would
# not receive email about them to the global @excludedAddresses list.
2001-01-24 23:26:24 +03:00
2002-07-03 02:18:49 +04:00
my ($role, $reasons, $users) = @_;
# Make a list of users to filter.
my @users = split( /,/ , $users );
# Treat users who are in the process of being removed from this role
# as if they were still in it.
push @users, @{$force{$role}};
# If this installation supports user watching, add to the list those
# users who are watching other users already on the list. By doing
# this here, we allow watchers to inherit the roles of the people
# they are watching while at the same time filtering email for watchers
# based on their own preferences.
if (Param("supportwatchers") && scalar(@users)) {
# Convert the unfiltered list of users into an SQL-quoted,
# comma-separated string suitable for use in an SQL query.
my $watched = join(",", map(SqlQuote($_), @users));
SendSQL("SELECT watchers.login_name
FROM watch, profiles AS watchers, profiles AS watched
WHERE watched.login_name IN ($watched)
AND watched.userid = watch.watched
AND watch.watcher = watchers.userid");
push (@users, FetchOneColumn()) while MoreSQLData();
2001-03-15 10:50:36 +03:00
}
2002-07-03 02:18:49 +04:00
# Initialize the list of recipients.
my @recipients = ();
2001-03-15 10:50:36 +03:00
2002-07-03 02:18:49 +04:00
USER: foreach my $user (@users) {
next unless $user;
2001-01-24 23:26:24 +03:00
2002-07-03 02:18:49 +04:00
# Get the user's unique ID, and if the user is not registered
# (no idea why unregistered users should even be on this list,
# but the code that was here before I re-wrote it allows this),
# then we do not have any preferences for them, so assume the
# default preference to receive all mail for any reason.
my $userid = DBname_to_id($user);
if (!$userid) {
push(@recipients, $user);
2001-01-24 23:26:24 +03:00
next;
}
2002-07-03 02:18:49 +04:00
# Get the user's email preferences from the database.
SendSQL("SELECT emailflags FROM profiles WHERE userid = $userid");
my $prefs = FetchOneColumn();
2001-01-24 23:26:24 +03:00
2002-07-03 02:18:49 +04:00
# If the user's preferences are empty, assume the default preference
# to receive all mail. This happens when the installation upgraded
# from a version of Bugzilla without email preferences to one with
# them, but the user has not set their preferences yet.
if (!defined($prefs) || $prefs !~ /email/) {
push(@recipients, $user);
next;
}
2001-01-24 23:26:24 +03:00
2002-07-03 02:18:49 +04:00
# Write the user's preferences into a Perl record indexed by
# preference name. We pass the value "255" to the split function
# because otherwise split will trim trailing null fields, causing
# Perl to generate lots of warnings. Any suitably large number
# would do.
my %prefs = split(/~/, $prefs, 255);
# If this user is the one who made the change in the first place,
# and they prefer not to receive mail about their own changes,
# filter them from the list.
if (lc($user) eq $nametoexclude && $prefs{'ExcludeSelf'} eq 'on') {
push(@excludedAddresses, $user);
next;
2001-01-24 23:26:24 +03:00
}
2002-07-03 02:18:49 +04:00
# If the user doesn't want to receive email about unconfirmed
# bugs, that setting overrides their other preferences, including
# the preference to receive email when they are added to or removed
# from a role, so remove them from the list before checking their
# other preferences.
if (grep(/Unconfirmed/, @$reasons)
&& exists($prefs{"email${role}Unconfirmed"})
&& $prefs{"email${role}Unconfirmed"} eq '')
{
push(@excludedAddresses, $user);
next;
}
2001-01-24 23:26:24 +03:00
2002-07-03 02:18:49 +04:00
# If the user was added to or removed from this role, and they
# prefer to receive email when that happens, send them mail.
# Note: This was originally written to send email when users
# were removed from roles and was later enhanced for additions,
# but for simplicity's sake the name "Removeme" was retained.
if (grep($_ eq $user, @{$force{$role}})
&& $prefs{"email${role}Removeme"} eq 'on')
{
push (@recipients, $user);
next;
2001-01-24 23:26:24 +03:00
}
2002-07-03 02:18:49 +04:00
# If the user prefers to be included in mail about this change,
# or they haven't specified a preference for it (because they
# haven't visited the email preferences page since the preference
# was added, in which case we include them by default), add them
# to the list of recipients.
foreach my $reason (@$reasons) {
my $pref = "email$role$reason";
if (!exists($prefs{$pref}) || $prefs{$pref} eq 'on') {
push(@recipients, $user);
next USER;
2001-02-14 23:41:26 +03:00
}
2002-07-03 02:18:49 +04:00
}
# At this point there's no way the user wants to receive email
# about this change, so exclude them from the list of recipients.
push(@excludedAddresses, $user);
} # for each user on the unfiltered list
2001-02-14 23:41:26 +03:00
2002-07-03 02:18:49 +04:00
return @recipients;
2001-01-24 23:26:24 +03:00
}
2002-08-20 01:17:28 +04:00
sub NewProcessOnePerson ($$$$$$$$$$$$$) {
2001-08-12 03:16:16 +04:00
my ($person, $count, $hlRef, $reasonsRef, $valueRef, $dmhRef, $fdRef, $difftext,
2002-08-20 01:17:28 +04:00
$newcomments, $anyprivate, $start, $id, $depbugsRef) = @_;
2000-01-22 07:24:42 +03:00
2000-03-29 01:31:24 +04:00
my %values = %$valueRef;
my @headerlist = @$hlRef;
2001-08-12 03:16:16 +04:00
my @reasons = @$reasonsRef;
2000-03-29 01:31:24 +04:00
my %defmailhead = %$dmhRef;
my %fielddescription = %$fdRef;
2002-01-16 06:25:52 +03:00
my @depbugs = @$depbugsRef;
2000-03-29 01:31:24 +04:00
if ($seen{$person}) {
return;
}
2001-05-24 07:10:49 +04:00
if ($nomail{$person}) {
return;
}
2001-10-23 19:44:53 +04:00
2000-01-23 04:03:15 +03:00
2001-10-23 19:44:53 +04:00
SendSQL("SELECT userid, groupset " .
2000-03-29 01:31:24 +04:00
"FROM profiles WHERE login_name = " . SqlQuote($person));
2001-05-24 07:10:49 +04:00
my ($userid, $groupset) = (FetchSQLData());
2001-10-23 19:44:53 +04:00
2000-03-29 01:31:24 +04:00
$seen{$person} = 1;
2000-01-22 07:24:42 +03:00
2001-10-23 19:44:53 +04:00
detaint_natural($userid);
detaint_natural($groupset);
2000-01-22 07:24:42 +03:00
2000-03-29 01:31:24 +04:00
# if this person doesn't have permission to see info on this bug,
# return.
#
2001-10-23 19:44:53 +04:00
# XXX - This currently means that if a bug is suddenly given
2000-03-29 01:31:24 +04:00
# more restrictive permissions, people without those permissions won't
# see the action of restricting the bug itself; the bug will just
# quietly disappear from their radar.
#
2001-10-23 19:44:53 +04:00
return unless CanSeeBug($id, $userid, $groupset);
2002-08-20 01:17:28 +04:00
# Drop any non-insiders if the comment is private
if (Param("insidergroup") && ($anyprivate != 0)) {
ConnectToDatabase();
PushGlobalSQLState();
SendSQL("select (bit & $groupset ) != 0 from groups where name = " . SqlQuote(Param("insidergroup")));
my $bit = FetchOneColumn();
PopGlobalSQLState();
if (!$bit) {
return;
}
}
2002-01-16 06:25:52 +03:00
# We shouldn't send changedmail if this is a dependency mail, and any of
# the depending bugs is not visible to the user.
foreach my $dep_id (@depbugs) {
my $save_id = $dep_id;
detaint_natural($dep_id) || warn("Unexpected Error: \@depbugs contains a non-numeric value: '$save_id'")
&& return;
return unless CanSeeBug($dep_id, $userid, $groupset);
}
2000-03-29 01:31:24 +04:00
my %mailhead = %defmailhead;
my $head = "";
foreach my $f (@headerlist) {
if ($mailhead{$f}) {
my $value = $values{$f};
2001-06-14 18:16:27 +04:00
# If there isn't anything to show, don't include this header
if (! $value) {
2000-03-29 01:31:24 +04:00
next;
}
my $desc = $fielddescription{$f};
$head .= FormatDouble($desc, $value);
}
}
if ($difftext eq "" && $newcomments eq "") {
# Whoops, no differences!
return;
}
2001-08-13 21:06:38 +04:00
my $reasonsbody = "------- You are receiving this mail because: -------\n";
2001-08-12 03:16:16 +04:00
if (scalar(@reasons) == 0) {
$reasonsbody .= "Whoops! I have no idea!\n";
} else {
foreach my $reason (@reasons) {
if ($reason eq 'AssignedTo') {
$reasonsbody .= "You are the assignee for the bug, or are watching the assignee.\n";
} elsif ($reason eq 'Reporter') {
$reasonsbody .= "You reported the bug, or are watching the reporter.\n";
} elsif ($reason eq 'QAContact') {
$reasonsbody .= "You are the QA contact for the bug, or are watching the QA contact.\n";
} elsif ($reason eq 'CC') {
$reasonsbody .= "You are on the CC list for the bug, or are watching someone who is.\n";
} elsif ($reason eq 'Voter') {
$reasonsbody .= "You are a voter for the bug, or are watching someone who is.\n";
} else {
$reasonsbody .= "Whoops! There is an unknown reason!\n";
}
}
}
2000-03-29 01:31:24 +04:00
my $isnew = ($start !~ m/[1-9]/);
my %substs;
2000-09-13 21:45:48 +04:00
2001-10-06 02:38:12 +04:00
# If an attachment was created, then add an URL. (Note: the 'g'lobal
# replace should work with comments with multiple attachments.)
if ( $newcomments =~ /Created an attachment \(/ ) {
my $showattachurlbase =
2002-01-30 17:14:12 +03:00
Param('urlbase') . "attachment.cgi?id=";
2001-10-06 02:38:12 +04:00
2002-01-30 17:14:12 +03:00
$newcomments =~ s/(Created an attachment \(id=([0-9]+)\))/$1\n --> \(${showattachurlbase}$2&action=view\)/g;
2001-10-06 02:38:12 +04:00
}
2000-09-13 21:45:48 +04:00
$person .= Param('emailsuffix');
2000-09-14 01:25:25 +04:00
# 09/13/2000 cyeh@bluemartini.com
# If a bug is changed, don't put the word "Changed" in the subject mail
# since if the bug didn't change, you wouldn't be getting mail
# in the first place! see http://bugzilla.mozilla.org/show_bug.cgi?id=29820
# for details.
2001-04-06 21:40:49 +04:00
$substs{"neworchanged"} = $isnew ? 'New: ' : '';
2000-03-29 01:31:24 +04:00
$substs{"to"} = $person;
$substs{"cc"} = '';
$substs{"bugid"} = $id;
if ($isnew) {
$substs{"diffs"} = $head . "\n\n" . $newcomments;
} else {
$substs{"diffs"} = $difftext . "\n\n" . $newcomments;
}
$substs{"summary"} = $values{'short_desc'};
2001-08-12 03:16:16 +04:00
$substs{"reasonsheader"} = join(" ", @reasons);
$substs{"reasonsbody"} = $reasonsbody;
2000-03-29 01:31:24 +04:00
my $template = Param("newchangedmail");
my $msg = PerformSubsts($template, \%substs);
2000-08-30 00:10:15 +04:00
my $sendmailparam = "-ODeliveryMode=deferred";
if (Param("sendmailnow")) {
2000-09-02 08:26:36 +04:00
$sendmailparam = "";
2000-08-30 00:10:15 +04:00
}
2001-01-24 23:26:24 +03:00
if ($enableSendMail == 1) {
2002-02-17 11:22:31 +03:00
open(SENDMAIL, "|/usr/lib/sendmail $sendmailparam -t -i") ||
2000-03-29 01:31:24 +04:00
die "Can't open sendmail";
print SENDMAIL trim($msg) . "\n";
close SENDMAIL;
2001-01-24 23:26:24 +03:00
}
2000-03-29 01:31:24 +04:00
push(@sentlist, $person);
2001-01-24 23:26:24 +03:00
return 1;
2000-01-22 07:24:42 +03:00
}
1999-05-12 09:22:36 +04:00
# Code starts here
ConnectToDatabase();
2000-01-22 07:24:42 +03:00
GetVersionTable();
1999-05-12 09:22:36 +04:00
if (open(FID, "<data/nomail")) {
while (<FID>) {
2001-05-24 07:10:49 +04:00
$nomail{trim($_)} = 1;
1999-05-12 09:22:36 +04:00
}
close FID;
}
2000-03-29 01:31:24 +04:00
if ($#ARGV >= 0 && $ARGV[0] eq "regenerate") {
2001-05-24 07:10:49 +04:00
print "Regenerating is no longer required or supported\n";
1999-05-12 09:22:36 +04:00
exit;
}
2000-03-29 01:31:24 +04:00
if ($#ARGV >= 0 && $ARGV[0] eq "-forcecc") {
2000-01-14 01:23:25 +03:00
shift(@ARGV);
foreach my $i (split(/,/, shift(@ARGV))) {
2001-02-14 23:41:26 +03:00
push(@{$force{'CClist'}}, trim($i));
2000-01-14 01:23:25 +03:00
}
}
2001-02-14 23:41:26 +03:00
if ($#ARGV >= 0 && $ARGV[0] eq "-forceowner") {
shift(@ARGV);
@{$force{'Owner'}} = (trim(shift(@ARGV)));
}
if ($#ARGV >= 0 && $ARGV[0] eq "-forceqacontact") {
shift(@ARGV);
@{$force{'QAcontact'}} = (trim(shift(@ARGV)));
}
2002-04-14 08:43:55 +04:00
if ($#ARGV >= 0 && $ARGV[0] eq "-forcereporter") {
shift(@ARGV);
@{$force{'Reporter'}} = trim(shift(@ARGV));
}
2000-01-14 01:23:25 +03:00
if (($#ARGV < 0) || ($#ARGV > 1)) {
2001-02-14 23:41:26 +03:00
print "Usage:\n processmail {bugid} {nametoexclude} " .
"[-forcecc list,of,users]\n [-forceowner name] " .
2002-04-14 08:43:55 +04:00
"[-forceqacontact name]\n [-forcereporter name]\nor\n" .
2001-02-14 23:41:26 +03:00
" processmail rescanall\n";
2000-01-14 01:23:25 +03:00
exit;
}
1999-05-12 09:22:36 +04:00
if ($#ARGV == 1) {
1999-06-11 20:07:32 +04:00
$nametoexclude = lc($ARGV[1]);
1999-05-12 09:22:36 +04:00
}
1999-10-11 22:18:39 +04:00
if ($ARGV[0] eq "rescanall") {
2002-03-04 01:06:20 +03:00
print "Collecting bug ids...\n";
SendSQL("select bug_id, lastdiffed, delta_ts from bugs where lastdiffed < delta_ts AND delta_ts < date_sub(now(), INTERVAL 30 minute) order by bug_id");
1999-10-11 22:18:39 +04:00
my @list;
while (my @row = FetchSQLData()) {
2002-03-04 01:06:20 +03:00
my $time = $row[2];
if ($time =~ /^(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/) {
$time = "$1-$2-$3 $4:$5:$6";
}
print STDERR "Bug $row[0] has unsent mail. lastdiffed is $row[1], delta_ts is $time.\n";
1999-10-11 22:18:39 +04:00
push @list, $row[0];
}
2002-03-04 01:06:20 +03:00
if (scalar(@list) > 0) {
print STDERR scalar(@list) . " bugs found with possibly unsent mail\n";
print STDERR "Updating bugs, sending mail if required\n";
} else {
print "All appropriate mail appears to have been sent\n"
}
1999-10-11 22:18:39 +04:00
foreach my $id (@list) {
2001-10-23 19:44:53 +04:00
if (detaint_natural($id)) {
ProcessOneBug($id);
}
1999-10-11 22:18:39 +04:00
}
} else {
2001-07-04 08:41:27 +04:00
my $bugnum;
if ($ARGV[0] =~ m/^([1-9][0-9]*)$/) {
$bugnum = $1;
} else {
print "Error calling processmail (bug id is not an integer)<br>\n";
exit;
}
ProcessOneBug($bugnum);
1999-10-11 22:18:39 +04:00
}
1999-05-12 09:22:36 +04:00
1998-09-16 01:49:26 +04:00
exit;