]> git.donarmstrong.com Git - debbugs.git/blob - Debbugs/Recipients.pm
merge changes from dla source
[debbugs.git] / Debbugs / Recipients.pm
1 # This module is part of debbugs, and is released
2 # under the terms of the GPL version 2, or any later version. See the
3 # file README and COPYING for more information.
4 # Copyright 2008 by Don Armstrong <don@donarmstrong.com>.
5 # $Id: perl_module_header.pm 1221 2008-05-19 15:00:40Z don $
6
7 package Debbugs::Recipients;
8
9 =head1 NAME
10
11 Debbugs::Recipients -- Determine recipients of messages from the bts
12
13 =head1 SYNOPSIS
14
15
16 =head1 DESCRIPTION
17
18
19 =head1 BUGS
20
21 None known.
22
23 =cut
24
25 use warnings;
26 use strict;
27 use vars qw($VERSION $DEBUG %EXPORT_TAGS @EXPORT_OK @EXPORT);
28 use base qw(Exporter);
29
30 BEGIN{
31      ($VERSION) = q$Revision: 1221 $ =~ /^Revision:\s+([^\s+])/;
32      $DEBUG = 0 unless defined $DEBUG;
33
34      @EXPORT = ();
35      %EXPORT_TAGS = (add    => [qw(add_recipients)],
36                      det    => [qw(determine_recipients)],
37                     );
38      @EXPORT_OK = ();
39      Exporter::export_ok_tags(keys %EXPORT_TAGS);
40      $EXPORT_TAGS{all} = [@EXPORT_OK];
41
42 }
43
44 use Debbugs::Config qw(:config);
45 use Params::Validate qw(:types validate_with);
46 use Debbugs::Common qw(:misc :util);
47 use Debbugs::Status qw(splitpackages isstrongseverity);
48
49 use Debbugs::Packages qw(binarytosource);
50
51 use Debbugs::Mail qw(get_addresses);
52
53 use Carp;
54
55 =head2 add_recipients
56
57      add_recipients(data => $data,
58                     recipients => \%recipients;
59                    );
60
61 Given data (from read_bug or similar) (or an arrayref of data),
62 calculates the addresses which need to receive mail involving this
63 bug.
64
65 =over
66
67 =item data -- Data from read_bug or similar; can be an arrayref of data
68
69 =item recipients -- hashref of recipient data structure; pass to
70 subsequent calls of add_recipients or
71
72 =item debug -- optional 
73
74
75 =back
76
77 =cut
78
79
80 sub add_recipients {
81      # Data structure is:
82      #   maintainer email address &c -> assoc of packages -> assoc of bug#'s
83      my %param = validate_with(params => \@_,
84                                spec   => {data => {type => HASHREF|ARRAYREF,
85                                                   },
86                                           recipients => {type => HASHREF,
87                                                         },
88                                           debug => {type => HANDLE|SCALARREF,
89                                                     optional => 1,
90                                                    },
91                                           transcript => {type => HANDLE|SCALARREF,
92                                                          optional => 1,
93                                                         },
94                                           actions_taken => {type => HASHREF,
95                                                             default => {},
96                                                            },
97                                          },
98                               );
99
100      $param{transcript} = globify_scalar($param{transcript});
101      $param{debug} = globify_scalar($param{debug});
102      if (ref ($param{data}) eq 'ARRAY') {
103           for my $data (@{$param{data}}) {
104                add_recipients(data => $data,
105                               map {exists $param{$_}?($_,$param{$_}):()}
106                               qw(recipients debug transcript actions_taken)
107                              );
108           }
109           return;
110      }
111      my ($p, $addmaint);
112      my $anymaintfound=0; my $anymaintnotfound=0;
113      my $ref = $param{data}{bug_num};
114      for my $p (splitpackages($param{data}{package})) {
115           $p = lc($p);
116           if (defined $config{subscription_domain}) {
117                my @source_packages = binarytosource($p);
118                if (@source_packages) {
119                     for my $source (@source_packages) {
120                          _add_address(recipients => $param{recipients},
121                                       address => "$source\@".$config{subscription_domain},
122                                       reason => $source,
123                                       type  => 'bcc',
124                                      );
125                     }
126                }
127                else {
128                     _add_address(recipients => $param{recipients},
129                                  address => "$p\@".$config{subscription_domain},
130                                  reason => $p,
131                                  type  => 'bcc',
132                                 );
133                }
134           }
135           if (defined $param{data}{severity} and defined $config{strong_list} and
136               isstrongseverity($param{data}{severity})) {
137                _add_address(recipients => $param{recipients},
138                             address => "$config{strong_list}\@".$config{list_domain},
139                             reason => $param{data}{severity},
140                             type  => 'bcc',
141                            );
142           }
143           my @maints = package_maintainer(binary => $p);
144           if (@maints) {
145               print {$param{debug}} "MR|".join(',',@maints)."|$p|$ref|\n";
146               _add_address(recipients => $param{recipients},
147                            address => \@maints,
148                            reason => $p,
149                            bug_num => $param{data}{bug_num},
150                            type  => 'cc',
151                           );
152               print {$param{debug}} "maintainer add >$p|".join(',',@maints)."<\n";
153           }
154           else {
155                print {$param{debug}} "maintainer none >$p<\n";
156                print {$param{transcript}} "Warning: Unknown package '$p'\n";
157                print {$param{debug}} "MR|unknown-package|$p|$ref|\n";
158                _add_address(recipients => $param{recipients},
159                             address => $config{unknown_maintainer_email},
160                             reason => $p,
161                             bug_num => $param{data}{bug_num},
162                             type  => 'cc',
163                            )
164                     if defined $config{unknown_maintainer_email} and
165                          length $config{unknown_maintainer_email};
166           }
167       }
168      if (defined $config{bug_subscription_domain} and
169          length $config{bug_subscription_domain}) {
170           _add_address(recipients => $param{recipients},
171                        address    => 'bug='.$param{data}{bug_num}.'@'.
172                                      $config{bug_subscription_domain},
173                        reason     => "bug $param{data}{bug_num}",
174                        bug_num    => $param{data}{bug_num},
175                        type       => 'bcc',
176                       );
177      }
178
179      if (length $param{data}{owner}) {
180           $addmaint = $param{data}{owner};
181           print {$param{debug}} "MO|$addmaint|$param{data}{package}|$ref|\n";
182           _add_address(recipients => $param{recipients},
183                        address => $addmaint,
184                        reason => "owner of $param{data}{bug_num}",
185                        bug_num => $param{data}{bug_num},
186                        type  => 'cc',
187                       );
188         print {$param{debug}} "owner add >$param{data}{package}|$addmaint<\n";
189      }
190      if (exists $param{actions_taken}) {
191           if (exists $param{actions_taken}{done} and
192               $param{actions_taken}{done} and
193               length($config{done_list}) and
194               length($config{list_domain})
195              ) {
196                _add_address(recipients => $param{recipients},
197                             type       => 'cc',
198                             address    => $config{done_list}.'@'.$config{list_domain},
199                             bug_num    => $param{data}{bug_num},
200                             reason     => "bug $param{data}{bug_num} done",
201                            );
202           }
203           if (exists $param{actions_taken}{forwarded} and
204               $param{actions_taken}{forwarded} and
205               length($config{forward_list}) and
206               length($config{list_domain})
207              ) {
208                _add_address(recipients => $param{recipients},
209                             type       => 'cc',
210                             address    => $config{forward_list}.'@'.$config{list_domain},
211                             bug_num    => $param{data}{bug_num},
212                             reason     => "bug $param{data}{bug_num} forwarded",
213                            );
214           }
215      }
216 }
217
218 =head2 determine_recipients
219
220      my @recipients = determine_recipients(recipients => \%recipients,
221                                            bcc => 1,
222                                           );
223      my %recipients => determine_recipients(recipients => \%recipients,);
224
225      # or a crazy example:
226      send_mail_message(message => $message,
227                        recipients =>
228                         [make_list(
229                           values %{{determine_recipients(
230                                 recipients => \%recipients)
231                                   }})
232                         ],
233                       );
234
235 Using the recipient hashref, determines the set of recipients.
236
237 If you specify one of C<bcc>, C<cc>, or C<to>, you will receive only a
238 LIST of recipients which the main should be Bcc'ed, Cc'ed, or To'ed
239 respectively. By default, a LIST with keys bcc, cc, and to is returned
240 with ARRAYREF values correponding to the users to whom a message
241 should be sent.
242
243 =over
244
245 =item address_only -- whether to only return mail addresses without reasons or realnamesq
246
247 =back
248
249 Passing more than one of bcc, cc or to is a fatal error.
250
251 =cut
252
253 sub determine_recipients {
254      my %param = validate_with(params => \@_,
255                                spec   => {recipients => {type => HASHREF,
256                                                         },
257                                           bcc        => {type => BOOLEAN,
258                                                          default => 0,
259                                                         },
260                                           cc         => {type => BOOLEAN,
261                                                          default => 0,
262                                                         },
263                                           to         => {type => BOOLEAN,
264                                                          default => 0,
265                                                         },
266                                           address_only => {type => BOOLEAN,
267                                                            default => 0,
268                                                           }
269                                          },
270                               );
271
272      if (1 < scalar grep {$param{$_}} qw(to cc bcc)) {
273           croak "Passing more than one of to, cc, or bcc is non-sensical";
274      }
275
276      my %final_recipients;
277      # start with the to recipients
278      for my $addr (keys %{$param{recipients}}) {
279           my $level = 'bcc';
280           my @reasons;
281           for my $reason (keys %{$param{recipients}{$addr}}) {
282                my @bugs;
283                for my $bug (keys %{$param{recipients}{$addr}{$reason}}) {
284                     push @bugs, $bug;
285                     my $t_level = $param{recipients}{$addr}{$reason}{$bug};
286                     if ($level eq 'to' or
287                         $t_level eq 'to') {
288                          $level = 'to';
289                     }
290                     elsif ($t_level eq 'cc') {
291                          $level = 'cc';
292                     }
293                }
294                # strip out all non-word non-spaces
295                $reason =~ s/[^\ \w]//g;
296                push @reasons, $reason . ' for {'.join(',',@bugs).'}';
297           }
298           if ($param{address_only}) {
299                push @{$final_recipients{$level}}, get_addresses($addr);
300           }
301           else {
302                push @{$final_recipients{$level}}, $addr . ' ('.join(', ',@reasons).')';
303           }
304      }
305      for (qw(to cc bcc)) {
306           if ($param{$_}) {
307                if (exists $final_recipients{$_}) {
308                     return @{$final_recipients{$_}||[]};
309                }
310                return ();
311           }
312      }
313      return %final_recipients;
314 }
315
316
317 =head1 PRIVATE FUNCTIONS
318
319 =head2 _add_address
320
321           _add_address(recipients => $param{recipients},
322                        address => $addmaint,
323                        reason => $param{data}{package},
324                        bug_num => $param{data}{bug_num},
325                        type  => 'cc',
326                       );
327
328
329 =cut
330
331
332 sub _add_address {
333      my %param = validate_with(params => \@_,
334                                spec => {recipients => {type => HASHREF,
335                                                       },
336                                         bug_num    => {type => SCALAR,
337                                                        regex => qr/^\d*$/,
338                                                        default => '',
339                                                       },
340                                         reason     => {type => SCALAR,
341                                                        default => '',
342                                                       },
343                                         address    => {type => SCALAR|ARRAYREF,
344                                                       },
345                                         type       => {type => SCALAR,
346                                                        default => 'cc',
347                                                        regex   => qr/^(?:b?cc|to)$/i,
348                                                       },
349                                        },
350                               );
351      for my $addr (make_list($param{address})) {
352           if (lc($param{type}) eq 'bcc' and
353               exists $param{recipients}{$addr}{$param{reason}}{$param{bug_num}}
354              ) {
355                next;
356           }
357           elsif (lc($param{type}) eq 'cc' and
358                  exists $param{recipients}{$addr}{$param{reason}}{$param{bug_num}}
359                  and $param{recipients}{$addr}{$param{reason}}{$param{bug_num}} eq 'to'
360                 ) {
361                next;
362           }
363           $param{recipients}{$addr}{$param{reason}}{$param{bug_num}} = lc($param{type});
364      }
365 }
366
367 1;
368
369
370 __END__
371
372
373
374
375
376