This commit was generated by cvs2svn to compensate for changes in r4407,
[freeside.git] / rt / lib / RT / Interface / Web.pm
index 0151cc1..5097f54 100644 (file)
@@ -1,14 +1,8 @@
-# {{{ BEGIN BPS TAGGED BLOCK
+# BEGIN LICENSE BLOCK
 # 
-# COPYRIGHT:
-#  
-# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
-#                                          <jesse@bestpractical.com>
+# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
 # 
-# (Except where explicitly superseded by other copyright notices)
-# 
-# 
-# LICENSE:
+# (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
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 # General Public License for more details.
 # 
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-# 
-# 
-# CONTRIBUTION SUBMISSION POLICY:
-# 
-# (The following paragraph is not intended to limit the rights granted
-# to you to modify and distribute this software under the terms of
-# the GNU General Public License and is only of importance to you if
-# you choose to contribute your changes and enhancements to the
-# community by submitting them to Best Practical Solutions, LLC.)
+# 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.
 # 
-# By intentionally submitting any modifications, corrections or
-# derivatives to this work, or any other work intended for use with
-# Request Tracker, to Best Practical Solutions, LLC, you confirm that
-# you are the copyright holder for those contributions and you grant
-# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
-# royalty-free, perpetual, license to use, copy, create derivative
-# works based on those contributions, and sublicense and distribute
-# those contributions and any derivatives thereof.
 # 
-# }}} END BPS TAGGED BLOCK
+# END LICENSE BLOCK
 ## Portions Copyright 2000 Tobias Brox <tobix@fsck.com>
 
 ## This is a library of static subs to be used by the Mason web
@@ -67,83 +45,94 @@ use strict;
 
 
 
-# {{{ EscapeUTF8
 
-=head2 EscapeUTF8 SCALARREF
 
-does a css-busting but minimalist escaping of whatever html you're passing in.
+# {{{ sub NewApacheHandler 
 
-=cut
+=head2 NewApacheHandler
 
-sub EscapeUTF8  {
-        my  $ref = shift;
-        my $val = $$ref;
-        use bytes;
-        $val =~ s/&/&#38;/g;
-        $val =~ s/</&lt;/g; 
-        $val =~ s/>/&gt;/g;
-        $val =~ s/\(/&#40;/g;
-        $val =~ s/\)/&#41;/g;
-        $val =~ s/"/&#34;/g;
-        $val =~ s/'/&#39;/g;
-        $$ref = $val;
-        Encode::_utf8_on($$ref);
+  Takes extra options to pass to HTML::Mason::ApacheHandler->new
+  Returns a new Mason::ApacheHandler object
 
+=cut
 
+sub NewApacheHandler {
+    require HTML::Mason::ApacheHandler;
+    my $ah = new HTML::Mason::ApacheHandler( 
+    
+        comp_root                    => [
+            [ local    => $RT::MasonLocalComponentRoot ],
+            [ standard => $RT::MasonComponentRoot ]
+        ],
+        args_method => "CGI",
+        default_escape_flags => 'h',
+        allow_globals        => [qw(%session)],
+        data_dir => "$RT::MasonDataDir",
+        @_
+    );
+
+    $ah->interp->set_escape( h => \&RT::Interface::Web::EscapeUTF8 );
+    
+    return ($ah);
 }
 
 # }}}
 
-# {{{ WebCanonicalizeInfo
+# {{{ sub NewCGIHandler 
 
-=head2 WebCanonicalizeInfo();
+=head2 NewCGIHandler
 
-Different web servers set different environmental varibles. This
-function must return something suitable for REMOTE_USER. By default,
-just downcase $ENV{'REMOTE_USER'}
+  Returns a new Mason::CGIHandler object
 
 =cut
 
-sub WebCanonicalizeInfo {
-    my $user;
-
-    if ( defined $ENV{'REMOTE_USER'} ) {
-       $user = lc ( $ENV{'REMOTE_USER'} ) if( length($ENV{'REMOTE_USER'}) );
-    }
+sub NewCGIHandler {
+    my %args = (
+        @_
+    );
 
-    return $user;
-}
+    my $handler = HTML::Mason::CGIHandler->new(
+        comp_root                    => [
+            [ local    => $RT::MasonLocalComponentRoot ],
+            [ standard => $RT::MasonComponentRoot ]
+        ],
+        data_dir => "$RT::MasonDataDir",
+        default_escape_flags => 'h',
+        allow_globals        => [qw(%session)]
+    );
+  
 
-# }}}
+    $handler->interp->set_escape( h => \&RT::Interface::Web::EscapeUTF8 );
 
-# {{{ WebExternalAutoInfo
 
-=head2 WebExternalAutoInfo($user);
+    return ($handler);
 
-Returns a hash of user attributes, used when WebExternalAuto is set.
+}
+# }}}
 
-=cut
 
-sub WebExternalAutoInfo {
-    my $user = shift;
+# {{{ EscapeUTF8
 
-    my %user_info;
+=head2 EscapeUTF8 SCALARREF
 
-    $user_info{'Privileged'} = 1;
+does a css-busting but minimalist escaping of whatever html you're passing in.
 
-    if ($^O !~ /^(?:riscos|MacOS|MSWin32|dos|os2)$/) {
-       # Populate fields with information from Unix /etc/passwd
+=cut
 
-       my ($comments, $realname) = (getpwnam($user))[5, 6];
-       $user_info{'Comments'} = $comments if defined $comments;
-       $user_info{'RealName'} = $realname if defined $realname;
-    }
-    elsif ($^O eq 'MSWin32' and eval 'use Net::AdminMisc; 1') {
-       # Populate fields with information from NT domain controller
-    }
+sub EscapeUTF8  {
+        my  $ref = shift;
+        my $val = $$ref;
+        use bytes;
+        $val =~ s/&/&#38;/g;
+        $val =~ s/</&lt;/g; 
+        $val =~ s/>/&gt;/g;
+        $val =~ s/\(/&#40;/g;
+        $val =~ s/\)/&#41;/g;
+        $val =~ s/"/&#34;/g;
+        $val =~ s/'/&#39;/g;
+        $$ref = $val;
+        Encode::_utf8_on($$ref);
 
-    # and return the wad of stuff
-    return {%user_info};
 }
 
 # }}}
@@ -171,13 +160,10 @@ sub loc {
         UNIVERSAL::can($session{'CurrentUser'}, 'loc')){
         return($session{'CurrentUser'}->loc(@_));
     }
-    elsif ( my $u = eval { RT::CurrentUser->new($RT::SystemUser->Id) } ) {
+    else  {
+        my $u = RT::CurrentUser->new($RT::SystemUser);
         return ($u->loc(@_));
     }
-    else {
-       # pathetic case -- SystemUser is gone.
-       return $_[0];
-    }
 }
 
 # }}}
@@ -203,7 +189,7 @@ sub loc_fuzzy {
         return($session{'CurrentUser'}->loc_fuzzy($msg));
     }
     else  {
-        my $u = RT::CurrentUser->new($RT::SystemUser->Id);
+        my $u = RT::CurrentUser->new($RT::SystemUser);
         return ($u->loc_fuzzy($msg));
     }
 }
@@ -275,7 +261,6 @@ sub CreateTicket {
     }
 
     my %create_args = (
-        Type            => $ARGS{'Type'} || 'ticket',
         Queue           => $ARGS{'Queue'},
         Owner           => $ARGS{'Owner'},
         InitialPriority => $ARGS{'InitialPriority'},
@@ -292,54 +277,36 @@ sub CreateTicket {
         Starts          => $starts->ISO,
         MIMEObj         => $MIMEObj
     );
-    foreach my $arg (%ARGS) {
+  foreach my $arg (%ARGS) {
         if ($arg =~ /^CustomField-(\d+)(.*?)$/) {
             next if ($arg =~ /-Magic$/);
             $create_args{"CustomField-".$1} = $ARGS{"$arg"};
         }
     }
-
-    # turn new link lists into arrays, and pass in the proper arguments
-    my (@dependson, @dependedonby, 
-       @parents, @children, 
-       @refersto, @referredtoby);
-
-    foreach my $luri ( split ( / /, $ARGS{"new-DependsOn"} ) ) {
-       $luri =~ s/\s*$//;    # Strip trailing whitespace
-       push @dependson, $luri;
-    }
-    $create_args{'DependsOn'} = \@dependson;
-
-    foreach my $luri ( split ( / /, $ARGS{"DependsOn-new"} ) ) {
-       push @dependedonby, $luri;
-    }
-    $create_args{'DependedOnBy'} = \@dependedonby;
-
-    foreach my $luri ( split ( / /, $ARGS{"new-MemberOf"} ) ) {
-       $luri =~ s/\s*$//;    # Strip trailing whitespace
-       push @parents, $luri;
-    }
-    $create_args{'Parents'} = \@parents;
-
-    foreach my $luri ( split ( / /, $ARGS{"MemberOf-new"} ) ) {
-       push @children, $luri;
+    my ( $id, $Trans, $ErrMsg ) = $Ticket->Create(%create_args);
+    unless ( $id && $Trans ) {
+        Abort($ErrMsg);
     }
-    $create_args{'Children'} = \@children;
+    my @linktypes = qw( DependsOn MemberOf RefersTo );
 
-    foreach my $luri ( split ( / /, $ARGS{"new-RefersTo"} ) ) {
-       $luri =~ s/\s*$//;    # Strip trailing whitespace
-       push @refersto, $luri;
-    }
-    $create_args{'RefersTo'} = \@refersto;
+    foreach my $linktype (@linktypes) {
+        foreach my $luri ( split ( / /, $ARGS{"new-$linktype"} ) ) {
+            $luri =~ s/\s*$//;    # Strip trailing whitespace
+            my ( $val, $msg ) = $Ticket->AddLink(
+                Target => $luri,
+                Type   => $linktype
+            );
+            push ( @Actions, $msg ) unless ($val);
+        }
 
-    foreach my $luri ( split ( / /, $ARGS{"RefersTo-new"} ) ) {
-       push @referredtoby, $luri;
-    }
-    $create_args{'ReferredToBy'} = \@referredtoby;
+        foreach my $luri ( split ( / /, $ARGS{"$linktype-new"} ) ) {
+            my ( $val, $msg ) = $Ticket->AddLink(
+                Base => $luri,
+                Type => $linktype
+            );
 
-    my ( $id, $Trans, $ErrMsg ) = $Ticket->Create(%create_args);
-    unless ( $id && $Trans ) {
-        Abort($ErrMsg);
+            push ( @Actions, $msg ) unless ($val);
+        }
     }
 
     push ( @Actions, split("\n", $ErrMsg) );
@@ -398,9 +365,7 @@ sub ProcessUpdateMessage {
     );
 
     #Make the update content have no 'weird' newlines in it
-    if ( $args{ARGSRef}->{'UpdateTimeWorked'} ||
-        $args{ARGSRef}->{'UpdateContent'} ||
-        $args{ARGSRef}->{'UpdateAttachments'}) {
+    if ( $args{ARGSRef}->{'UpdateContent'} ) {
 
         if (
             $args{ARGSRef}->{'UpdateSubject'} eq $args{'TicketObj'}->Subject() )
@@ -420,7 +385,7 @@ sub ProcessUpdateMessage {
 
         ## TODO: Implement public comments
         if ( $args{ARGSRef}->{'UpdateType'} =~ /^(private|public)$/ ) {
-            my ( $Transaction, $Description, $Object ) = $args{TicketObj}->Comment(
+            my ( $Transaction, $Description ) = $args{TicketObj}->Comment(
                 CcMessageTo  => $args{ARGSRef}->{'UpdateCc'},
                 BccMessageTo => $args{ARGSRef}->{'UpdateBcc'},
                 MIMEObj      => $Message,
@@ -429,7 +394,7 @@ sub ProcessUpdateMessage {
             push ( @{ $args{Actions} }, $Description );
         }
         elsif ( $args{ARGSRef}->{'UpdateType'} eq 'response' ) {
-            my ( $Transaction, $Description, $Object ) = $args{TicketObj}->Correspond(
+            my ( $Transaction, $Description ) = $args{TicketObj}->Correspond(
                 CcMessageTo  => $args{ARGSRef}->{'UpdateCc'},
                 BccMessageTo => $args{ARGSRef}->{'UpdateBcc'},
                 MIMEObj      => $Message,
@@ -468,8 +433,7 @@ sub MakeMIMEEntity {
         Cc                  => undef,
         Body                => undef,
         AttachmentFieldName => undef,
-#        map Encode::encode_utf8($_), @_,
-        @_,
+        map Encode::encode_utf8($_), @_,
     );
 
     #Make the update content have no 'weird' newlines in it
@@ -485,7 +449,6 @@ sub MakeMIMEEntity {
             Subject => $args{'Subject'} || "",
             From    => $args{'From'},
             Cc      => $args{'Cc'},
-            Charset => 'utf8',
             Data    => [ $args{'Body'} ]
         );
     }
@@ -500,14 +463,7 @@ sub MakeMIMEEntity {
 
     #foreach my $filehandle (@filenames) {
 
-    my ( $fh, $temp_file );
-    for ( 1 .. 10 ) {
-        # on NFS and NTFS, it is possible that tempfile() conflicts
-        # with other processes, causing a race condition. we try to
-        # accommodate this by pausing and retrying.
-        last if ($fh, $temp_file) = eval { tempfile( UNLINK => 1) };
-        sleep 1;
-    }
+    my ( $fh, $temp_file ) = tempfile();
 
     binmode $fh;    #thank you, windows
     my ($buffer);
@@ -525,7 +481,7 @@ sub MakeMIMEEntity {
 
     $Message->attach(
         Path     => $temp_file,
-        Filename => Encode::decode_utf8($filename),
+        Filename => $filename,
         Type     => $uploadinfo->{'Content-Type'},
     );
     close($fh);
@@ -638,13 +594,13 @@ sub ProcessSearchQuery {
 
     # }}}
     # {{{ Limit requestor email
-     if ( $args{ARGS}->{'ValueOfWatcherRole'} ne '' ) {
-         $session{'tickets'}->LimitWatcher(
-             TYPE     => $args{ARGS}->{'WatcherRole'},
-             VALUE    => $args{ARGS}->{'ValueOfWatcherRole'},
-             OPERATOR => $args{ARGS}->{'WatcherRoleOp'},
 
+    if ( $args{ARGS}->{'ValueOfRequestor'} ne '' ) {
+        my $alias = $session{'tickets'}->LimitRequestor(
+            VALUE    => $args{ARGS}->{'ValueOfRequestor'},
+            OPERATOR => $args{ARGS}->{'RequestorOp'},
         );
+
     }
 
     # }}}
@@ -824,13 +780,17 @@ sub ProcessACLChanges {
 
             my $obj;
 
-             if ($object_type eq 'RT::System') {
-                $obj = $RT::System;
-           } elsif ($RT::ACE::OBJECT_TYPES{$object_type}) {
-                $obj = $object_type->new($session{'CurrentUser'});
+            if ($object_type eq 'RT::Queue') {
+                $obj = RT::Queue->new($session{'CurrentUser'});
+                $obj->Load($object_id);      
+            } elsif ($object_type eq 'RT::Group') {
+                $obj = RT::Group->new($session{'CurrentUser'});
                 $obj->Load($object_id);      
+
+            } elsif ($object_type eq 'RT::System') {
+                $obj = $RT::System;
             } else {
-                push (@results, loc("System Error"). ': '.
+                push (@results, loc("System Error").
                                 loc("Rights could not be granted for [_1]", $object_type));
                 next;
             }
@@ -853,14 +813,17 @@ sub ProcessACLChanges {
             next unless ($right);
             my $obj;
 
-             if ($object_type eq 'RT::System') {
-                $obj = $RT::System;
-           } elsif ($RT::ACE::OBJECT_TYPES{$object_type}) {
-                $obj = $object_type->new($session{'CurrentUser'});
+            if ($object_type eq 'RT::Queue') {
+                $obj = RT::Queue->new($session{'CurrentUser'});
                 $obj->Load($object_id);      
+            } elsif ($object_type eq 'RT::Group') {
+                $obj = RT::Group->new($session{'CurrentUser'});
+                $obj->Load($object_id);      
+
+            } elsif ($object_type eq 'RT::System') {
+                $obj = $RT::System;
             } else {
-               die;
-                push (@results, loc("System Error"). ': '.
+                push (@results, loc("System Error").
                                 loc("Rights could not be revoked for [_1]", $object_type));
                 next;
             }
@@ -896,12 +859,52 @@ sub UpdateRecordObject {
         @_
     );
 
-    my $Object = $args{'Object'};
-    my @results = $Object->Update(AttributesRef => $args{'AttributesRef'},
-                                 ARGSRef       => $args{'ARGSRef'},
-                  AttributePrefix => $args{'AttributePrefix'}
-                                 );
+    my (@results);
 
+    my $object     = $args{'Object'};
+    my $attributes = $args{'AttributesRef'};
+    my $ARGSRef    = $args{'ARGSRef'};
+    foreach my $attribute (@$attributes) {
+        my $value;
+        if ( defined $ARGSRef->{$attribute} ) {
+            $value = $ARGSRef->{$attribute};
+        }
+        elsif (
+              defined( $args{'AttributePrefix'} )
+              && defined(
+                  $ARGSRef->{ $args{'AttributePrefix'} . "-" . $attribute }
+              )
+          ) {
+            $value = $ARGSRef->{ $args{'AttributePrefix'} . "-" . $attribute };
+
+        } else {
+                next;
+        }
+
+            $value =~ s/\r\n/\n/gs;
+
+        if ($value ne $object->$attribute()){
+
+              my $method = "Set$attribute";
+              my ( $code, $msg ) = $object->$method($value);
+
+              push @results, loc($attribute) . ': ' . loc_fuzzy($msg);
+=for loc
+                                   "[_1] could not be set to [_2].",       # loc
+                                   "That is already the current value",    # loc
+                                   "No value sent to _Set!\n",             # loc
+                                   "Illegal value for [_1]",               # loc
+                                   "The new value has been set.",          # loc
+                                   "No column specified",                  # loc
+                                   "Immutable field",                      # loc
+                                   "Nonexistant field?",                   # loc
+                                   "Invalid data",                         # loc
+                                   "Couldn't find row",                    # loc
+                                   "Missing a primary key?: [_1]",         # loc
+                                   "Found Object",                         # loc
+=cut
+          };
+    }
     return (@results);
 }
 
@@ -950,17 +953,6 @@ sub ProcessCustomFieldUpdates {
         my ( $err, $msg ) = $Object->DeleteValue($id);
         push ( @results, $msg );
     }
-
-    my $vals = $Object->Values();
-    while (my $cfv = $vals->Next()) {
-        if (my $so = $ARGSRef->{ 'CustomField-' . $Object->Id . '-SortOrder' . $cfv->Id }) {
-            if ($cfv->SortOrder != $so) {
-                my ( $err, $msg ) = $cfv->SetSortOrder($so);
-                push ( @results, $msg );
-            }
-        }
-    }
-
     return (@results);
 }
 
@@ -993,7 +985,6 @@ sub ProcessTicketBasics {
       TimeEstimated
       TimeWorked
       TimeLeft
-      Type
       Status
       Queue
     );
@@ -1006,8 +997,6 @@ sub ProcessTicketBasics {
         }
     }
 
-    $ARGSRef->{'Status'} ||= $TicketObj->Status;
-    
     my @results = UpdateRecordObject(
         AttributesRef => \@attribs,
         Object        => $TicketObj,
@@ -1061,11 +1050,8 @@ sub ProcessTicketCustomFieldUpdates {
 
     # For each of those tickets
     foreach my $tick ( keys %custom_fields_to_mod ) {
-        my $Ticket = $args{'TicketObj'};
-       if (!$Ticket or $Ticket->id != $tick) {
-           $Ticket = RT::Ticket->new( $session{'CurrentUser'} );
-           $Ticket->Load($tick);
-       }
+        my $Ticket = RT::Ticket->new( $session{'CurrentUser'} );
+        $Ticket->Load($tick);
 
         # For each custom field  
         foreach my $cf ( keys %{ $custom_fields_to_mod{$tick} } ) {
@@ -1088,15 +1074,10 @@ sub ProcessTicketCustomFieldUpdates {
                 my @values =
                   ( ref( $ARGSRef->{$arg} ) eq 'ARRAY' ) 
                   ? @{ $ARGSRef->{$arg} }
-                  : split /\n/, $ARGSRef->{$arg} ;
-
-               #for poor windows boxen that pass in "\r\n"
-               local $/ = "\r";
-               chomp @values;
-
+                  : ( $ARGSRef->{$arg} );
                 if ( ( $arg =~ /-AddValue$/ ) || ( $arg =~ /-Value$/ ) ) {
                     foreach my $value (@values) {
-                        next unless length($value);
+                        next unless ($value);
                         my ( $val, $msg ) = $Ticket->AddCustomFieldValue(
                             Field => $cf,
                             Value => $value
@@ -1106,7 +1087,7 @@ sub ProcessTicketCustomFieldUpdates {
                 }
                 elsif ( $arg =~ /-DeleteValues$/ ) {
                     foreach my $value (@values) {
-                        next unless length($value);
+                        next unless ($value);
                         my ( $val, $msg ) = $Ticket->DeleteCustomFieldValue(
                             Field => $cf,
                             Value => $value
@@ -1119,7 +1100,7 @@ sub ProcessTicketCustomFieldUpdates {
 
                     my %values_hash;
                     foreach my $value (@values) {
-                        next unless length($value);
+                        next unless ($value);
 
                         # build up a hash of values that the new set has
                         $values_hash{$value} = 1;
@@ -1204,7 +1185,7 @@ sub ProcessTicketWatchers {
     foreach my $key ( keys %$ARGSRef ) {
 
         # {{{ Delete deletable watchers
-        if ( ( $key =~ /^Ticket-DeleteWatcher-Type-(.*)-Principal-(\d+)$/ )  ) {
+        if ( ( $key =~ /^Ticket-DelWatcher-Type-(.*)-Principal-(\d+)$/ )  ) {
             my ( $code, $msg ) = 
                 $Ticket->DeleteWatcher(PrincipalId => $2,
                                        Type => $1);
@@ -1212,8 +1193,8 @@ sub ProcessTicketWatchers {
         }
 
         # Delete watchers in the simple style demanded by the bulk manipulator
-        elsif ( $key =~ /^Delete(Requestor|Cc|AdminCc)$/ ) {       
-            my ( $code, $msg ) = $Ticket->DeleteWatcher( Email => $ARGSRef->{$key}, Type => $1 );
+        elsif ( $key =~ /^Delete(Requestor|Cc|AdminCc)$/ ) {
+            my ( $code, $msg ) = $Ticket->DeleteWatcher( Type => $ARGSRef->{$key}, PrincipalId => $1 );
             push @results, $msg;
         }
 
@@ -1333,29 +1314,6 @@ sub ProcessTicketLinks {
     my $Ticket  = $args{'TicketObj'};
     my $ARGSRef = $args{'ARGSRef'};
 
-    my (@results) = ProcessRecordLinks(RecordObj => $Ticket,
-                                      ARGSRef => $ARGSRef);
-
-    #Merge if we need to
-    if ( $ARGSRef->{ $Ticket->Id . "-MergeInto" } ) {
-        my ( $val, $msg ) =
-          $Ticket->MergeInto( $ARGSRef->{ $Ticket->Id . "-MergeInto" } );
-        push @results, $msg;
-    }
-
-    return (@results);
-}
-
-# }}}
-
-sub ProcessRecordLinks {
-    my %args = ( RecordObj => undef,
-                 ARGSRef   => undef,
-                 @_ );
-
-    my $Record  = $args{'RecordObj'};
-    my $ARGSRef = $args{'ARGSRef'};
-
     my (@results);
 
     # Delete links that are gone gone gone.
@@ -1367,7 +1325,7 @@ sub ProcessRecordLinks {
 
             push @results,
               "Trying to delete: Base: $base Target: $target  Type $type";
-            my ( $val, $msg ) = $Record->DeleteLink( Base   => $base,
+            my ( $val, $msg ) = $Ticket->DeleteLink( Base   => $base,
                                                      Type   => $type,
                                                      Target => $target );
 
@@ -1380,18 +1338,18 @@ sub ProcessRecordLinks {
     my @linktypes = qw( DependsOn MemberOf RefersTo );
 
     foreach my $linktype (@linktypes) {
-        if ( $ARGSRef->{ $Record->Id . "-$linktype" } ) {
-            for my $luri ( split ( / /, $ARGSRef->{ $Record->Id . "-$linktype" } ) ) {
+        if ( $ARGSRef->{ $Ticket->Id . "-$linktype" } ) {
+            for my $luri ( split ( / /, $ARGSRef->{ $Ticket->Id . "-$linktype" } ) ) {
                 $luri =~ s/\s*$//;    # Strip trailing whitespace
-                my ( $val, $msg ) = $Record->AddLink( Target => $luri,
+                my ( $val, $msg ) = $Ticket->AddLink( Target => $luri,
                                                       Type   => $linktype );
                 push @results, $msg;
             }
         }
-        if ( $ARGSRef->{ "$linktype-" . $Record->Id } ) {
+        if ( $ARGSRef->{ "$linktype-" . $Ticket->Id } ) {
 
-            for my $luri ( split ( / /, $ARGSRef->{ "$linktype-" . $Record->Id } ) ) {
-                my ( $val, $msg ) = $Record->AddLink( Base => $luri,
+            for my $luri ( split ( / /, $ARGSRef->{ "$linktype-" . $Ticket->Id } ) ) {
+                my ( $val, $msg ) = $Ticket->AddLink( Base => $luri,
                                                       Type => $linktype );
 
                 push @results, $msg;
@@ -1399,9 +1357,18 @@ sub ProcessRecordLinks {
         } 
     }
 
+    #Merge if we need to
+    if ( $ARGSRef->{ $Ticket->Id . "-MergeInto" } ) {
+        my ( $val, $msg ) =
+          $Ticket->MergeInto( $ARGSRef->{ $Ticket->Id . "-MergeInto" } );
+        push @results, $msg;
+    }
+
     return (@results);
 }
 
+# }}}
+
 eval "require RT::Interface::Web_Vendor";
 die $@ if ($@ && $@ !~ qr{^Can't locate RT/Interface/Web_Vendor.pm});
 eval "require RT::Interface::Web_Local";