#!/usr/bin/perl # # Script which classifies scarab e-mails based on a defined # association between Event->Module->Role. # author: kasia trapszo ktrapszo@tickets.com # # Scarab events # # New # ToDev # ToQA # InDev # InQA # QAReject # Closed # Assigned # Modified <-- Modified event encompasses all scarab events. # # # TURBINE roles as defined in scarab: # # +---------+---------------+ # | ROLE_ID | ROLE_NAME | # +---------+---------------+ # | 2 | Partner | # | 3 | Observer | # | 4 | Developer | # | 5 | QA | # | 6 | Project Owner | # | 7 | Root | # +---------+---------------+ # # To have e-mail just go to everyone associated with the issue (default scarab behaviour) # the value used should be: # # 'associated' # # # # Scarab modules as defined currently: # # +--------------------+ # | MODULE_NAME | # +--------------------+ # | Global | # | Pipeline | # | Infrastructure | # | Operations | # +--------------------+ # # # "default" is the default behaviour applied to all modules unless a specific # behaviour is defined in the database. # # Table schema # # CREATE TABLE scarab_email ( # id int(11) NOT NULL AUTO_INCREMENT, # module_name varchar(255)NOT NULL, # scarab_event varchar(99) NOT NULL, # role_name varchar(99) NOT NULL, # PRIMARY KEY (id) # ) TYPE=MyISAM; # # # Sample (default) data # # NOTE: Module names and role names *must* match scarab data for script # to work properly. # # # INSERT INTO scarab_email (module_name, scarab_event, role_name) values ('default', 'New', 'Partner'); # INSERT INTO scarab_email (module_name, scarab_event, role_name) values ('default', 'New', 'Project Owner'); # INSERT INTO scarab_email (module_name, scarab_event, role_name) values ('default', 'New', 'QA'); # INSERT INTO scarab_email (module_name, scarab_event, role_name) values ('default', 'New', 'Verbose'); # INSERT INTO scarab_email (module_name, scarab_event, role_name) values ('default', 'ToDev', 'Developer'); # INSERT INTO scarab_email (module_name, scarab_event, role_name) values ('default', 'ToDev', 'Observer'); # INSERT INTO scarab_email (module_name, scarab_event, role_name) values ('default', 'ToDev', 'Verbose'); # INSERT INTO scarab_email (module_name, scarab_event, role_name) values ('default', 'ToQA', 'QA'); # INSERT INTO scarab_email (module_name, scarab_event, role_name) values ('default', 'ToQA', 'Verbose'); # INSERT INTO scarab_email (module_name, scarab_event, role_name) values ('default', 'QAReject', 'Developer'); # INSERT INTO scarab_email (module_name, scarab_event, role_name) values ('default', 'QAReject', 'Project Owner'); # INSERT INTO scarab_email (module_name, scarab_event, role_name) values ('default', 'QAReject', 'Verbose'); # INSERT INTO scarab_email (module_name, scarab_event, role_name) values ('default', 'Closed', 'Observer'); # INSERT INTO scarab_email (module_name, scarab_event, role_name) values ('default', 'Closed', 'Project Owner'); # INSERT INTO scarab_email (module_name, scarab_event, role_name) values ('default', 'Closed', 'Verbose'); # INSERT INTO scarab_email (module_name, scarab_event, role_name) values ('default', 'Modified', 'Verbose'); # INSERT INTO scarab_email (module_name, scarab_event, role_name) values ('default', 'Assigned', 'associated'); # INSERT INTO scarab_email (module_name, scarab_event, role_name) values ('default', 'InQA', 'Verbose'); # INSERT INTO scarab_email (module_name, scarab_event, role_name) values ('default', 'InDev', 'Verbose'); # # KNOWN ISSUES #---------------- # # If scarab is configured to send archive email, it sometimes sends the same e-mail twice, once to original # recipients, second time to archive. To avoid duplication, archive email should be turned off. # use DBI; use miscsql; use strict; require "login.sub"; #---------------------------------------------------------------- # Configurable options #---------------------------------------------------------------- # sendmail # my $sendmail = '/usr/sbin/sendmail'; # e-mail will arrive from this sender. # my $sender = 'issues@example.com'; # this is where delivery problems will go to. # my $envelope_sender = 'admin@example.com'; # e-mail domain name --> where the email is going to , the part after @ in our # mailing lists. my $domain = 'engineering.example.com'; my $scarab_header = 'X-Scarab-Module:'; # Where we write log info # my $log = '/home/scarab/logs/maillog'; # The table where we're storing the rules. The one created above. # my $table = 'scarab_email'; # What we call our events. # my $event_new = "New"; my $event_todev = "ToDev"; my $event_toqa = "ToQA"; my $event_qareject = "QAReject"; my $event_closed = "Closed"; my $event_assigned = "Assigned"; my $event_modified = "Modified"; my $event_indev = "InDev"; my $event_inqa = "InQA"; # This hash defines how we decide which event the e-mail describes. # my %events = ( $event_todev => "to \"To Dev", $event_toqa => "to \"To QA", $event_qareject => "to \"Rejected", $event_closed => "to \"Closed", $event_assigned => "has added user", $event_indev => "to \"In Dev", $event_inqa => "to \"In QA" ); # This setting will turn the email off - per role/module of course. # my $turn_off = "OFF"; # # If no settings are defined for a module, use this module's settings. # my $default_module = "default"; # # If this is the role defined for event/module e-mail to users associated # with the issue which are basically the "to" header of the email since # that's what scarab does by default. # my $associated = "associated"; # The unique string we can use to identify that the email is about # a new issue. # my $new_issue_string = "New issue details:"; # The unique string we can use to identify that the email is abuot # a modified issue. # my $modified_issue_string = "The following modifications were made to this issue:"; # The separator scarab puts around the description of issue modifications. # my $modified_separator_string = "---------------------------------------------------------------------"; # # debug, with this enabled it will dump output to a log, it won't otherwise # why waste good space? # # debug of 1 is informative # 2 a bit more informative # 3 dumps everything including the entire message. # my $debug = 1; # If set to one, the script will go through the whole filtering process # and do *everything* *but* send the actuall email. # my $fake_email = 0; # If set, it will go through the motions of filtering, report everything # in the log, but send e-mail as originally intended by scarab. # my $test_mode = 0; #---------------------------------------------------------------- # Nothing to configure below. #---------------------------------------------------------------- my $command = ""; my @RECIPS = (); my @HEADERS = (); my @BODY = (); my @ORIG_RECIPS = (); my $module = ''; my $event = undef; my $issue_modified = 0; my $in_header = 1; my $seen_separator = 0; my $dont_send_mail = 0; foreach ( @ARGV ) { if ( m/^--help/i ) { print STDERR <> $log") or die "ERROR: Can't open log file ($log)\n"; print (LOG "----------------- Starting processing e-mail -----------------\n"); } while () { # we don't want to forward the message with this header # since this is exactly what we're filtering on. # retaining the header will put the email in a loop, # that will make the server unhappy. # next if m/^Reply-To:/i; # check for end of headers. # $in_header = 0 if($in_header and m/^\s*$/); if($in_header) { print LOG "headers: $_" if $debug > 2; push @HEADERS, $_; if(m/^Subject:/i) { # everything between [ ] in subject # should be the module name, if not, fear not # we'll use default settings and log that. # if( m/\[ ( [^\]]+ ) \]/x ) { $module = $1; print LOG "Detected module name as: $module\n" if $debug > 1; } # Pop subject in case it's more than one line, don't want to break it up. # my $subject = pop @HEADERS; print LOG "Injecting our header: $scarab_header $module\n" if $debug; push @HEADERS, "$scarab_header $module\n"; push @HEADERS, $subject; } } else { print LOG "body: $_" if $debug > 2; push @BODY, $_; if($issue_modified) { next if(m/^\s*$/); if(m/^$modified_separator_string/i) { if(!$seen_separator) { $seen_separator = 1; print LOG "First separator encountered\n" if $debug > 1; } else { $seen_separator = 0; $issue_modified = 0; print LOG "Second separator encountered, stopping looking at modified stuff\n" if $debug > 1; } next; } my $curr_event_key; my $curr_event; foreach $curr_event_key(sort keys %events) { $curr_event = $events{$curr_event_key}; print LOG "Matching against \"$curr_event\"\n" if $debug > 1; if(m/^*$curr_event*/i) { $issue_modified = 0; $event = $curr_event_key; print LOG "Okay, we detected the event is: $event\n" if $debug > 1; next; } } } # okay, we've got a new issue! # elsif(m/^$new_issue_string/i) { $event = $event_new; print LOG "We have a new issue!\n" if $debug > 1; } elsif(m/^*$modified_issue_string*/i) { $issue_modified = 1; print LOG "Detected modified issue, will look at further lines\n" if $debug > 1; } } } # If we didn't detect an event, going with a generic "modified". # if(not defined $event) { $event = $event_modified; print LOG "No event detected, going with generic $event_modified\n" if $debug > 1; } @RECIPS = getRecips(); print LOG "Summary before we send: module is $module, event is $event, recipient(s) is/are ", join(" ", @RECIPS, "\n") if !$dont_send_mail and $debug; if($test_mode) { print LOG "We're in test mode, email would have gone out to: @RECIPS but sending to @ORIG_RECIPS as scarab intended\n" if $debug; @RECIPS = @ORIG_RECIPS; } $command = join(" ", "$sendmail -f $envelope_sender", @RECIPS); print (LOG "Originally to: @ORIG_RECIPS\n") if $debug > 0; if(!$fake_email and !$dont_send_mail) { open(MAIL, "| $command") or die "ERROR: can't launch sendmail\n"; print MAIL @HEADERS; print MAIL "\n"; print MAIL @BODY; print MAIL "This message is being sent to ", join(" ", @RECIPS, "\n"); print MAIL "Module is $module and event is $event\n"; close MAIL; } if($debug) { print (LOG "Done\n"); close(LOG); } # Determines who will receive the email based on passed in params # sub getRecips { # we want to send it *somewhere* right? If all fails, just go with # what scarab was originally trying to do -- which is everyone in the # universe or so. # my @out = (); my $roles = &sqlSelectMany("role_name", "$table", "module_name='$module' and scarab_event = '$event'"); my $role = ''; my $have_values = 0; while($role = $roles->fetchrow()) { $have_values = 1; print LOG "Role to use for $module and $event is $role\n" if $debug > 1; push @out, getEmailValue($role); } if(!$have_values) { print LOG "No roles defined for $module and $event, going for defaults\n" if $debug > 1; $roles = &sqlSelectMany("role_name", "$table", "module_name='$default_module' and scarab_event = '$event'"); while($role = $roles->fetchrow()) { $have_values = 1; print LOG "Using defaults roles $role for $module and $event\n" if $debug > 2; push @out, getEmailValue($role); } } if(!$have_values) { print LOG "Oops, we don't even have default values defined for $event! Using original recipients.\n" if $debug > 1; @out = @ORIG_RECIPS; } return @out; } # Builds the e-mail address for this role/module. # sub getEmailValue { my @out = (); my $role = shift; if($role eq $turn_off) { @out = ''; $dont_send_mail = 1; print LOG "Role for $module $event is $turn_off we will not send any email\n" if debug; } elsif($role eq $associated) { @out = @ORIG_RECIPS; } else { $role = no_blanks($role); my ($module_id, $module_code) = &sqlSelect("MODULE_ID, MODULE_CODE", "SCARAB_MODULE", "MODULE_NAME='$module'"); if(!$module_code eq '') { push @out, "$module_code-$role\@$domain"; } else { print LOG "uhm, this module, $module does not have a module_code in the database, that's not good!\n" if $debug; } } return @out; } # Replace blanks spaces with _ # sub no_blanks { my @out = @_; for (@out) { s/^\s+//; s/\s+$//; s/\s+ /_/xg; } return wantarray ? @out : shift @out; }