landing rt 3.2.2
[freeside.git] / rt / bin / rt-commit-handler.in
diff --git a/rt/bin/rt-commit-handler.in b/rt/bin/rt-commit-handler.in
deleted file mode 100644 (file)
index 02b01ab..0000000
+++ /dev/null
@@ -1,846 +0,0 @@
-#!@PERL@ -w
-# BEGIN LICENSE BLOCK
-# 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
-# 
-# (Except where explictly superceded by other copyright notices)
-# 
-# This work is made available to you under the terms of Version 2 of
-# the GNU General Public License. A copy of that license should have
-# been provided with this software, but in any event can be snarfed
-# from www.gnu.org.
-# 
-# This work is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# General Public License for more details.
-# 
-# Unless otherwise specified, all modifications, corrections or
-# extensions to this work which alter its source code become the
-# property of Best Practical Solutions, LLC when submitted for
-# inclusion in the work.
-# 
-# 
-# END LICENSE BLOCK
-
-# {{{ Docs
-# -*-Perl-*-
-#
-#ident "@(#)ccvs/contrib:$Name:  $:$Id: rt-commit-handler.in,v 1.1 2003-07-15 13:16:15 ivan Exp $"
-#
-# Perl filter to handle the log messages from the checkin of files in multiple
-# directories.  This script will group the lists of files by log message, and
-# send one piece of mail per unique message, no matter how many files are
-# committed.
-
-=head1 NAME rt-commit-handler
-
-=head1 USAGE
-
-
-
-=head2 Regular use
-
-Stick the following in in CVSROOT/commitinfo
-
- ALL     @RT_BIN_PATH@/rt-commit-handler --record-last-dir
-
-Stick the following  in CVSROOT/loginfo
-
- ALL     @RT_BIN_PATH@/rt-commit-handler --cvs-root /pathtocvs/root --rt %{Vvts}
-
-=head2 Invocation (advanced use)
-
-rt-commit-handler --cvs-root /path/to/cvs/root [-d] [-D] [-r] [-M module] \
-                [[-m mailto] ...] [[-R replyto] ...] [-f logfile] 
-
-
-       -d              - turn on debugging
-       -m mailto       - send mail to "mailto" (multiple)
-       -R replyto      - set the "Reply-To:" to "replyto" (multiple)
-       -M modulename   - set module name to "modulename"
-       -f logfile      - write commit messages to logfile too
-       -D              - generate diff commands
-        --rt              - invoke RT commit handler
-        --cvs-root       - specify your CVS root 
-
-        --record-last-dir -  Record the last directory with changes in
-                             pre-commit (commitinfo) mode
-
-
-=cut
-
-# }}}
-
-use strict;
-use Carp;
-use Getopt::Long;
-use Text::Wrap;
-use Digest::MD5;
-use MIME::Entity;
-
-use lib ("@RT_LIB_PATH@", "@LOCAL_LIB_PATH@");
-
-use RT::Interface::CLI qw(CleanEnv GetCurrentUser GetMessageContent loc);
-
-use vars
-  qw(@MAILER $TMPDIR $FILE_PREFIX $LASTDIR_FILE $HASH_FILE $VERSION_FILE             $MESSAGE_FILE $MAIL_FILE $DEBUG $MAILTO $REPLYTO $id $MODULE_NAME
-  $LOGIN $COMMITLOG $CVS_ROOT $RT_HANDLER);
-
-#Clean out all the nasties from the environment
-CleanEnv();
-
-#Load etc/config.pm and drop privs
-RT::LoadConfig();
-
-#Drop setgid permissions
-RT::DropSetGIDPermissions();
-
-# {{{ Variable setup
-$TMPDIR      = '/tmp';
-$FILE_PREFIX = $TMPDIR . '/#cvs.';
-
-# The root of your CVS install. we should get this from some smarter place.
-# It needs a trailing /
-
-$LASTDIR_FILE = $FILE_PREFIX . "lastdir";
-$HASH_FILE    = $FILE_PREFIX . "hash";
-$VERSION_FILE = $FILE_PREFIX . "version";
-$MESSAGE_FILE = $FILE_PREFIX . "message";
-$MAIL_FILE    = $FILE_PREFIX . "mail";
-
-$DEBUG      = 0;
-$RT_HANDLER = 1;
-
-$MAILTO = '';
-
-my @files = ();
-my (@log_lines);
-my $do_diff = 0;
-my $id      = getpgrp();    # note, you *must* use a shell which does setpgrp()
-$LOGIN = getpwuid($<);
-
-# }}}
-
-die "User could not be found" unless ($LOGIN);
-
-# {{{ parse command line arguments (file list is seen as one arg)
-#
-while ( my $arg = shift @ARGV ) {
-
-    if ( $arg eq '-d' ) {
-        $DEBUG = 1;
-        warn "Debug turned on...\n";
-    }
-    elsif ( $arg =~ /^--record-last-dir$/i ) {
-        record_last_dir( $id, $ARGV[0] );
-        exit(0);
-    }
-    elsif ( $arg eq '-m' ) {
-        $MAILTO .= ", " if $MAILTO;
-        $MAILTO .= shift @ARGV;
-    }
-    elsif ( $arg eq '--rt' ) {
-        $RT_HANDLER = 1;
-    }
-    elsif ( $arg eq '-R' ) {
-        $REPLYTO .= ", " if $REPLYTO;
-        $REPLYTO .= shift @ARGV;
-    }
-    elsif ( $arg eq '-M' ) {
-        die ("too many '-M' args\n") if $MODULE_NAME;
-        $MODULE_NAME = shift @ARGV;
-    }
-    elsif ( $arg eq '--cvs-root' ) {
-        $CVS_ROOT = shift @ARGV;
-        $CVS_ROOT .= "/" unless ( $CVS_ROOT =~ /\/$/ );
-    }
-    elsif ( $arg eq '-f' ) {
-        die ("too many '-f' args\n") if $COMMITLOG;
-        $COMMITLOG = shift @ARGV;
-
-        # This is a disgusting hack to untaint $COMMITLOG if we're running from
-        # setgid cvs.
-        $COMMITLOG = untaint($COMMITLOG);
-    }
-    elsif ( $arg eq '-D' ) {
-        $do_diff = 1;
-    }
-    else {
-        @files = split ( ' ', $arg );
-        last;
-    }
-}
-
-# }}}
-
-$REPLYTO = $LOGIN unless ($REPLYTO);
-
-# for now, the first "file" is the repository directory being committed,
-# relative to the $CVSROOT location
-#
-my $dir = shift @files;
-
-# XXX there are some ugly assumptions in here about module names and
-# XXX directories relative to the $CVSROOT location -- really should
-# XXX read $CVSROOT/CVSROOT/modules, but that's not so easy to do, since
-# XXX we have to parse it backwards.
-#
-# XXX For now we set the `module' name to the top-level directory name.
-#
-unless ($MODULE_NAME) {
-    ($MODULE_NAME) = split ( '/', $dir, 2 );
-}
-
-if ($DEBUG) {
-    warn "module - ", $MODULE_NAME, "\n";
-    warn "dir    - ", $dir,         "\n";
-    warn "files  - ", join ( " ", @files ), "\n";
-    warn "id     - ", $id, "\n";
-}
-
-# {{{ Check for a new directory or an import command.
-
-#
-#    files[0] - "-"
-#    files[1] - "New"
-#    files[2] - "directory"
-#
-#    files[0] - "-"
-#    files[1] - "Imported"
-#    files[2] - "sources"
-#
-if ( $files[0] eq "-" ) {
-
-    #we just don't care about  New Directory notes
-    unless ( $files[1] eq "New" && $files[2] eq "directory" ) {
-
-        my @text = ();
-
-        push @text, build_header();
-        push @text, "";
-
-        while ( my $line = <STDIN> ) {
-            chop $line;    # Drop the newline
-            push @text, $line;
-        }
-
-        append_logfile( $COMMITLOG, @text ) if ($COMMITLOG);
-
-        mail_notification( $id, @text );
-    }
-
-    exit 0;
-}
-
-# }}}
-
-# {{{ Collect just the log message from stdin.
-#
-
-while ( my $line = <STDIN> ) {
-    chop $line;    # strip the newline
-    last if ( $line =~ /^Log Message:$/ );
-}
-while ( my $line = <STDIN> ) {
-    chop $line;    # strip the newline
-    $line =~ s/\s+$//;    # strip trailing white space
-    push @log_lines, $line;
-}
-
-my $md5 = Digest::MD5->new();
-foreach my $line (@log_lines) {
-    $md5->add( $line . "\n" );
-}
-my $hash = $md5->hexdigest();
-
-warn "hash = $hash\n" if ($DEBUG);
-
-if ( !-e "$MESSAGE_FILE.$id.$hash" ) {
-    append_logfile( "$HASH_FILE.$id",      $hash );
-    write_file( "$MESSAGE_FILE.$id.$hash", @log_lines );
-}
-
-# }}}
-
-# Spit out the information gathered in this pass.
-
-append_logfile( "$VERSION_FILE.$id.$hash", $dir . '/', @files );
-
-# {{{ Check whether this is the last directory.  If not, quit.
-
-warn "Checking current dir against last dir $LASTDIR_FILE.$id\n" if ($DEBUG);
-
-my @last_dir = read_file("$LASTDIR_FILE.$id");
-
-unless ($CVS_ROOT) {
-    die "No cvs root specified with --cvs-root. Can't continue.";
-}
-
-if ( $last_dir[0] ne $CVS_ROOT . $dir ) {
-    warn "Current directory $CVS_ROOT$dir is not last directory $last_dir[0].\n"
-      if ($DEBUG);
-    exit 0;
-}
-
-# }}}
-
-# {{{ End Of Commits!
-#
-
-# This is it.  The commits are all finished.  Lump everything together
-# into a single message, fire a copy off to the mailing list, and drop
-# it on the end of the Changes file.
-#
-
-#
-# Produce the final compilation of the log messages
-#
-
-my @hashes = read_file("$HASH_FILE.$id");
-my (@text);
-
-push @text, build_header();
-push @text, "";
-
-my ( @added_files, @modified_files, @removed_files );
-
-foreach my $hash (@hashes) {
-
-    # In case we're running setgid, make sure the hash file hasn't been hacked.
-    $hash =~ m/([a-z0-9]*)/ || die "*** Hacking attempt detected\n";
-    $hash = $1;
-
-    my @files     = read_file("$VERSION_FILE.$id.$hash");
-    my @log_lines = read_file("$MESSAGE_FILE.$id.$hash");
-
-    my $working_on_dir;    # gets set as we iterate through the files.
-    foreach my $file (@files) {
-
-        #If we've entered a new directory, make a note of that and remove the trailing /
-
-        if ( $file =~ s'\/$'' ) {
-            $working_on_dir = $file;
-            next;
-        }
-
-        my @file_entry = ( split ( ',', $file, 4 ), $working_on_dir );
-
-        # file_entry looks like ths:
-
-        # 0        1          2      3        4
-        # Old rev : new rev : tag:   file    :directory        
-        my $entry = {};
-        $entry->{'old'}  = $file_entry[0];
-        $entry->{'new'}  = $file_entry[1];
-        $entry->{'tag'}  = $file_entry[2];
-        $entry->{'file'} = $file_entry[3];
-        $entry->{'dir'}  = $file_entry[4];
-
-        if ( $file_entry[0] eq 'NONE' ) {
-            $entry->{'old'} = '0';
-            push @added_files, $entry;
-        }
-        elsif ( $file_entry[1] eq 'NONE' ) {
-            $entry->{'new'} = '0';
-            push @removed_files, $entry;
-        }
-        else {
-            push @modified_files, $entry;
-        }
-    }
-}
-
-# }}}
-
-# {{{ start building up the body
-
-# Strip leading and trailing blank lines from the log message.  Also
-# compress multiple blank lines in the body of the message down to a
-# single blank line.
-#
-
-my $blank = 1;
-@log_lines = map {
-    my $wasblank = $blank;
-    $blank = $_ eq '';
-    $blank && $wasblank ? () : $_;
-} @log_lines;
-
-pop @log_lines if $blank;
-
-@modified_files = order_and_summarize_diffs(@modified_files);
-@added_files    = order_and_summarize_diffs(@added_files);
-@removed_files  = order_and_summarize_diffs(@removed_files);
-
-push @text, "Modified Files:", format_lists(@modified_files)
-  if (@modified_files);
-
-push @text, "Added Files:", format_lists(@added_files) if (@added_files);
-
-push @text, "Removed Files:", format_lists(@removed_files) if (@removed_files);
-
-push @text, "", "Log Message", @log_lines if (@log_lines);
-
-push @text, "";
-
-if ($RT_HANDLER) {
-    rt_handler(
-        @log_lines,                             "\n",
-        loc("To generate a diff of this commit:\n"), "\n",
-        format_diffs( @modified_files, @added_files, @removed_files )
-    );
-}
-
-if ($COMMITLOG) {
-    append_logfile( $COMMITLOG, @text );
-}
-
-if ($do_diff) {
-    push @text, "";
-    push @text, loc("To generate a diff of this commit:");
-    push @text, format_diffs( @modified_files, @added_files, @removed_files );
-    push @text, "";
-}
-
-# }}}
-
-# {{{ Mail out the notification.
-
-mail_notification( $id, @text );
-
-# }}} 
-
-# {{{ clean up
-
-unless ($DEBUG) {
-    $hash = untaint($hash);
-    $id   = untaint($id);
-    unlink "$VERSION_FILE.$id.$hash";
-    unlink "$MESSAGE_FILE.$id.$hash";
-    unlink "$MAIL_FILE.$id";
-    unlink "$LASTDIR_FILE.$id";
-    unlink "$HASH_FILE.$id";
-}
-
-# }}}
-
-exit 0;
-
-# {{{ Subroutines
-#
-
-# {{{ append_logfile
-sub append_logfile {
-    my $filename = shift;
-    my (@lines) = @_;
-
-    $filename = untaint($filename);
-
-    open( FILE, ">>$filename" )
-      || die ("Cannot open file $filename for append.\n");
-    foreach my $line (@lines) {
-        print FILE $line . "\n";
-    }
-    close(FILE);
-}
-
-# }}}
-
-# {{{ write_file
-sub write_file {
-    my $filename = shift;
-    my (@lines) = @_;
-
-    $filename = untaint($filename);
-
-    open( FILE, ">$filename" )
-      || die ("Cannot open file $filename for write.\n");
-    foreach my $line (@lines) {
-        print FILE $line . "\n";
-    }
-    close(FILE);
-}
-
-# }}}
-
-# {{{ read_file
-sub read_file {
-    my $filename = shift;
-    my (@lines);
-
-    open( FILE, "<$filename" )
-      || die ("Cannot open file $filename for read.\n");
-    while ( my $line = <FILE> ) {
-        chop $line;
-        push @lines, $line;
-    }
-    close(FILE);
-
-    return (@lines);
-}
-
-# }}}
-
-# {{{ sub format_lists
-
-sub format_lists {
-    my @items = (@_);
-
-    my $files = "";
-    map {
-        $_->{'files'} && ( $files .= ' ' . join ( ' ', @{ $_->{'files'} } ) );
-    } @items;
-
-    my @lines = wrap( "\t", "\t\t", $files );
-    return (@lines);
-
-}
-
-# }}}
-
-# {{{ sub format_diffs
-
-sub format_diffs {
-    my @items = (@_);
-
-    my @lines;
-    foreach my $item (@items) {
-        next unless ( $item->{'files'} );
-        push ( @lines,
-            "cvs diff -r"
-              . $item->{'old'} . " -r"
-              . $item->{'new'} . " "
-              . join ( " ", @{ $item->{'files'} } ) . "\n" );
-
-    }
-
-    @lines = fill( "\t", "\t\t", @lines );
-
-    return (@lines);
-}
-
-# }}}
-
-# {{{ sub order_and_summarize_diffs {
-
-# takes an array of file items
-# returns a sorted array of fileset items, which are like file items, except they can have an array of files, rather than 
-# a singleton file.
-
-sub order_and_summarize_diffs {
-
-    my @files = (@_);
-
-    # Sort by tag, dir, file.
-    @files = sort {
-        $a->{'tag'} cmp $b->{'tag'}
-          || $a->{'dir'} cmp $b->{'dir'}
-          || $a->{'file'} cmp $b->{'file'};
-    } @files;
-
-    # Combine adjacent rows that are the same modulo the file name.
-
-    my @items = (undef);
-
-    foreach my $file (@files) {
-        if ( $#items == -1    #if it's empty
-            || ( !defined $items[-1]->{'old'}
-                || $items[-1]->{'old'} ne $file->{'old'} )
-            || ( !defined $items[-1]->{'new'}
-                || $items[-1]->{'new'} ne $file->{'new'} )
-            || ( !defined $items[-1]->{'tag'}
-                || $items[-1]->{'tag'} ne $file->{'tag'} ) )
-        {
-
-            push ( @items, $file );
-        }
-        push ( @{ $items[-1]->{'files'} },
-            $file->{'dir'} . "/" . $file->{'file'} );
-    }
-
-    return (@items);
-}
-
-# }}}
-
-# {{{ build_header
-
-sub build_header {
-    my $now    = gmtime;
-    my $header =
-      sprintf( "Module Name:\t%s\nCommitted By:\t%s\nDate:\t\t%s %s %s",
-        $MODULE_NAME, $LOGIN, substr( $now, 0, 19 ), "UTC",
-        substr( $now, 20, 4 ) );
-    return ($header);
-}
-
-# }}}
-
-# {{{ mail_notification
-sub mail_notification {
-    my $id = shift;
-    my (@text) = @_;
-    write_file( "$MAIL_FILE.$id", "From: " . $LOGIN,
-        "Subject: CVS commit: " . $MODULE_NAME, "To: " . $MAILTO,
-        "Reply-To: " . $REPLYTO,                "", "", @text );
-
-    my $entity = MIME::Entity->build(
-        From       => $LOGIN,
-        To         => $MAILTO,
-        Subject    => "CVS commit: " . $MODULE_NAME,
-        'Reply-To' => $REPLYTO,
-        Data       => join ( "\n", @text )
-    );
-    if ( $RT::MailCommand eq 'sendmailpipe' ) {
-        open( MAIL, "|$RT::SendmailPath $RT::SendmailArguments" )
-          || die "Couldn't send mail: " . $@ . "\n";
-        print MAIL $entity->as_string;
-        close(MAIL);
-    }
-    else {
-        $entity->send( $RT::MailCommand, $RT::MailParams );
-    }
-
-}
-
-# }}}
-
-# {{{ sub record_last_dir
-
-sub record_last_dir {
-    my $id  = shift;
-    my $dir = shift;
-
-    # make a note of this directory. later, we'll use this to 
-    # figure out if we've gone through the whole commit,
-    # for something that is a bad mockery of attomic commits.
-
-    warn "about to write $dir to $LASTDIR_FILE.$id" if ($DEBUG);
-
-    write_file( "$LASTDIR_FILE.$id", $dir );
-}
-
-# }}}
-
-# {{{ Get the RT stuff set up
-
-# {{{ sub rt_handler 
-
-sub rt_handler {
-    my (@LogMessage) = (@_);
-
-    #Connect to the database and get RT::SystemUser and RT::Nobody loaded
-    RT::Init;
-
-    require RT::Ticket;
-
-    #Get the current user all loaded
-    my $CurrentUser = GetCurrentUser();
-
-    if ( !$CurrentUser->Id ) {
-        print
-loc("No valid RT user found. RT cvs handler disengaged. Please consult your RT administrator.\n");
-        return;
-    }
-
-    my (@commands) = find_commands( \@LogMessage );
-
-    my ( @tickets, @errors );
-
-    # Get the list of tickets we're working with out of commands
-    grep { $_ =~ /^RT-Ticket:\s*(.*?)$/i && push ( @tickets, $1 ) } @commands;
-
-    my $message = new MIME::Entity;
-    $message->build(
-        From    => $CurrentUser->EmailAddress,
-        Subject => 'CVS Commit',
-        Data    => \@LogMessage
-    );
-
-    # {{{ comment or correspond, as needed
-
-    foreach my $ticket (@tickets) {
-        my $TicketObj = RT::Ticket->new($CurrentUser);
-        $TicketObj->Load($ticket);
-        my ( $id, $msg );
-        unless ( $TicketObj->Id ) {
-            push ( @errors,
-"Couldn't load ticket #$ticket. Not adding commit log to ticket history.\n"
-            );
-        }
-
-        if ( $LogMessage[0] =~ /^(comment|private)$/ ) {
-            ( $id, $msg ) = $TicketObj->Comment( MIMEObj => $message );
-
-        }
-        else {
-            ( $id, $msg ) = $TicketObj->Correspond( MIMEObj => $message );
-        }
-
-        push ( @errors, ">> Log message",
-            "Ticket #" . $TicketObj->Id . ": " . $msg );
-
-    }
-
-    # }}}
-
-    my ($reply) = ActOnPseudoHeaders( $CurrentUser, @commands );
-    print "$reply\n" if ($reply);
-    print join ( "\n", @errors );
-    print "\n";
-
-}
-
-# }}}
-
-# {{{ sub find_commands
-
-sub find_commands {
-    my $lines = shift;
-    my (@pseudoheaders);
-
-    while ( my $line = shift @{$lines} ) {
-        next if $line =~ /^\s*?$/;
-        if ( $line =~ /^RT-/i ) {
-
-            push ( @pseudoheaders, $line );
-        }
-
-        #If we find a line that's not a command, get out.
-        else {
-            unshift ( @{$lines}, $line );
-            last;
-        }
-    }
-
-    return (@pseudoheaders);
-
-}
-
-# }}}
-
-# {{{ sub ActOnPseudoHeaders
-
-=item ActOnPseudoHeaders $PseudoHeaders
-
-Takes a string of pseudo-headers, iterates through them and does what they tell it to.
-
-=cut
-
-sub ActOnPseudoHeaders {
-    my $CurrentUser = shift;
-    my (@actions) = (@_);
-
-    my $ResultsMessage = '';
-    my $Ticket         = RT::Ticket->new($CurrentUser);
-
-    foreach my $action (@actions) {
-        my ($val);
-        my $msg = '';
-
-        $ResultsMessage .= ">>> $action\n";
-
-        if ( $action =~ /^RT-(.*?):\s*(.*)$/i ) {
-            my $command = $1;
-            my $args    = $2;
-
-            if ( $command =~ /^ticket$/i ) {
-
-                $val = $Ticket->Load($args);
-                unless ($val) {
-                    $ResultsMessage .=
-                      loc("ERROR: Couldn't load ticket '[_1]': [_2].\n", $1, $msg);
-                      . loc("Aborting to avoid unintended ticket modifications.\n")
-                      . loc("The following commands were not proccessed:\n\n")
-                      . join ( "\n", @actions );
-                    return ($ResultsMessage);
-                }
-                $ResultsMessage .= loc("Ticket [_1] loaded\n", $Ticket->Id);
-            }
-            else {
-                unless ( $Ticket->Id ) {
-                    $ResultsMessage .= loc("No Ticket specified. Aborting ticket ")
-                      . loc("modifications\n\n")
-                      . loc("The following commands were not proccessed:\n\n")
-                      . join ( "\n", @actions );
-                    return ($ResultsMessage);
-                }
-
-                # Deal with the basics
-                if ( $command =~ /^(Subject|Owner|Status|Queue)$/i ) {
-                    my $method = 'Set' . ucfirst( lc($1) );
-                    ( $val, $msg ) = $Ticket->$method($args);
-                }
-
-                # Deal with the dates
-                elsif ( $command =~ /^(due|starts|started|resolved)$/i ) {
-                    my $method = 'Set' . ucfirst( lc($1) );
-                    my $date   = new RT::Date($CurrentUser);
-                    $date->Set( Format => 'unknown', Value => $args );
-                    ( $val, $msg ) = $Ticket->$method( $date->ISO );
-                }
-
-                # Deal with the watchers
-                elsif ( $command =~ /^(requestor|requestors|cc|admincc)$/i ) {
-                    my $operator = "+";
-                    my ($type);
-                    if ( $args =~ /^(\+|\-)(.*)$/ ) {
-                        $operator = $1;
-                        $args     = $2;
-                    }
-                    $type = 'Requestor' if ( $command =~ /^requestor/i );
-                    $type = 'Cc'        if ( $command =~ /^cc/i );
-                    $type = 'AdminCc'   if ( $command =~ /^admincc/i );
-
-                       my $user = RT::User->new($CurrentUser);
-                    $user->Load($args);
-
-                    if ($operator eq '+') {
-                        ($val, $msg) = $Ticket->AddWatcher( Type => $type,
-                                                            PrincipalId => $user->PrincipalId);
-                    } elsif ($operator eq '-') {
-                        ($val, $msg) = $Ticket->DeleteWatcher( Type => $type,
-                                                               PrincipalId => $user->PrincipalId);
-                    }
-
-            }
-            $ResultsMessage .= $msg . "\n";
-        }
-
-    }
-    return ($ResultsMessage);
-
-}
-
-# }}}
-
-# {{{ sub untaint 
-sub untaint {
-    my $val = shift;
-
-    if ( $val =~ /^([-\#\/\w.]+)$/ ) {
-        $val = $1;    # $data now untainted
-    }
-    else {
-        die loc("Bad data in [_1]", $val);    # log this somewhere
-    }
-    return ($val);
-}
-
-# }}}
-
-=head1 AUTHOR
-
-
-
-  rt-commit-handler is a rewritten version of the NetBSD commit handler,
-  which was placed in the public domain by Charles Hannum. It bore the following
-  authors statement:
-
- Contributed by David Hampton <hampton@cisco.com>
- Hacked greatly by Greg A. Woods <woods@planix.com>
- Rewritten by Charles M. Hannum <mycroft@netbsd.org>
-
-=cut
-