~ubuntu-branches/ubuntu/hardy/bugzilla/hardy-security

« back to all changes in this revision

Viewing changes to processmail

  • Committer: Bazaar Package Importer
  • Author(s): Rémi Perrot
  • Date: 2004-04-02 01:13:32 UTC
  • Revision ID: james.westby@ubuntu.com-20040402011332-hxrg0n2szimd7d25
Tags: upstream-2.16.5
Import upstream version 2.16.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bonsaitools/bin/perl -wT
 
2
# -*- Mode: perl; indent-tabs-mode: nil -*-
 
3
#
 
4
# The contents of this file are subject to the Mozilla Public
 
5
# License Version 1.1 (the "License"); you may not use this file
 
6
# except in compliance with the License. You may obtain a copy of
 
7
# the License at http://www.mozilla.org/MPL/
 
8
#
 
9
# Software distributed under the License is distributed on an "AS
 
10
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 
11
# implied. See the License for the specific language governing
 
12
# rights and limitations under the License.
 
13
#
 
14
# The Original Code is the Bugzilla Bug Tracking System.
 
15
#
 
16
# The Initial Developer of the Original Code is Netscape Communications
 
17
# Corporation. Portions created by Netscape are
 
18
# Copyright (C) 1998 Netscape Communications Corporation. All
 
19
# Rights Reserved.
 
20
#
 
21
# Contributor(s): Terry Weissman <terry@mozilla.org>,
 
22
#                 Bryce Nesbitt <bryce-mozilla@nextbus.com>
 
23
#                 Dan Mosedale <dmose@mozilla.org>
 
24
#                 Alan Raetz <al_raetz@yahoo.com>
 
25
#                 Jacob Steenhagen <jake@actex.net>
 
26
#                 Matthew Tuck <matty@chariot.net.au>
 
27
 
 
28
use diagnostics;
 
29
use strict;
 
30
use lib ".";
 
31
 
 
32
require "globals.pl";
 
33
 
 
34
use RelationSet;
 
35
 
 
36
 
 
37
# Shut up misguided -w warnings about "used only once".
 
38
sub processmail_sillyness {
 
39
    my $zz;
 
40
    $zz = $::db;
 
41
}
 
42
 
 
43
$| = 1;
 
44
 
 
45
umask(0);
 
46
 
 
47
my $nametoexclude = "";
 
48
my %nomail;
 
49
 
 
50
my @excludedAddresses = ();
 
51
 
 
52
# disable email flag for offline debugging work
 
53
my $enableSendMail = 1;
 
54
 
 
55
my %force;
 
56
@{$force{'QAcontact'}} = ();
 
57
@{$force{'Owner'}} = ();
 
58
@{$force{'Reporter'}} = ();
 
59
@{$force{'CClist'}} = ();
 
60
@{$force{'Voter'}} = ();
 
61
 
 
62
 
 
63
my %seen;
 
64
my @sentlist;
 
65
 
 
66
sub FormatTriple {
 
67
    my ($a, $b, $c) = (@_);
 
68
    $^A = "";
 
69
    my $temp = formline << 'END', $a, $b, $c;
 
70
^>>>>>>>>>>>>>>>>>>|^<<<<<<<<<<<<<<<<<<<<<<<<<<<|^<<<<<<<<<<<<<<<<<<<<<<<<<<<~~
 
71
END
 
72
    ; # This semicolon appeases my emacs editor macros. :-)
 
73
    return $^A;
 
74
}
 
75
    
 
76
sub FormatDouble {
 
77
    my ($a, $b) = (@_);
 
78
    $a .= ":";
 
79
    $^A = "";
 
80
    my $temp = formline << 'END', $a, $b;
 
81
^>>>>>>>>>>>>>>>>>> ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~~
 
82
END
 
83
    ; # This semicolon appeases my emacs editor macros. :-)
 
84
    return $^A;
 
85
}
 
86
    
 
87
 
 
88
sub ProcessOneBug {
 
89
    my ($id) = (@_);
 
90
 
 
91
    my @headerlist;
 
92
    my %values;
 
93
    my %defmailhead;
 
94
    my %fielddescription;
 
95
 
 
96
    my $msg = "";
 
97
 
 
98
    SendSQL("SELECT name, description, mailhead FROM fielddefs " .
 
99
            "ORDER BY sortkey");
 
100
    while (MoreSQLData()) {
 
101
        my ($field, $description, $mailhead) = (FetchSQLData());
 
102
        push(@headerlist, $field);
 
103
        $defmailhead{$field} = $mailhead;
 
104
        $fielddescription{$field} = $description;
 
105
    }
 
106
    SendSQL("SELECT " . join(',', @::log_columns) . ", lastdiffed, now() " .
 
107
            "FROM bugs WHERE bug_id = $id");
 
108
    my @row = FetchSQLData();
 
109
    foreach my $i (@::log_columns) {
 
110
        $values{$i} = shift(@row);
 
111
    }
 
112
    my ($start, $end) = (@row);
 
113
    # $start and $end are considered safe because users can't touch them
 
114
    trick_taint($start);
 
115
    trick_taint($end);
 
116
 
 
117
    my $ccSet = new RelationSet();
 
118
    $ccSet->mergeFromDB("SELECT who FROM cc WHERE bug_id = $id");
 
119
    $values{'cc'} = $ccSet->toString();
 
120
    
 
121
    my @voterList;
 
122
    SendSQL("SELECT profiles.login_name FROM votes, profiles " .
 
123
            "WHERE votes.bug_id = $id AND profiles.userid = votes.who");
 
124
    while (MoreSQLData()) {
 
125
        push(@voterList, FetchOneColumn());
 
126
    }
 
127
 
 
128
    $values{'assigned_to'} = DBID_to_name($values{'assigned_to'});
 
129
    $values{'reporter'} = DBID_to_name($values{'reporter'});
 
130
    if ($values{'qa_contact'}) {
 
131
        $values{'qa_contact'} = DBID_to_name($values{'qa_contact'});
 
132
    }
 
133
 
 
134
    my @diffs;
 
135
 
 
136
 
 
137
    SendSQL("SELECT profiles.login_name, fielddefs.description, " .
 
138
            "       bug_when, removed, added, attach_id " .
 
139
            "FROM bugs_activity, fielddefs, profiles " .
 
140
            "WHERE bug_id = $id " .
 
141
            "  AND fielddefs.fieldid = bugs_activity.fieldid " .
 
142
            "  AND profiles.userid = who " .
 
143
            "  AND bug_when > '$start' " .
 
144
            "  AND bug_when <= '$end' " .
 
145
            "ORDER BY bug_when"
 
146
            );
 
147
 
 
148
    while (MoreSQLData()) {
 
149
        my @row = FetchSQLData();
 
150
        push(@diffs, \@row);
 
151
    }
 
152
 
 
153
    my $difftext = "";
 
154
    my $lastwho = "";
 
155
    foreach my $ref (@diffs) {
 
156
        my ($who, $what, $when, $old, $new, $attachid) = (@$ref);
 
157
        if ($who ne $lastwho) {
 
158
            $lastwho = $who;
 
159
            $difftext .= "\n$who" . Param('emailsuffix') . " changed:\n\n";
 
160
            $difftext .= FormatTriple("What    ", "Removed", "Added");
 
161
            $difftext .= ('-' x 76) . "\n";
 
162
        }
 
163
        $what =~ s/^Attachment/Attachment #$attachid/ if $attachid;
 
164
        $difftext .= FormatTriple($what, $old, $new);
 
165
    }
 
166
 
 
167
    $difftext = trim($difftext);
 
168
 
 
169
 
 
170
    my $deptext = "";
 
171
 
 
172
    my $resid = 
 
173
 
 
174
    SendSQL("SELECT bugs_activity.bug_id, bugs.short_desc, fielddefs.name, " .
 
175
            "       removed, added " .
 
176
            "FROM bugs_activity, bugs, dependencies, fielddefs ".
 
177
            "WHERE bugs_activity.bug_id = dependencies.dependson " .
 
178
            "  AND bugs.bug_id = bugs_activity.bug_id ".
 
179
            "  AND dependencies.blocked = $id " .
 
180
            "  AND fielddefs.fieldid = bugs_activity.fieldid" .
 
181
            "  AND (fielddefs.name = 'bug_status' " .
 
182
            "    OR fielddefs.name = 'resolution') " .
 
183
            "  AND bug_when > '$start' " .
 
184
            "  AND bug_when <= '$end' " .
 
185
            "ORDER BY bug_when, bug_id");
 
186
    
 
187
    my $thisdiff = "";
 
188
    my $lastbug = "";
 
189
    my $interestingchange = 0;
 
190
    my $depbug = 0;
 
191
    my @depbugs;
 
192
    while (MoreSQLData()) {
 
193
        my ($summary, $what, $old, $new);
 
194
        ($depbug, $summary, $what, $old, $new) = (FetchSQLData());
 
195
        if ($depbug ne $lastbug) {
 
196
            if ($interestingchange) {
 
197
                $deptext .= $thisdiff;
 
198
            }
 
199
            $lastbug = $depbug;
 
200
            my $urlbase = Param("urlbase");
 
201
            $thisdiff =
 
202
              "\nBug $id depends on bug $depbug, which changed state.\n\n" . 
 
203
              "Bug $depbug Summary: $summary\n" . 
 
204
              "${urlbase}show_bug.cgi?id=$depbug\n\n"; 
 
205
            $thisdiff .= FormatTriple("What    ", "Old Value", "New Value");
 
206
            $thisdiff .= ('-' x 76) . "\n";
 
207
            $interestingchange = 0;
 
208
        }
 
209
        $thisdiff .= FormatTriple($fielddescription{$what}, $old, $new);
 
210
        if ($what eq 'bug_status' && IsOpenedState($old) ne IsOpenedState($new)) {
 
211
            $interestingchange = 1;
 
212
        }
 
213
        
 
214
        push(@depbugs, $depbug);
 
215
    }
 
216
    
 
217
    if ($interestingchange) {
 
218
        $deptext .= $thisdiff;
 
219
    }
 
220
 
 
221
    $deptext = trim($deptext);
 
222
 
 
223
    if ($deptext) {
 
224
        $difftext = trim($difftext . "\n\n" . $deptext);
 
225
    }
 
226
 
 
227
 
 
228
    my $newcomments = GetLongDescriptionAsText($id, $start, $end);
 
229
 
 
230
    #
 
231
    # Start of email filtering code
 
232
    #
 
233
    my $count = 0;
 
234
 
 
235
    my @currentEmailAttributes = getEmailAttributes($newcomments, @diffs);
 
236
    my (@assigned_toList,@reporterList,@qa_contactList,@ccList) = ();
 
237
 
 
238
    #open(LOG, ">>/tmp/maillog");
 
239
    #print LOG "\nBug ID: $id   CurrentEmailAttributes:";
 
240
    #print LOG join(',', @currentEmailAttributes) . "\n";
 
241
 
 
242
    @excludedAddresses = (); # zero out global list 
 
243
 
 
244
    @assigned_toList = filterEmailGroup('Owner',
 
245
                                        \@currentEmailAttributes,
 
246
                                        $values{'assigned_to'});
 
247
    @reporterList = filterEmailGroup('Reporter', 
 
248
                                     \@currentEmailAttributes,
 
249
                                     $values{'reporter'});
 
250
    if (Param('useqacontact') && $values{'qa_contact'}) {
 
251
        @qa_contactList = filterEmailGroup('QAcontact',
 
252
                                           \@currentEmailAttributes,
 
253
                                           $values{'qa_contact'});
 
254
    } else { 
 
255
        @qa_contactList = (); 
 
256
    }
 
257
 
 
258
    @ccList = filterEmailGroup('CClist', \@currentEmailAttributes,
 
259
                               $values{'cc'});
 
260
 
 
261
    @voterList = filterEmailGroup('Voter', \@currentEmailAttributes,
 
262
                                  join(',',@voterList));
 
263
 
 
264
    my @emailList = (@assigned_toList, @reporterList, 
 
265
                     @qa_contactList, @ccList, @voterList);
 
266
 
 
267
    # only need one entry per person
 
268
    my @allEmail = ();
 
269
    my %AlreadySeen = ();
 
270
    foreach my $person (@emailList) {
 
271
        if ( !($AlreadySeen{$person}) ) {
 
272
            push(@allEmail,$person);
 
273
            $AlreadySeen{$person}++;
 
274
        }
 
275
    }
 
276
 
 
277
    #print LOG "\nbug $id email sent: " . join(',', @allEmail) . "\n";
 
278
        
 
279
    @excludedAddresses = filterExcludeList(\@excludedAddresses,
 
280
                                           \@allEmail);
 
281
 
 
282
    # print LOG "excluded: " . join(',',@excludedAddresses) . "\n\n";
 
283
 
 
284
    foreach my $person ( @allEmail ) {
 
285
        my @reasons;
 
286
 
 
287
        $count++;
 
288
 
 
289
        push(@reasons, 'AssignedTo') if lsearch(\@assigned_toList, $person) != -1;
 
290
        push(@reasons, 'Reporter') if lsearch(\@reporterList, $person) != -1;
 
291
        push(@reasons, 'QAContact') if lsearch(\@qa_contactList, $person) != -1;
 
292
        push(@reasons, 'CC') if lsearch(\@ccList, $person) != -1;
 
293
        push(@reasons, 'Voter') if lsearch(\@voterList, $person) != -1;
 
294
 
 
295
        if ( !defined(NewProcessOnePerson($person, $count, \@headerlist,
 
296
                                          \@reasons, \%values,
 
297
                                          \%defmailhead, 
 
298
                                          \%fielddescription, $difftext, 
 
299
                                          $newcomments, $start, $id, 
 
300
                                          \@depbugs))) 
 
301
        {
 
302
 
 
303
            # if a value is not returned, this means that the person
 
304
            # was not sent mail.  add them to the excludedAddresses list.
 
305
            # it will be filtered later for dups.
 
306
            #
 
307
            push @excludedAddresses, $person;
 
308
 
 
309
        }
 
310
    }
 
311
 
 
312
 
 
313
    SendSQL("UPDATE bugs SET lastdiffed = '$end', delta_ts = delta_ts " .
 
314
            "WHERE bug_id = $id");
 
315
 
 
316
    # Filter the exclude list for dupes one last time
 
317
    @excludedAddresses = filterExcludeList(\@excludedAddresses,
 
318
                                           \@sentlist);
 
319
    if (@sentlist) {
 
320
        print "<b>Email sent to:</b> " . join(", ", @sentlist) ."<br>\n";
 
321
    } else {
 
322
        print "<b>Email sent to:</b> no one<br>\n";
 
323
    }
 
324
 
 
325
    if (@excludedAddresses) {
 
326
        print "<b>Excluding:</b> " . join(", ", @excludedAddresses) . "\n";
 
327
    }
 
328
 
 
329
    print "<br><center>If you wish to tweak the kinds of mail Bugzilla sends you, you can";
 
330
    print " <a href=\"userprefs.cgi?tab=email\">change your preferences</a></center>\n";
 
331
 
 
332
}
 
333
 
 
334
# When one person is in different fields on one bug, they may be
 
335
# excluded from email because of one relationship to the bug (eg
 
336
# they're the QA contact) but included because of another (eg they
 
337
# also reported the bug).  Inclusion takes precedence, so this
 
338
# function looks for and removes any users from the exclude list who
 
339
# are also on the include list.  Additionally, it removes duplicate
 
340
# entries from the exclude list.  
 
341
#
 
342
# Arguments are the exclude list and the include list; the cleaned up
 
343
# exclude list is returned.
 
344
#
 
345
sub filterExcludeList ($$) {
 
346
 
 
347
    if ($#_ != 1) {
 
348
        die ("filterExcludeList called with wrong number of args");
 
349
    }
 
350
 
 
351
    my ($refExcluded, $refAll) = @_;
 
352
 
 
353
    my @excludedAddrs = @$refExcluded;
 
354
    my @allEmail = @$refAll;
 
355
    my @tmpList = @excludedAddrs;
 
356
    my (@result,@uniqueResult) = ();
 
357
    my %alreadySeen;
 
358
 
 
359
    foreach my $excluded (@tmpList) {
 
360
 
 
361
        push (@result,$excluded);
 
362
        foreach my $included (@allEmail) {
 
363
 
 
364
            # match found, so we remove the entry
 
365
            if ($included eq $excluded) {
 
366
                pop(@result);
 
367
                last;
 
368
            }
 
369
        }
 
370
    }
 
371
 
 
372
    # only need one entry per person
 
373
    foreach my $person (@result) {
 
374
        if ( !($alreadySeen{$person}) ) {
 
375
            push(@uniqueResult,$person);
 
376
            $alreadySeen{$person}++;
 
377
        }
 
378
    }
 
379
 
 
380
    return @uniqueResult;
 
381
}
 
382
 
 
383
# if the Status was changed to Resolved or Verified
 
384
#       set the Resolved flag
 
385
#
 
386
# else if Severity, Status OR Priority fields have any change
 
387
#       set the Status flag
 
388
#
 
389
# else if Keywords has changed
 
390
#       set the Keywords flag
 
391
#
 
392
# else if CC has changed
 
393
#       set the CC flag
 
394
#
 
395
# if the Comments field shows an attachment
 
396
#       set the Attachment flag
 
397
#
 
398
# else if Comments exist
 
399
#       set the Comments flag
 
400
#
 
401
# if no flags are set and there was some other field change
 
402
#       set the Status flag
 
403
#
 
404
sub getEmailAttributes ($@) {
 
405
    
 
406
    my ($commentField,@fieldDiffs) = @_;
 
407
    my (@flags,@uniqueFlags,%alreadySeen) = ();
 
408
    
 
409
    foreach my $ref (@fieldDiffs) {
 
410
        my ($who, $fieldName, $when, $old, $new) = (@$ref);
 
411
        
 
412
        #print qq{field: $fieldName $new<br>};
 
413
        
 
414
        # the STATUS will be flagged for Severity, Status and 
 
415
        # Priority changes
 
416
        #
 
417
        if ( $fieldName eq 'Status') {
 
418
            if ($new eq 'RESOLVED' || $new eq 'VERIFIED') {
 
419
                push (@flags, 'Resolved');
 
420
            }
 
421
        }
 
422
        elsif ( $fieldName eq 'Severity' || $fieldName eq 'Status' ||
 
423
                $fieldName eq 'Priority' ) {
 
424
            push (@flags, 'Status');
 
425
        } elsif ( $fieldName eq 'Keywords') {
 
426
            push (@flags, 'Keywords');
 
427
        } elsif ( $fieldName eq 'CC') {
 
428
            push (@flags, 'CC');
 
429
        }
 
430
 
 
431
        # These next few lines are for finding out who's been added
 
432
        # to the Owner, QA, CC, etc. fields.  It does not effect
 
433
        # the @flags array at all, but is run here because it does
 
434
        # effect filtering later and we're already in the loop.
 
435
        if ($fieldName eq 'Owner') {
 
436
            push (@{$force{'Owner'}}, $new);
 
437
        } elsif ($fieldName eq 'QAContact') {
 
438
           push (@{$force{'QAContact'}}, $new);
 
439
        } elsif ($fieldName eq 'CC') {
 
440
            my @added = split (/[ ,]/, $new);
 
441
            push (@{$force{'CClist'}}, @added);
 
442
        }
 
443
    }
 
444
    
 
445
    if ( $commentField =~ /Created an attachment \(/ ) {
 
446
        push (@flags, 'Attachments');
 
447
    }
 
448
    elsif ( ($commentField ne '') && !(scalar(@flags) == 1 && $flags[0] eq 'Resolved')) {
 
449
        push (@flags, 'Comments');
 
450
    }
 
451
    
 
452
    # default fallthrough for any unflagged change is 'Other'
 
453
    if ( @flags == 0 && @fieldDiffs != 0 ) {
 
454
        push (@flags, 'Other');
 
455
    }
 
456
    
 
457
    # only need one flag per attribute type
 
458
    foreach my $flag (@flags) {
 
459
        if ( !($alreadySeen{$flag}) ) {
 
460
            push(@uniqueFlags,$flag);
 
461
            $alreadySeen{$flag}++;
 
462
        }
 
463
    }
 
464
    #print "\nEmail Attributes: ", join(' ,',@uniqueFlags), "<br>\n";
 
465
    
 
466
    # catch-all default, just in case the above logic is faulty
 
467
    if ( @uniqueFlags == 0) {
 
468
        push (@uniqueFlags, 'Comments');
 
469
    }
 
470
    
 
471
    return @uniqueFlags;
 
472
}
 
473
 
 
474
sub filterEmailGroup ($$$) {
 
475
    
 
476
    my ($emailGroup,$refAttributes,$emailList) = @_;
 
477
    my @emailAttributes = @$refAttributes;
 
478
    my @emailList = split(/,/,$emailList);
 
479
    my @filteredList = ();
 
480
    
 
481
 
 
482
    # the force list for this email group needs to be checked as well
 
483
    #
 
484
    push @emailList, @{$force{$emailGroup}};
 
485
 
 
486
    # Check this user for any watchers... doing this here allows them to inhert the
 
487
    # relationship to the bug of the person they are watching (if the person they
 
488
    # are watching is an owner, their mail is filtered as if they were the owner).
 
489
    if (Param("supportwatchers")) {
 
490
        my @watchers;
 
491
        foreach my $person(@emailList) {
 
492
            my $personId = DBname_to_id($person);
 
493
            SendSQL("SELECT watcher FROM watch WHERE watched = $personId");
 
494
            while(MoreSQLData()) {
 
495
                my ($watcher) = FetchSQLData();
 
496
                if ($watcher) {
 
497
                    push (@watchers, DBID_to_name($watcher));
 
498
                }
 
499
            }
 
500
        }
 
501
        push(@emailList, @watchers);
 
502
    }
 
503
 
 
504
 
 
505
    foreach my $person (@emailList) {
 
506
        
 
507
        my $lastCount = @filteredList;
 
508
 
 
509
        if ( $person eq '' ) { next; }
 
510
 
 
511
        my $userid = DBname_to_id($person);
 
512
 
 
513
        if ( ! $userid ) {
 
514
            push(@filteredList,$person);
 
515
            next;
 
516
        }
 
517
        
 
518
        SendSQL("SELECT emailflags FROM profiles WHERE " .
 
519
                "userid = $userid" );
 
520
 
 
521
        my ($userFlagString) = FetchSQLData();
 
522
        
 
523
        # If the sender doesn't want email, exclude them from list
 
524
        
 
525
        if (lc($person) eq $nametoexclude) {
 
526
            
 
527
            if ( defined ($userFlagString) && 
 
528
                 $userFlagString =~ /ExcludeSelf\~on/ ) {
 
529
                
 
530
                push (@excludedAddresses,$person);
 
531
                next;
 
532
            }
 
533
        }
 
534
        
 
535
        # if the users database entry is empty, send them all email
 
536
        # by default (they have not accessed userprefs.cgi recently).
 
537
        
 
538
        if ( !defined($userFlagString) || !($userFlagString =~ /email/) ) {
 
539
            push(@filteredList,$person);
 
540
        }
 
541
        else {
 
542
 
 
543
            # the 255 param is here, because without a third param, 
 
544
            # split will trim any trailing null fields, which causes perl 
 
545
            # to eject lots of warnings.  any suitably large number would 
 
546
            # do.
 
547
                
 
548
            my %userFlags = split(/~/, $userFlagString, 255);
 
549
 
 
550
            # The default condition is to send each person email.
 
551
            # If we match the email attribute with the user flag, and
 
552
            # they do not want email, then remove them from the list.
 
553
 
 
554
            push(@filteredList,$person);            
 
555
 
 
556
            my $detectedOn = 0;
 
557
            
 
558
            foreach my $attribute (@emailAttributes) {
 
559
 
 
560
                my $matchName = 'email' . $emailGroup . $attribute;
 
561
                
 
562
                # **** Kludge... quick and dirty fix for 2.12
 
563
                #      http://bugzilla.mozilla.org/show_bug.cgi?id=73665
 
564
                # If this pref is new (it's been added since this user
 
565
                # last updated their filtering prefs, $userFlags{$matchName}
 
566
                # will be undefined.  This should be considered a match
 
567
                # so that new prefs will default to 'on'
 
568
                if (!defined($userFlags{$matchName})) {
 
569
                    $detectedOn = 1;
 
570
                }
 
571
 
 
572
                while ((my $flagName, my $flagValue) = each %userFlags) {
 
573
                    
 
574
                    if ($flagName !~ /$emailGroup/) { 
 
575
                        next; 
 
576
                    }
 
577
 
 
578
                    if ($flagName eq $matchName){
 
579
                        if ($flagValue eq 'on') {
 
580
                            $detectedOn = 1;
 
581
                        }
 
582
                    }
 
583
 
 
584
                } # for each userFlag
 
585
 
 
586
            } # for each email attribute
 
587
 
 
588
            # if the current flag hasn't been detected on at least once, 
 
589
            # this person gets filtered from this group.
 
590
            #
 
591
            if (! $detectedOn) {
 
592
                pop(@filteredList);
 
593
            }
 
594
 
 
595
            # check to see if the person was added to or removed from  
 
596
            # this email group.
 
597
            # Note: This was originally written as only removed from
 
598
            # and was rewritten to be Added/Removed, but for simplicity
 
599
            # sake, the name "Removeme" wasn't changed.
 
600
            # http://bugzilla.mozilla.org/show_bug.cgi?id=71912 
 
601
 
 
602
            if ( grep ($_ eq $person, @{$force{$emailGroup}} ) ) {
 
603
 
 
604
                # if so, see if they want mail about that
 
605
                #
 
606
                if ( $userFlags{'email' . $emailGroup . 'Removeme'} eq 'on' ) {
 
607
 
 
608
                    # we definitely want mail sent to this person, since
 
609
                    # inclusion on a mail takes precedence over the previous
 
610
                    # exclusion
 
611
 
 
612
                    # have they been filtered for some other reason?
 
613
                    #
 
614
                    if (@filteredList == $lastCount) {
 
615
                        
 
616
                        # if so, put them back
 
617
                        #
 
618
                        push (@filteredList, $person);
 
619
                    }
 
620
                }
 
621
            }
 
622
 
 
623
        } # if $userFlagString is valid
 
624
 
 
625
        # has the person been moved off the filtered list?
 
626
        #
 
627
        if (@filteredList == $lastCount ) {
 
628
 
 
629
            # mark them as excluded
 
630
            #
 
631
            push (@excludedAddresses,$person);
 
632
        } 
 
633
            
 
634
    } # for each person
 
635
 
 
636
    return @filteredList;
 
637
}
 
638
 
 
639
sub NewProcessOnePerson ($$$$$$$$$$$$) {
 
640
    my ($person, $count, $hlRef, $reasonsRef, $valueRef, $dmhRef, $fdRef, $difftext, 
 
641
        $newcomments, $start, $id, $depbugsRef) = @_;
 
642
 
 
643
    my %values = %$valueRef;
 
644
    my @headerlist = @$hlRef;
 
645
    my @reasons = @$reasonsRef;
 
646
    my %defmailhead = %$dmhRef;
 
647
    my %fielddescription = %$fdRef;
 
648
    my @depbugs = @$depbugsRef;
 
649
    
 
650
    if ($seen{$person}) {
 
651
      return;
 
652
    }
 
653
 
 
654
    if ($nomail{$person}) {
 
655
      return;
 
656
    }
 
657
 
 
658
        
 
659
    SendSQL("SELECT userid, groupset " .
 
660
            "FROM profiles WHERE login_name = " . SqlQuote($person));
 
661
    my ($userid, $groupset) =  (FetchSQLData());
 
662
 
 
663
    $seen{$person} = 1;
 
664
 
 
665
    detaint_natural($userid);
 
666
    detaint_natural($groupset);
 
667
 
 
668
    # if this person doesn't have permission to see info on this bug, 
 
669
    # return.
 
670
    #
 
671
    # XXX - This currently means that if a bug is suddenly given
 
672
    # more restrictive permissions, people without those permissions won't
 
673
    # see the action of restricting the bug itself; the bug will just 
 
674
    # quietly disappear from their radar.
 
675
    #
 
676
    return unless CanSeeBug($id, $userid, $groupset);
 
677
    
 
678
    # We shouldn't send changedmail if this is a dependency mail, and any of 
 
679
    # the depending bugs is not visible to the user.
 
680
    foreach my $dep_id (@depbugs) {
 
681
        my $save_id = $dep_id;
 
682
        detaint_natural($dep_id) || warn("Unexpected Error: \@depbugs contains a non-numeric value: '$save_id'")
 
683
                                 && return;
 
684
        return unless CanSeeBug($dep_id, $userid, $groupset);
 
685
    }
 
686
 
 
687
    my %mailhead = %defmailhead;
 
688
    
 
689
    my $head = "";
 
690
    
 
691
    foreach my $f (@headerlist) {
 
692
      if ($mailhead{$f}) {
 
693
        my $value = $values{$f};
 
694
        # If there isn't anything to show, don't include this header
 
695
        if (! $value) {
 
696
          next;
 
697
        }
 
698
        my $desc = $fielddescription{$f};
 
699
        $head .= FormatDouble($desc, $value);
 
700
      }
 
701
    }
 
702
    
 
703
    if ($difftext eq "" && $newcomments eq "") {
 
704
      # Whoops, no differences!
 
705
      return;
 
706
    }
 
707
    
 
708
    my $reasonsbody = "------- You are receiving this mail because: -------\n";
 
709
 
 
710
    if (scalar(@reasons) == 0) {
 
711
        $reasonsbody .= "Whoops!  I have no idea!\n";
 
712
    } else {
 
713
        foreach my $reason (@reasons) {
 
714
            if ($reason eq 'AssignedTo') {
 
715
                $reasonsbody .= "You are the assignee for the bug, or are watching the assignee.\n";
 
716
            } elsif ($reason eq 'Reporter') {
 
717
                $reasonsbody .= "You reported the bug, or are watching the reporter.\n";
 
718
            } elsif ($reason eq 'QAContact') {
 
719
                $reasonsbody .= "You are the QA contact for the bug, or are watching the QA contact.\n";
 
720
            } elsif ($reason eq 'CC') {
 
721
                $reasonsbody .= "You are on the CC list for the bug, or are watching someone who is.\n";
 
722
            } elsif ($reason eq 'Voter') {
 
723
                $reasonsbody .= "You are a voter for the bug, or are watching someone who is.\n";
 
724
            } else {
 
725
                $reasonsbody .= "Whoops!  There is an unknown reason!\n";
 
726
            }
 
727
        }
 
728
    }
 
729
 
 
730
    my $isnew = ($start !~ m/[1-9]/);
 
731
    
 
732
    my %substs;
 
733
 
 
734
    # If an attachment was created, then add an URL. (Note: the 'g'lobal
 
735
    # replace should work with comments with multiple attachments.)
 
736
 
 
737
    if ( $newcomments =~ /Created an attachment \(/ ) {
 
738
 
 
739
        my $showattachurlbase =
 
740
            Param('urlbase') . "attachment.cgi?id=";
 
741
 
 
742
        $newcomments =~ s/(Created an attachment \(id=([0-9]+)\))/$1\n --> \(${showattachurlbase}$2&action=view\)/g;
 
743
    }
 
744
 
 
745
    $person .= Param('emailsuffix');
 
746
# 09/13/2000 cyeh@bluemartini.com
 
747
# If a bug is changed, don't put the word "Changed" in the subject mail
 
748
# since if the bug didn't change, you wouldn't be getting mail
 
749
# in the first place! see http://bugzilla.mozilla.org/show_bug.cgi?id=29820 
 
750
# for details.
 
751
    $substs{"neworchanged"} = $isnew ? 'New: ' : '';
 
752
    $substs{"to"} = $person;
 
753
    $substs{"cc"} = '';
 
754
    $substs{"bugid"} = $id;
 
755
    if ($isnew) {
 
756
      $substs{"diffs"} = $head . "\n\n" . $newcomments;
 
757
    } else {
 
758
      $substs{"diffs"} = $difftext . "\n\n" . $newcomments;
 
759
    }
 
760
    $substs{"summary"} = $values{'short_desc'};
 
761
    $substs{"reasonsheader"} = join(" ", @reasons);
 
762
    $substs{"reasonsbody"} = $reasonsbody;
 
763
    
 
764
    my $template = Param("newchangedmail");
 
765
    
 
766
    my $msg = PerformSubsts($template, \%substs);
 
767
 
 
768
    my $sendmailparam = "-ODeliveryMode=deferred";
 
769
    if (Param("sendmailnow")) {
 
770
       $sendmailparam = "";
 
771
    }
 
772
 
 
773
    if ($enableSendMail == 1) {
 
774
    open(SENDMAIL, "|/usr/lib/sendmail $sendmailparam -t -i") ||
 
775
      die "Can't open sendmail";
 
776
    
 
777
    print SENDMAIL trim($msg) . "\n";
 
778
    close SENDMAIL;
 
779
    }
 
780
    push(@sentlist, $person);
 
781
    return 1;
 
782
}
 
783
 
 
784
# Code starts here
 
785
 
 
786
ConnectToDatabase();
 
787
# Set Taint mode for the SQL
 
788
$::db->{Taint} = 1;
 
789
# ^^^ Taint mode is still a work in progress...
 
790
GetVersionTable();
 
791
 
 
792
if (open(FID, "<data/nomail")) {
 
793
    while (<FID>) {
 
794
        $nomail{trim($_)} = 1;
 
795
    }
 
796
    close FID;
 
797
}
 
798
 
 
799
if ($#ARGV >= 0 && $ARGV[0] eq "regenerate") {
 
800
    print "Regenerating is no longer required or supported\n";
 
801
    exit;
 
802
}
 
803
 
 
804
if ($#ARGV >= 0 && $ARGV[0] eq "-forcecc") {
 
805
    shift(@ARGV);
 
806
    foreach my $i (split(/,/, shift(@ARGV))) {
 
807
        push(@{$force{'CClist'}}, trim($i));
 
808
    }
 
809
}
 
810
 
 
811
if ($#ARGV >= 0 && $ARGV[0] eq "-forceowner") {
 
812
    shift(@ARGV);
 
813
    @{$force{'Owner'}} = (trim(shift(@ARGV)));
 
814
}
 
815
 
 
816
if ($#ARGV >= 0 && $ARGV[0] eq "-forceqacontact") {
 
817
    shift(@ARGV);
 
818
    @{$force{'QAcontact'}} = (trim(shift(@ARGV)));
 
819
}
 
820
 
 
821
if ($#ARGV >= 0 && $ARGV[0] eq "-forcereporter") {
 
822
    shift(@ARGV);
 
823
    @{$force{'Reporter'}} = trim(shift(@ARGV));
 
824
}
 
825
 
 
826
if (($#ARGV < 0) || ($#ARGV > 1)) {
 
827
    print "Usage:\n processmail {bugid} {nametoexclude} " . 
 
828
      "[-forcecc list,of,users]\n             [-forceowner name] " .
 
829
      "[-forceqacontact name]\n             [-forcereporter name]\nor\n" .
 
830
      " processmail rescanall\n";
 
831
    exit;
 
832
}
 
833
 
 
834
if ($#ARGV == 1) {
 
835
    $nametoexclude = lc($ARGV[1]);
 
836
}
 
837
 
 
838
if ($ARGV[0] eq "rescanall") {
 
839
    print "Collecting bug ids...\n";
 
840
    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");
 
841
    my @list;
 
842
    while (my @row = FetchSQLData()) {
 
843
        my $time = $row[2];
 
844
        if ($time =~ /^(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/) {
 
845
            $time = "$1-$2-$3 $4:$5:$6";
 
846
        }
 
847
        print STDERR "Bug $row[0] has unsent mail. lastdiffed is $row[1], delta_ts is $time.\n";
 
848
        push @list, $row[0];
 
849
    }
 
850
    if (scalar(@list) > 0) {
 
851
        print STDERR scalar(@list) . " bugs found with possibly unsent mail\n";
 
852
        print STDERR "Updating bugs, sending mail if required\n";
 
853
    } else {
 
854
        print "All appropriate mail appears to have been sent\n"
 
855
    }
 
856
    foreach my $id (@list) {
 
857
        %seen = ();
 
858
        if (detaint_natural($id)) {
 
859
            ProcessOneBug($id);
 
860
        }
 
861
    }
 
862
} else {
 
863
    my $bugnum;
 
864
    if ($ARGV[0] =~ m/^([1-9][0-9]*)$/) {
 
865
        $bugnum = $1;
 
866
    } else {
 
867
        print "Error calling processmail (bug id is not an integer)<br>\n";
 
868
        exit;
 
869
    }
 
870
    ProcessOneBug($bugnum);
 
871
}
 
872
 
 
873
exit;