#!/usr/bin/perl -T --
# -*- Mode: perl; indent-tabs-mode: nil -*-
#

# processmail_bugs - The 'bug tracking' mail processing engine for
# tinderbox.  The bug tracking server (bugzilla, aim, remedy, etc.)
# should send mail to the tinderbox server, when bug tickets change
# state. This program will parse the most common mail formats and
# tell the tinderbox server about the the database column Vs value
# pairs.  This program should be run by the MTA (Sendmail,Fetchmail)
# whenever mail for the tinderbox's bugtracking mail account arrives.
# Tinderbox will display summary information about these tickets on
# the same page as the build and version control information.  This
# program should not need any local configuration.  All we assume is
# that the mail contains the name/value pairs on separate lines and
# that these are easy to parse out.  All configuration is done in the
# BTData.pm so that the display module (BT_Generic.pm) can display the
# information correclty.  The Bug Tracking modules are designed to be
# very flexible and work with any bug tracking system, they may
# require technical configurations.  No locks are used by the mail
# processes, data is passed to the tinderbox server in a maildir like
# format.



# $Revision: 1.15 $ 
# $Date: 2005/11/25 21:57:07 $ 
# $Author: timeless%mozdev.org $ 
# $Source: /cvsroot/mozilla/webtools/tinderbox2/src/bin/processmail_bugs,v $ 
# $Name:  $ 


# 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/NPL/
#
# 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.
#
# The Original Code is the Tinderbox build tool.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#

# complete rewrite by Ken Estes for contact info see the
#     mozilla/webtools/tinderbox2/Contact file.
# Contributor(s): 


# Standard perl libraries
use File::Basename;
use Sys::Hostname;
use File::stat;
use Getopt::Long;

# Tinderbox libraries
use lib '/usr/share/tinderbox/lib', '/etc/tinderbox';

use TinderConfig;
use Utils;
use FileStructure;
use Persistence;
use MailProcess;
use BTData;
use TinderDB::BT_Generic;



=pod

# Sample Bugzilla mail.
# notice that mail is a diff either -u or -c format

# There are other format that mail can be sent: "prettyasciimail",
# "newemailtech". I have not received any mail in these formats so I
# have not written a parser yet.

# The first example comes from redhat.com the second from bugzilla.org
# notice they use different diff settings.


+Bug#: 1999
+Product: Red Hat Contrib|Net
+Version: 1.0
+Platform: All
+OS/Version: 
+Status: NEW   
+Resolution: 
+Severity: low
-Priority: high
+Priority: normal
+Component: rhcn
+AssignedTo: adevries@redhat.com                            
+ReportedBy: kestes@staff.mail.com               
+URL: 
+Cc: bugzilla-owner@redhat.com
+Summary: RPM 2.5.6 BUG



*** shadow/38305	Mon May 22 17:17:36 2000
--- shadow/38305.tmp.25956	Fri May 26 17:37:48 2000
***************
*** 11,17 ****
  AssignedTo: slamm@netscape.com                            
  ReportedBy: kestes@staff.mail.com               
  QAContact: matty@box.net.au
! TargetMilestone: ---
  URL: 
  Summary: new version of Tinderbox
  
--- 11,17 ----
  AssignedTo: slamm@netscape.com                            
  ReportedBy: kestes@staff.mail.com               
  QAContact: matty@box.net.au
! TargetMilestone: M20
  URL: 
  Summary: new version of Tinderbox
  


# this sample is from the Bugzilla 'new email technology' format


http://bugzilla.mozilla.org/show_bug.cgi?id=48679

mcafee@netscape.com changed:

           What    |Old Value                   |New Value
----------------------------------------------------------------------------
         OS/Version|All                         |FreeBSD
           Platform|All                         |Other



------- Additional Comments From mcafee@netscape.com  2000-09-22 02:41 -------
test, ignore




# AIM has blocks like this.  The blocks are not contiguious and the
# names have spaces.  It is true that the names which are displayed in
# the mail message are configurable, this shows the default settings.


-----------------------------------------------------
USER/SUBMITTOR INFORMATION
-----------------------------------------------------
User Login: hfung
E-Mail: hfung@staff.mail.com

-----------------------------------------------------
DEVELOPMENT STAFF INFORMATION
-----------------------------------------------------
Support Staff Login: mzhang
Support Staff E-Mail: mzhang@staff.mail.com

-----------------------------------------------------
BUG/DEFECT/FEATURE INFORMATION
-----------------------------------------------------
Ticket #: 1116
Date Open: 5/10/00
Last Modified Date: 05/18/2000
Product Sub System: Admin
Product Version: 1.1
Severity: 3 - Minor
Status: Closed
Closed Date: *
Short Description: the "C" in the Cancel Button on Mailing List Delete
Confirm page should be caps.

Bug/Defect/Feature Description:

the "C" in the Cancel Button on Mailing List Delete Confirm page should be
caps.
[-Open- 05/10/2000 12:00:05 PM - hfung - Submit Bug/Defect/Feature-]
[-Assigned- 05/11/2000 02:11:05 PM - admin - Assign Bug/Defect/Feature(s)-]
[-Pending- 05/17/2000 04:17:12 PM - WIG - Modify Bug/Defect/Feature-]
[-Assigned- 05/18/2000 06:12:32 PM - mzhang - Confirm Reception of
Bug/Defect/Feature(s)-]
[-Closed- 05/18/2000 06:26:58 PM - mzhang - Modify Bug/Defect/Feature-]


=cut

# untaint the variable and values parsed from trouble ticket mail.

sub clean_bug_input {
  my ($var, $value) = @_;

  # untaint data for safety

  $var = main::extract_printable_chars($var);

  # the input is HTML so it is a good idea to escape it
  
  $value = main::extract_html_chars($value);
  $value = HTMLPopUp::escapeHTML($value);

  # remove spaces at beginning and end of lines

  $value =~ s/\s+$//;
  $value =~ s/^\s+//;

  $var =~ s/\s+$//;
  $var =~ s/^\s+//;


  # The AIM bug tracker has spaces in some of the variable names,
  # convert these to underlines to make processing easier.

  $var =~ s/\s+/_/g;

  return ($var, $value);
}



sub parse_bt_vars {

  # Lines will be diffs, and this could cause the variables to appear
  # twice in the data with different values.  We keep the LAST
  # assignment of each variable.  This means that long variables can
  # not be split up to multiple lines.

  # Because of the bugzilla program diffs the old/new ticket we do not
  # always get all the interesting fields we need in the contents of
  # the message. We ensure that we always have a bug number and
  # Summary line, by taking it out of the subject line, if the message
  # has a different date it will overwrite this default.

  if ($MAIL_HEADER{'Subject'} =~ m/\[Bug\s+(\d+)\]/) {
    $tinderbox{$BTData::BUGID_FIELD_NAME} = $1;
  }

  if ($MAIL_HEADER{'Subject'} =~ m/Changed\s+-\s+(.*)/) {
    $tinderbox{'Summary'} = $1;
  }

  # We parse the whole mail message because some formats are hard to
  # tell when we are done AND we do not need to keep the long
  # descriptions anyway.

  my ($found_vars)= 0;
  my ($line) = '';

  while(defined($line = <>)) {
    
    my ($num_colons) = scalar($line =~ tr/://);
    my ($num_pipes) = scalar($line =~ tr/|//);

    if ( 
        ($num_colons == 1) && 
        ($line =~ m/^[ \t\+\!]*[A-Z]/) && 
        ($line =~ m/:\s+\w/) 
       ) {

      # Capture one of the bug variables
      
      # We make a quick test to eliminate lines we do not want.
      
      # The lines we want:
      # 1)  begin with a capital letter (but may be preceded by 
      #     diff characters).
      # 2)  have a colon followed by a space followed by data in them.
      
      if ( $line =~ m!
	   ^[ \t\+\!]*                # line may begin with 'diff characters'
                                      #       (skip diff deletions)
	   ($BTData::VAR_PATTERN)     # variable identifier
	   \s*\:\s+                   # followed by a colon-space separator
	   (.+)                       # value of the variable
	   \n$                        # go till end of line 
	   !ox ) {
	
	my ($var, $value) = ($1, $2);

        ($var, $value) = clean_bug_input($var, $value);

	($value) || next;
	($var) || next;

	$tinderbox{$var} = $value;
      }
 
    } elsif ( 
               ($num_pipes == 2) && 
               ($line =~ m/^[ \t]*[A-Z]/)
              ) {

      # Capture one of the bug variables
      
      # We make a quick test to eliminate lines we do not want.
      
      # The lines we want:
      # 1)  begin with a capital letter (but may be preceded by 
      #     white space).
      # 2)  have exactly two pipes in them.
      
      if ( $line =~ m!
	   ^[ \t]*                    # line may begin with white space
	   ($BTData::VAR_PATTERN)     # variable identifier
	   \s*\|\s*                   # followed by a pipe-space separator
	   ([^|]+)                    # old value of the variable
	   \s*\|\s*                   # followed by a pipe-space separator
	   ([^|]+)                    # new value of the variable
	   \n$                        # go till end of line 
	   !ox ) {
	
	my ($var, $value) = ($1, $3);

        ($var, $value) = clean_bug_input($var, $value);

	($value) || next;
	($var) || next;

	$tinderbox{$var} = $value;
      }

    }
  } # while

  return %tinderbox;
} # parse_tinderbox_vars



sub set_tinderbox_variables {

  # set known tinderbox fields based on the bug tracker's variables.
  my ($bug_id) = $TINDERBOX{$BTData::BUGID_FIELD_NAME};

  $TINDERBOX{'tinderbox_timenow'} = time();

  $TINDERBOX{'tinderbox_mailto'} = $MAIL_HEADER{'To'};
  $TINDERBOX{'tinderbox_mailfrom'} = $MAIL_HEADER{'From'};
  $TINDERBOX{'tinderbox_mailsubject'} = $MAIL_HEADER{'Subject'};

  # I believe this is sendmail specific so do not rely on it, 
  # however I hate to lose the data.
  $TINDERBOX{'tinderbox_maildate'} = $MAIL_HEADER{'Date'};

  $TINDERBOX{'tinderbox_status'} = $TINDERBOX{$BTData::STATUS_FIELD_NAME};

  $TINDERBOX{'tinderbox_bug_id'} = $bug_id;

  return 1;
}




# --------------------main-------------------------
{
  set_static_vars();
  get_env();
  MailProcess::parse_mailprocess_args();
  chk_security();

  $SIG{'__DIE__'} = \&MailProcess::fatal_mailprocessing_error;

  %MAIL_HEADER = MailProcess::parse_mail_header();
  %TINDERBOX = parse_bt_vars();

  my (@trees) = BTData::update2tree(\%TINDERBOX);
  
  foreach $tree (@trees) {
    
      # It is easier to ignore trees we do not know about here rather
      # then to make the BTData module depend on the TreeData module.

      ($tree) || next;
      $TreeData::VC_TREE {$tree} || next;

    set_tinderbox_variables();

    $TINDERBOX{'tinderbox_tree'} = $tree;

    # some updates do not have a status.  We can not do anything with
    # them, and we probably only want to report when the bug
    # changes state anyway.

    ($TINDERBOX{'tinderbox_status'}) ||
      exit 0;

    (BTData::is_status_valid($TINDERBOX{'tinderbox_status'})) ||
      die("Status: $TINDERBOX{'tinderbox_status'} ".
          "is not a valid bug status\n");

    # Testing is easier if the update files appear at the top of the
    # status page, even though they are checked out of CVS.
    
    if ($FORCE_TIME) {
      $TINDERBOX{'tinderbox_timenow'} = time() - 10;
    }
    
    my ($uniq_id) = join('.', 
                         $TINDERBOX{'tinderbox_tree'},
                         $TINDERBOX{'tinderbox_timenow'},
                         $TINDERBOX{'tinderbox_bug_id'},
                         $TINDERBOX{'tinderbox_mailto'},
                         $TINDERBOX{'tinderbox_mailfrom'},
                        );
    
    MailProcess::write_update_file('BT_Generic', $uniq_id, $tree, %TINDERBOX );

  } # foreach $tree

  exit 0;
}
