This commit was manufactured by cvs2svn to create tag 'freeside_1_5_7'. freeside_1_5_7
authorcvs2git <cvs2git>
Thu, 5 Jan 2006 09:34:33 +0000 (09:34 +0000)
committercvs2git <cvs2git>
Thu, 5 Jan 2006 09:34:33 +0000 (09:34 +0000)
59 files changed:
ANNOUNCE.1.5 [deleted file]
bin/rate.import
bin/rt-drop-tables [new file with mode: 0755]
httemplate/search/cust_bill.cgi [deleted file]
rt/Makefile
rt/README
rt/bin/mason_handler.fcgi
rt/bin/mason_handler.scgi
rt/bin/rt-mailgate
rt/bin/webmux.pl [deleted file]
rt/config.pld [new file with mode: 0644]
rt/etc/acl.Oracle
rt/etc/acl.Pg
rt/etc/acl.mysql
rt/etc/schema.Pg
rt/etc/schema.mysql
rt/lib/RT.pm
rt/lib/RT/ACE.pm
rt/lib/RT/ACL.pm
rt/lib/RT/Action/Autoreply.pm
rt/lib/RT/Action/Generic.pm
rt/lib/RT/Action/Notify.pm
rt/lib/RT/Action/NotifyAsComment.pm
rt/lib/RT/Action/ResolveMembers.pm
rt/lib/RT/Action/SendEmail.pm
rt/lib/RT/Attachment.pm
rt/lib/RT/Attachments.pm
rt/lib/RT/Condition/AnyTransaction.pm
rt/lib/RT/Condition/Generic.pm
rt/lib/RT/Condition/StatusChange.pm
rt/lib/RT/CurrentUser.pm
rt/lib/RT/Date.pm
rt/lib/RT/Group.pm
rt/lib/RT/GroupMember.pm
rt/lib/RT/GroupMembers.pm
rt/lib/RT/Groups.pm
rt/lib/RT/Handle.pm
rt/lib/RT/Interface/CLI.pm
rt/lib/RT/Interface/Email.pm
rt/lib/RT/Interface/Web.pm
rt/lib/RT/Link.pm
rt/lib/RT/Links.pm
rt/lib/RT/Queue.pm
rt/lib/RT/Queues.pm
rt/lib/RT/Record.pm
rt/lib/RT/Scrip.pm
rt/lib/RT/ScripAction.pm
rt/lib/RT/ScripActions.pm
rt/lib/RT/ScripCondition.pm
rt/lib/RT/ScripConditions.pm
rt/lib/RT/Scrips.pm
rt/lib/RT/Template.pm
rt/lib/RT/Templates.pm
rt/lib/RT/Ticket.pm
rt/lib/RT/Tickets.pm
rt/lib/RT/Transaction.pm
rt/lib/RT/Transactions.pm
rt/lib/RT/User.pm
rt/lib/RT/Users.pm

diff --git a/ANNOUNCE.1.5 b/ANNOUNCE.1.5
deleted file mode 100644 (file)
index 36c78e1..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-- broadband (dsl/wireless) tracking, etc etc
-- Extended description on invoice for time/data charges
-- Multiple, named taxes
-- */*FIX
-- extended reported and graphing
-- integrated RT ticketing system
-- one-time payments (in signup server too).  DCRD and DCHK on-demand payment types
-- credit report
-- reseller interface
-
-1.5.0pre6:
-- RADIUS session viewing
-- Major updates for reseller interface
-- Credit card and ACH refunds (w/supported processor module)
-- Proper email payment receipts (not invoice copies)
-- modular price plans, rewrote package add/edit page
-- fixed up tax report - should be correct for edge cases with named taxes,
-  tax classes, etc.
-- Documentation updates
-
-1.5.7:
-- version numbering change, now even/odd like Perl or Linux
-- fix bug that could cause mis-billing on upgrades! (new installs ok)
-- updated install documentation
-- historical late notice viewing in web interface
-- VoIP billing for CDRs from RADIUS
-- promotional codes for signup
-- lots of RT integration, integrated RT upgraded to 3.2.2, preliminary RT 
-  add-on docs
-- one-time referral credits
-- invoices now use history records (don't lose details)
-- option to credit for remaining service upon package cancel/change
-  (peter bowen)
-- one-time registration codes
-- "selfservice_server-session_module" config value can be set to
-  "Cache::FileCache" on FreeBSD or elsewhere IPC::ShareLite has trouble.
-- package changes don't re-charge setup fee
-- per-agent payment and credit reports
-- CSV and Excel export of most reports, others to be migrated to new report template
-- prepaid card support updated: now includes a web generator, agent-specific
-  prepaid cards, and creates *payments*, not credits
-- preliminary setup for Slony-1 PostgreSQL replication
-- reformatted latex invoice templates w/Text::Template (khoff) and removed
-  some useless fields (quantity/unit price)
-- simplified upgrade instructions
-- add export to vpopmail SQL
-- html invoices
-- big self-service updates (recharge w/prepaid card, change info, more)
-- significant freeside-daily speedup
-
-notyet (1.5.8?):
-- account merging UI in exports (for example, to consolidate passwd files from
-  multiple servers)
-
index 29b5239..fdd756d 100755 (executable)
@@ -59,15 +59,25 @@ while ( my $row = $sth->fetchrow_hashref ) {
     $prefix = $2;
   }
 
-  my @rate_prefix = map { 
-                          #warn $row->{'Country'}. ": $prefixprefix$_\n";
-                          new FS::rate_prefix {
-                            'countrycode' => $row->{'Code'},
-                            'npa'         => $prefixprefix.$_,
-                          };
-                        }
-                        split(/\s*[;,]\s*/, $prefix);
-
+  my @rate_prefix = ();
+  if ( $prefix =~ /\d/ ) {
+
+    @rate_prefix = map { 
+                         #warn $row->{'Country'}. ": $prefixprefix$_\n";
+                         new FS::rate_prefix {
+                           'countrycode' => $row->{'Code'},
+                           'npa'         => $prefixprefix.$_,
+                         };
+                       }
+                       split(/\s*[;,]\s*/, $prefix);
+
+  } else {
+    @rate_prefix = ( new FS::rate_prefix {
+                       'countycode' => $row->{'Code'},
+                       'npa'        => '',
+                     };
+                   );
+  }
 
   my $dest_detail = new FS::rate_detail {
                                           'ratenum'         => $ratenum,
diff --git a/bin/rt-drop-tables b/bin/rt-drop-tables
new file mode 100755 (executable)
index 0000000..b027542
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/perl
+
+my @tables = qw(
+Attachments 
+Queues 
+Links 
+Principals 
+Groups 
+ScripConditions 
+Transactions 
+Scrips 
+ACL 
+GroupMembers 
+CachedGroupMembers 
+Users 
+Tickets 
+ScripActions 
+Templates 
+TicketCustomFieldValues 
+CustomFields 
+CustomFieldValues 
+sessions 
+);
+
+foreach my $table ( @tables ) {
+  print "drop table $table;\n";
+  print "drop sequence ${table}_id_seq;\n";
+}
+
diff --git a/httemplate/search/cust_bill.cgi b/httemplate/search/cust_bill.cgi
deleted file mode 100755 (executable)
index 5b0538c..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-<%
-
-my $conf = new FS::Conf;
-my $maxrecords = $conf->config('maxsearchrecordsperpage');
-
-my $orderby = ''; #removeme
-
-my $limit = '';
-$limit .= "LIMIT $maxrecords" if $maxrecords;
-
-my $offset = $cgi->param('offset') || 0;
-$limit .= " OFFSET $offset" if $offset;
-
-my($total, $tot_amount, $tot_balance);
-
-my(@cust_bill);
-if ( $cgi->keywords ) {
-  my($query) = $cgi->keywords;
-  my $owed = "charged - ( select coalesce(sum(amount),0) from cust_bill_pay
-                          where cust_bill_pay.invnum = cust_bill.invnum )
-                      - ( select coalesce(sum(amount),0) from cust_credit_bill
-                          where cust_credit_bill.invnum = cust_bill.invnum )";
-  my @where;
-  if ( $query =~ /^(OPEN(\d*)_)?(invnum|date|custnum)$/ ) {
-    my($open, $days, $field) = ($1, $2, $3);
-    $field = "_date" if $field eq 'date';
-    $orderby = "ORDER BY cust_bill.$field";
-    push @where, "0 != $owed" if $open;
-    push @where, "cust_bill._date < ". (time-86400*$days) if $days;
-  } else {
-    die "unknown query string $query";
-  }
-
-  my $extra_sql = scalar(@where) ? 'WHERE '. join(' AND ', @where) : '';
-
-  my $statement = "SELECT COUNT(*), sum(charged), sum($owed)
-                   FROM cust_bill $extra_sql";
-  my $sth = dbh->prepare($statement) or die dbh->errstr. " doing $statement";
-  $sth->execute or die "Error executing \"$statement\": ". $sth->errstr;
-
-  ( $total, $tot_amount, $tot_balance ) = @{$sth->fetchrow_arrayref};
-
-  @cust_bill = qsearch(
-    'cust_bill',
-    {},
-    "cust_bill.*, $owed as owed",
-    "$extra_sql $orderby $limit"
-  );
-} else {
-  $cgi->param('invnum') =~ /^\s*(FS-)?(\d+)\s*$/;
-  my $invnum = $2;
-  @cust_bill = qsearchs('cust_bill', { 'invnum' => $invnum } );
-  $total = scalar(@cust_bill);
-}
-
-#if ( scalar(@cust_bill) == 1 ) {
-if ( $total == 1 ) {
-  my $invnum = $cust_bill[0]->invnum;
-  print $cgi->redirect(popurl(2). "view/cust_bill.cgi?$invnum");  #redirect
-} elsif ( scalar(@cust_bill) == 0 ) {
-%>
-<!-- mason kludge -->
-<%
-  eidiot("Invoice not found.");
-} else {
-%>
-<!-- mason kludge -->
-<%
-
-  #begin pager
-  my $pager = '';
-  if ( $total != scalar(@cust_bill) && $maxrecords ) {
-    unless ( $offset == 0 ) {
-      $cgi->param('offset', $offset - $maxrecords);
-      $pager .= '<A HREF="'. $cgi->self_url.
-                '"><B><FONT SIZE="+1">Previous</FONT></B></A> ';
-    }
-    my $poff;
-    my $page;
-    for ( $poff = 0; $poff < $total; $poff += $maxrecords ) {
-      $page++;
-      if ( $offset == $poff ) {
-        $pager .= qq!<FONT SIZE="+2">$page</FONT> !;
-      } else {
-        $cgi->param('offset', $poff);
-        $pager .= qq!<A HREF="!. $cgi->self_url. qq!">$page</A> !;
-      }
-    }
-    unless ( $offset + $maxrecords > $total ) {
-      $cgi->param('offset', $offset + $maxrecords);
-      $pager .= '<A HREF="'. $cgi->self_url.
-                '"><B><FONT SIZE="+1">Next</FONT></B></A> ';
-    }
-  }
-  #end pager
-
-  print header("Invoice Search Results", menubar(
-          'Main Menu', popurl(2)
-        )).
-        "$total matching invoices found<BR>".
-        "\$$tot_balance total balance<BR>".
-        "\$$tot_amount total amount<BR>".
-        "<BR>$pager". table(). <<END;
-      <TR>
-        <TH></TH>
-        <TH>Balance</TH>
-        <TH>Amount</TH>
-        <TH>Date</TH>
-        <TH>Contact name</TH>
-        <TH>Company</TH>
-      </TR>
-END
-
-  foreach my $cust_bill ( @cust_bill ) {
-    my($invnum, $owed, $charged, $date ) = (
-      $cust_bill->invnum,
-      sprintf("%.2f", $cust_bill->getfield('owed')),
-      sprintf("%.2f", $cust_bill->charged),
-      $cust_bill->_date,
-    );
-    my $pdate = time2str("%b %d %Y", $date);
-
-    my $rowspan = 1;
-
-    my $view = popurl(2). "view/cust_bill.cgi?$invnum";
-    print <<END;
-      <TR>
-        <TD ROWSPAN=$rowspan><A HREF="$view">$invnum</A></TD>
-        <TD ROWSPAN=$rowspan ALIGN="right"><A HREF="$view">\$$owed</A></TD>
-        <TD ROWSPAN=$rowspan ALIGN="right"><A HREF="$view">\$$charged</A></TD>
-        <TD ROWSPAN=$rowspan><A HREF="$view">$pdate</A></TD>
-END
-    my $custnum = $cust_bill->custnum;
-    my $cust_main = qsearchs('cust_main', { 'custnum' => $custnum } );
-    if ( $cust_main ) {
-      my $cview = popurl(2). "view/cust_main.cgi?". $cust_main->custnum;
-      my ( $name, $company ) = (
-        $cust_main->last. ', '. $cust_main->first,
-        $cust_main->company,
-      );
-      print <<END;
-        <TD ROWSPAN=$rowspan><A HREF="$cview">$name</A></TD>
-        <TD ROWSPAN=$rowspan><A HREF="$cview">$company</A></TD>
-END
-    } else {
-      print <<END
-        <TD ROWSPAN=$rowspan COLSPAN=2>WARNING: couldn't find cust_main.custnum $custnum (cust_bill.invnum $invnum)</TD>
-END
-    }
-
-    print "</TR>";
-  }
-  $tot_balance = sprintf("%.2f", $tot_balance);
-  $tot_amount = sprintf("%.2f", $tot_amount);
-  print "</TABLE>$pager<BR>". table(). <<END;
-      <TR><TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD><TH>Total<BR>Balance</TH><TH>Total<BR>Amount</TH></TR>
-      <TR><TD></TD><TD ALIGN="right">\$$tot_balance</TD><TD ALIGN="right">\$$tot_amount</TD></TD></TR>
-    </TABLE>
-  </BODY>
-</HTML>
-END
-
-}
-
-%>
index 6447221..0895874 100644 (file)
@@ -1,20 +1,19 @@
 # BEGIN LICENSE BLOCK
 # 
-# Copyright (c) 1996-2002 Jesse Vincent <jesse@bestpractical.com>
+# 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
+# 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
@@ -22,8 +21,6 @@
 # 
 # 
 # END LICENSE BLOCK
-
-
 #
 # DO NOT HAND-EDIT the file named 'Makefile'. This file is autogenerated.
 # Have a look at "configure" and "Makefile.in" instead
@@ -39,7 +36,7 @@ SITE_CONFIG_FILE              =       $(CONFIG_FILE_PATH)/RT_SiteConfig.pm
 
 RT_VERSION_MAJOR       =       3
 RT_VERSION_MINOR       =       0
-RT_VERSION_PATCH       =       4
+RT_VERSION_PATCH       =       9
 
 RT_VERSION =   $(RT_VERSION_MAJOR).$(RT_VERSION_MINOR).$(RT_VERSION_PATCH)
 TAG       =    rt-$(RT_VERSION_MAJOR)-$(RT_VERSION_MINOR)-$(RT_VERSION_PATCH)
@@ -101,8 +98,8 @@ RT_MODPERL_HANDLER   =       $(RT_BIN_PATH)/webmux.pl
 RT_FASTCGI_HANDLER     =       $(RT_BIN_PATH)/mason_handler.fcgi
 # RT_WIN32_FASTCGI_HANDLER is the mason handler script for FastCGI
 RT_WIN32_FASTCGI_HANDLER       =       $(RT_BIN_PATH)/mason_handler.svc
-# RT's admin CLI
-RT_CLI_ADMIN_BIN       =       $(RT_BIN_PATH)/rtadmin
+# RT's CLI
+RT_CLI_BIN             =       $(RT_BIN_PATH)/rt
 # RT's mail gateway
 RT_MAILGATE_BIN                =       $(RT_BIN_PATH)/rt-mailgate
 # RT's cron tool
@@ -115,6 +112,7 @@ SETGID_BINARIES             =       $(DESTDIR)/$(RT_FASTCGI_HANDLER) \
 
 BINARIES               =       $(DESTDIR)/$(RT_MODPERL_HANDLER) \
                                $(DESTDIR)/$(RT_MAILGATE_BIN) \
+                               $(DESTDIR)/$(RT_CLI_BIN) \
                                $(DESTDIR)/$(RT_CRON_BIN) \
                                $(SETGID_BINARIES)
 SYSTEM_BINARIES                =       $(DESTDIR)/$(RT_SBIN_PATH)/
@@ -128,6 +126,7 @@ SYSTEM_BINARIES             =       $(DESTDIR)/$(RT_SBIN_PATH)/
 # DB_TYPE defines what sort of database RT trys to talk to
 # "mysql" is known to work.
 # "Pg" is known to work
+# "Informix" is known to work
 
 DB_TYPE                        =       mysql
 
@@ -138,7 +137,8 @@ DB_TYPE                     =       mysql
 
 # For mysql, you probably want 'root'
 # For Pg, you probably want 'postgres' 
-# For oracle, you want 'system'
+# For Oracle, you want 'system'
+# For Informix, you want 'informix'
 
 DB_DBA                 =       root
 
@@ -211,7 +211,7 @@ upgrade-instruct:
        @echo "    $(RT_SBIN_PATH)/rt-setup-database --action insert --datafile etc/upgrade/<version>"
 
 
-upgrade: dirs upgrade-noclobber upgrade-instruct
+upgrade: config-install dirs files-install fixperms upgrade-instruct
 
 upgrade-noclobber: config-install libs-install html-install bin-install local-install doc-install fixperms
 
@@ -312,13 +312,16 @@ config-install:
 test: 
        $(PERL) -Ilib lib/t/00smoke.t
 
-regression-nosetgid-quiet: config-install dirs files-install libs-install sbin-install bin-install regression-instruct regression-reset-db  testify-pods fixperms-nosetgid apachectl
+regression-install: config-install
+       $(PERL) -pi -e 's/Set\(\$$DatabaseName.*\);/Set\(\$$DatabaseName, "rt3regression"\);/' $(DESTDIR)/$(CONFIG_FILE)
+
+regression-nosetgid-quiet: regression-install dirs files-install libs-install sbin-install bin-install regression-instruct regression-reset-db  testify-pods fixperms-nosetgid apachectl
        $(PERL) sbin/regression_harness
 
-regression-nosetgid: config-install dirs files-install libs-install sbin-install bin-install regression-instruct regression-reset-db  testify-pods fixperms-nosetgid apachectl
+regression-nosetgid: regression-install dirs files-install libs-install sbin-install bin-install regression-instruct regression-reset-db  testify-pods fixperms-nosetgid apachectl
        $(PERL) lib/t/02regression.t
 
-regression: config-install dirs files-install libs-install sbin-install bin-install regression-instruct regression-reset-db  testify-pods apachectl
+regression: regression-install dirs files-install libs-install sbin-install bin-install regression-instruct regression-reset-db  testify-pods fixperms apachectl
        $(PERL) lib/t/02regression.t
 
 regression-quiet:
@@ -397,7 +400,9 @@ bin-install:
        -cp -rp \
                bin/rt-mailgate \
                bin/mason_handler.fcgi \
+               bin/mason_handler.scgi \
                bin/mason_handler.svc \
+               bin/rt \
                bin/webmux.pl \
                bin/rt-crontool \
                $(DESTDIR)/$(RT_BIN_PATH)
index 7c5e4d4..9373f69 100755 (executable)
--- a/rt/README
+++ b/rt/README
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
-# END LICENSE BLOCK
+# 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
 RT is an enterprise-grade issue tracking system. It allows
 organizations to keep track of their to-do lists, who is working
 on which tasks, what's already been done, and when tasks were
@@ -28,30 +50,31 @@ completed. It is available under the terms of version 2 of the GNU
 General Public License (GPL), so it doesn't cost anything to set
 up and use.
 
+RT is commercially supported software. To purchase support, training,
+custom development or professional services, please write to
+sales@bestpractical.com. 
 
         Jesse Vincent
         Best Practical Solutions, LLC
-        March 2003
+        June 2004
+
 
 REQUIRED PACKAGES:
 ------------------
 
-o   Perl 5.8.0 or later (http://www.perl.com).
-
-       (If you intend to use the FastCGI or SpeedyCGI support, you 
-        need to make sure that perl has been built with support for 
-        setgid perl scripts.)`
+o   Perl 5.8.3 or later (http://www.perl.com).
 
-    Perl 5.6.1 is currently deprecated and will be officially desupported
-    in a future release
+           Perl versions prior to 5.8.3 contain bugs that could result
+           in data corruption. We recommend strongly that you use 5.8.3
+           or newer. RT may function with perl 5.8.0 and later, but
+           is unsupported in that configuration.
 
 o   A DB backend; MySQL is recommended ( http://www.mysql.com ) 
-        Currently supported:  Mysql 4.0.13 or later
+        Currently supported:  Mysql 4.0.13 or later with InnoDB support.
                               Postgres 7.2 or later.
+                              Oracle 9iR2.
+        Beta-quality support for Informix and SQLite is also available.
 
-                              Mysql 3.23.46 or newer with support for InnoDB 
-                             is currently deprecated and will be officially
-                             desupported in a future release.
 
 o   Apache version 1.3.x or 2.x (http://httpd.apache.org) 
     with mod_perl -- (http://perl.apache.org ) 
@@ -66,23 +89,7 @@ o   Apache version 1.3.x or 2.x (http://httpd.apache.org)
 
         mod_perl 1.x must be build with EVERYTHING=1
 
-        RT's FastCGI handler runs setgid to the 'rt' group to
-        protect RT's database password.  You may need to install
-        a special  "suidperl" package or reconfigure your perl
-        setup to support "setuid scripts" if you intend to use RT
-        with FastCGI.
-
-        Debian GNU/* 3.0+: the package which installs suidperl is
-         called perl-suid, and should work without any tweaking.
-
-        FreeBSD 4.2+: the package is called sperl, and should
-         install a suidperl that just works 
-
-        Conectiva Linux 6.0+: suidperl is installed by default when 
-         perl is installed, but the program /bin/suidperl is not setuid. 
-         You must use chmod to make it setuid.
-
-
+        RT's FastCGI handler needs to access RT's configuration file.
 
 o    Various and sundry perl modules
        A tool included with RT takes care of the installation of
@@ -97,9 +104,10 @@ o    Various and sundry perl modules
 GENERAL INSTALLATION
 --------------------
 
-This is a rough guide to installing RT. For more detail, you'll want 
-to read 'Chapter 2: Installing' in RT's manual, available at
-http://www.bestpractical.com/rt 
+This is a rough guide to installing RT. For more detail, you'll
+want to read a more comprehensive installation guide at:
+
+    http://wiki.bestpractical.com/index.cgi?InstallationGuides
 
 1   Unpack this distribution SOMWHERE OTHER THAN where you want to install RT
 
@@ -112,53 +120,69 @@ http://www.bestpractical.com/rt
         ./configure --help to see the list of options
         ./configure (with the flags you want)
 
-3   Satisfy RT's myriad dependencies. 
+3   Make sure that RT has everything it needs to run:
 
-3.1   Check for compliance:
-        
-   perl sbin/rt-test-dependencies \ 
-                --with-<databasename> --with-<web-environment>
+3.1   Check for missing dependencies:
 
-        databasename is one of: mysql, postgres
-        web-environment is one of: fastcgi, modperl1, modperl2
+        make testdeps        
 
 3.2   If there are unsatisfied dependencies, install them by hand or run:
 
-        perl sbin/rt-test-dependencies \
-                --with-<databasename> --with-<web-environment> --install
-        
+        make fixdeps
 
 3.3   Check to make sure everything was installed properly:
+        
+        make testdeps
 
-        perl sbin/rt-test-dependencies \
-                --with-<databasename> --with-<web-environment>
+        It might sometimes be necessary to run "make fixdeps" several times
+        to install all necessary perl modules.
 
 4   Create a group called 'rt'
 
 5a  FOR A NEW INSTALLATION: 
         
         As root, type:
-                 make install        (replace "make" with the local name for 
-                                 Make, if you need to)
-
+                 make install   
                        
                  make initialize-database 
 
-
         If the make fails, type:
                 make dropdb 
         and start over from step 5a
 
-5b  FOR UPGRADING: (Within the RT 3.0.x series)
+5b  FOR UPGRADING: (Within the RT 3.x series)
+
+        Read through the UPGRADING document included in this distribution.
+        It may contain important instructions which will help you upgrade
+        RT safely.
 
         As root, type: 
-                make upgrade     (replace "make" with the local name for 
-                                  Make, if you need to)
+                make upgrade    
 
         This will build new binaries, config files and libraries without
         overwriting your RT database. 
-        
-        It may then instruct you to update your RT system database objects 
+
+        You may also need to update RT's database.  To find out, type:
+
+           ls etc/upgrade
+
+        For each item in that directory whose name is greater than
+        your previously installed RT version, run:
+            /opt/rt3/sbin/rt-setup-database --action schema \
+                --datadir etc/upgrade/<version>
+            /opt/rt3/sbin/rt-setup-database --action acl \
+                --datadir etc/upgrade/<version>
+            /opt/rt3/sbin/rt-setup-database --action insert \
+                 --datadir etc/upgrade/<version>
+
+
+5c  FOR UPGRADING: (From RT 2.0.x)
+
+    Download the RT2 to RT3 migration tools from:
+
+    http://bestpractical.com/pub/rt/devel/rt2-to-rt3.tar.gz
+
+    Follow the included instructions.
 
 6   Edit etc/RT_SiteConfig.pm in your RT installation directory, by specifying
     any values you need to change from the defaults in etc/RT_Config.pm
@@ -180,43 +204,64 @@ http://www.bestpractical.com/rt
 THE WEB INTERFACE
 -----------------
 
-RT's web interface is based around HTML::Mason, which works best with the mod_perl
-perl interpreter within Apache httpd.  Alternatively, support for the FastCGI
-(and plain CGI) interface is also provided as 'bin/mason_handler.fcgi'.
+RT's web interface is based around HTML::Mason, which works well with
+the mod_perl perl interpreter within Apache httpd and FastCGI
 
-Apache 
-        You'll need to add a few lines to your httpd.conf telling it about RT:
+mod_perl
+--------
+
+To install RT with mod_perl, you'll need to add a few lines to your 
+Apache configuration file telling it about RT:
 
 <VirtualHost your.ip.address>
     ServerName your.rt.server.hostname
     DocumentRoot /opt/rt3/share/html
     AddDefaultCharset UTF-8
 
-    # this line applies to Apache2+mod_perl2 only
+    # these four lines apply to Apache2+mod_perl2 only: {{{
+    PerlSetVar MasonArgsMethod CGI
     PerlModule Apache2 Apache::compat
+    RewriteEngine On
+    RewriteRule ^(.*)/$ $1/index.html
+    # }}}
 
     PerlModule Apache::DBI
     PerlRequire /opt/rt3/bin/webmux.pl
 
-    # this section applies to Apache 1 only
     <Location />
         SetHandler perl-script
         PerlHandler RT::Mason
     </Location>
+</VirtualHost>
 
-    # this section applies to Apache2+mod_perl2 only
-    <FilesMatch "\.html$">
-        SetHandler perl-script
-        PerlHandler RT::Mason
-    </FilesMatch>
-    <LocationMatch "/Attachment/">
-        SetHandler perl-script
-        PerlHandler RT::Mason
-    </LocationMatch>
-    <LocationMatch "/REST/">
-        SetHandler perl-script
-        PerlHandler RT::Mason
-    </LocationMatch>
+FastCGI
+-------
+
+Installation with FastCGI is a little bit more complex and is documented 
+in detail at http://wiki.bestpractical.com/index.cgi?FastCGIConfiguration
+
+In the most basic configuration, you can set up your webserver to run
+as a user who is a member of the "rt" unix group so that the FastCGI script
+can read RT's configuration file.  It's important to understand the security
+implications of this configuration, which are discussed in the document
+mentioned above.
+
+To install RT with FastCGI, you'll need to add a few lines to your 
+Apache configuration file telling it about RT:
+
+<VirtualHost rt.example.com>
+
+   # Pass through requests to display images
+   Alias /NoAuth/images/ /opt/rt3/share/html/NoAuth/images/
+   
+   # Tell FastCGI to put its temporary files somewhere sane.
+   FastCgiIpcDir /tmp
+
+   FastCgiServer /opt/rt3/bin/mason_handler.fcgi -idle-timeout 120
+
+   AddHandler fastcgi-script fcgi
+   ScriptAlias / /opt/rt3/bin/mason_handler.fcgi/
+   
 </VirtualHost>
 
 
@@ -224,6 +269,9 @@ Apache
 SETTING UP THE MAIL GATEWAY 
 ---------------------------
 
+RT can accept incoming email using a simple program run as a "pipe" 
+by your mail server.
+
 An alias for the initial queue will need to be made in either your
 global mail aliases file (if you are using NIS) or locally on your
 machine.
@@ -244,14 +292,15 @@ rt-comment: "|/opt/rt3/bin/rt-mailgate --queue general --action comment --url ht
 BUGS
 ----
 
-To report a bug, send email to rt-3.0-bugs@fsck.com.
+To report a bug, send email to rt-bugs@fsck.com.
 
 GETTING HELP
 ------------
 
 If RT is mission-critical for you or if you use it heavily, we recommend that
 you purchase a commercial support contract.  Details on support contracts
-are available at http://www.bestpractical.com.
+are available at http://www.bestpractical.com or by writing to
+sales@bestpractical.com.
 
 If you're interested in having RT extended or customized or would like more
 information about commercial support options, please send email to 
@@ -264,15 +313,15 @@ RT-USERS MAILINGLIST
 To keep up to date on the latest RT tips, techniques and extensions,
 you probably want to join the rt-users mailing list.  Send a message to:
 
-         rt-users-request@lists.fsck.com 
+         rt-users-request@lists.bestpractical.com 
 
 With the body of the message consisting of only the word:
 
         subscribe
 
 If you're interested in hacking on RT, you'll want to subscribe to
-rt-devel@lists.fsck.com.  Subscribe to it with instructions similar to
-those above.
+rt-devel@lists.bestpractical.com.  Subscribe to it with instructions
+similar to those above.
 
 Address questions about the stable release to the rt-users list, and
 questions about the development version to the rt-devel list.  If you feel
@@ -286,15 +335,6 @@ RT WEBSITE
 For current information about RT, check out the RT website at 
         http://www.bestpractical.com/  
 
+
 You'll find screenshots, a pointer to the current version of RT, contributed 
 patches, and lots of other great stuff.
-
-
-TROUBLESHOOTING
----------------
-
-If the solution to the problem you're running into isn't obvious and you've 
-checked the FAQ, feel free to send mail to rt-users@fsck.com (for released 
-versions of RT) or rt-devel@fsck.com (for development versions).
-
-Thanks!
index 431eccb..93d1f88 100755 (executable)
@@ -27,7 +27,7 @@ use strict;
 use File::Basename;
 require ('/opt/rt3/bin/webmux.pl');
 
-my $h = &RT::Interface::Web::NewCGIHandler();
+my $h = &RT::Interface::Web::NewCGIHandler(@RT::MasonParameters);
 
 # Enter CGI::Fast mode, which should also work as a vanilla CGI script.
 require CGI::Fast;
@@ -44,11 +44,25 @@ while ( my $cgi = CGI::Fast->new ) {
     $ENV{'ENV'}    = '' if defined $ENV{'ENV'};
     $ENV{'IFS'}    = '' if defined $ENV{'IFS'};
 
-    unless ($h->interp->comp_exists($cgi->path_info)) {
-       $cgi->path_info($cgi->path_info . "/index.html");
+    RT::ConnectToDatabase();
+
+    if ( ( !$h->interp->comp_exists( $cgi->path_info ) )
+        && ( $h->interp->comp_exists( $cgi->path_info . "/index.html" ) ) ) {
+        $cgi->path_info( $cgi->path_info . "/index.html" );
+    }
+
+    eval { $h->handle_cgi_object($cgi); };
+    if ($@) {
+        $RT::Logger->crit($@);
+    }
+
+
+    if ($RT::Handle->TransactionDepth) {
+        $RT::Handle->ForceRollback;
+        $RT::Logger->crit("Transaction not committed. Usually indicates a software fault. Data loss may have occurred") ;
     }
-    $h->handle_cgi_object($cgi);
-    # _should_ always be tied
+
+
 }
 
 1;
index 8e1135c..7774189 100755 (executable)
 use strict;
 require ('/opt/rt3/bin/webmux.pl');
 
-my $h = &RT::Interface::Web::NewCGIHandler();
+my $h = &RT::Interface::Web::NewCGIHandler(@RT::MasonParameters);
 
 require CGI;
 
 RT::Init();
 
 my $cgi = CGI->new;
-unless ($h->interp->comp_exists($cgi->path_info)) {
-    $cgi->path_info($cgi->path_info . "/index.html");
+if ( ( !$h->interp->comp_exists( $cgi->path_info ) )
+    && ( $h->interp->comp_exists( $cgi->path_info . "/index.html" ) ) ) {
+    $cgi->path_info( $cgi->path_info . "/index.html" );
 }
+
 $h->handle_cgi_object($cgi);
 
 1;
index b304436..8af8002 100755 (executable)
@@ -1,26 +1,26 @@
 #!/usr/bin/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
 
 =head1 NAME
@@ -31,10 +31,25 @@ rt-mailgate - Mail interface to RT3.
 
 use RT::I18N;
 
+# Make sure that when we call the mailgate wrong, it tempfails
+
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://bad.address"), "Opened the mailgate - The error below is expected - $@");
+print MAIL <<EOF;
+From: root\@localhost
+To: rt\@example.com
+Subject: This is a test of new ticket creation
+
+Foob!
+EOF
+close (MAIL);
+
+# Check the return value
+is ( $? >> 8, 75, "The error message above is expected The mail gateway exited with a failure. yay");
+
 
 # {{{ Test new ticket creation by root who is privileged and superuser
 
-ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost/ --queue general --action correspond"), "Opened the mailgate - $@");
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost".$RT::WebPath."/ --queue general --action correspond"), "Opened the mailgate - $@");
 print MAIL <<EOF;
 From: root\@localhost
 To: rt\@example.com
@@ -45,6 +60,9 @@ Foob!
 EOF
 close (MAIL);
 
+#Check the return value
+is ($? >> 8, 0, "The mail gateway exited normally. yay");
+
 use RT::Tickets;
 my $tickets = RT::Tickets->new($RT::SystemUser);
 $tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
@@ -59,7 +77,7 @@ ok ($tick->Subject eq 'This is a test of new ticket creation', "Created the tick
 
 # {{{This is a test of new ticket creation as an unknown user
 
-ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost/ --queue general --action correspond"), "Opened the mailgate - $@");
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost".$RT::WebPath."/ --queue general --action correspond"), "Opened the mailgate - $@");
 print MAIL <<EOF;
 From: doesnotexist\@example.com
 To: rt\@example.com
@@ -69,6 +87,8 @@ Blah!
 Foob!
 EOF
 close (MAIL);
+#Check the return value
+is ($? >> 8, 0, "The mail gateway exited normally. yay");
 
 $tickets = RT::Tickets->new($RT::SystemUser);
 $tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
@@ -94,7 +114,7 @@ ok ($val, "Granted everybody the right to create tickets - $msg");
 
 sleep(60); # gotta sleep so the remote process' ACL cache times out
 
-ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost/ --queue general --action correspond"), "Opened the mailgate - $@");
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost".$RT::WebPath."/ --queue general --action correspond"), "Opened the mailgate - $@");
 print MAIL <<EOF;
 From: doesnotexist\@example.com
 To: rt\@example.com
@@ -104,6 +124,8 @@ Blah!
 Foob!
 EOF
 close (MAIL);
+#Check the return value
+is ($? >> 8, 0, "The mail gateway exited normally. yay");
 
 
 $tickets = RT::Tickets->new($RT::SystemUser);
@@ -126,7 +148,7 @@ ok( $u->Id != 0, " user does not exist and was created by ticket submission");
 #ok ($val, "Granted everybody the right to create tickets - $msg");
 #sleep(60); # gotta sleep so the remote process' ACL cache times out
 
-ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost/ --queue general --action correspond"), "Opened the mailgate - $@");
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost".$RT::WebPath."/ --queue general --action correspond"), "Opened the mailgate - $@");
 print MAIL <<EOF;
 From: doesnotexist-2\@example.com
 To: rt\@example.com
@@ -136,6 +158,8 @@ Blah!
 Foob!
 EOF
 close (MAIL);
+#Check the return value
+is ($? >> 8, 0, "The mail gateway exited normally. yay");
 
 $u = RT::User->new($RT::SystemUser);
 $u->Load('doesnotexist-2@example.com');
@@ -148,7 +172,7 @@ ok( $u->Id == 0, " user does not exist and was not created by ticket corresponde
 ok ($val, "Granted everybody the right to reply to  tickets - $msg");
 sleep(60); # gotta sleep so the remote process' ACL cache times out
 
-ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost/ --queue general --action correspond"), "Opened the mailgate - $@");
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost".$RT::WebPath."/ --queue general --action correspond"), "Opened the mailgate - $@");
 print MAIL <<EOF;
 From: doesnotexist-2\@example.com
 To: rt\@example.com
@@ -158,6 +182,8 @@ Blah!
 Foob!
 EOF
 close (MAIL);
+#Check the return value
+is ($? >> 8, 0, "The mail gateway exited normally. yay");
 
 
 $u = RT::User->new($RT::SystemUser);
@@ -173,7 +199,7 @@ ok( $u->Id != 0, " user exists and was created by ticket correspondence submissi
 #ok ($val, "Granted everybody the right to create tickets - $msg");
 #sleep(60); # gotta sleep so the remote process' ACL cache times out
 
-ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost/ --queue general --action comment"), "Opened the mailgate - $@");
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost".$RT::WebPath."/ --queue general --action comment"), "Opened the mailgate - $@");
 print MAIL <<EOF;
 From: doesnotexist-3\@example.com
 To: rt\@example.com
@@ -184,6 +210,9 @@ Foob!
 EOF
 close (MAIL);
 
+#Check the return value
+is ($? >> 8, 0, "The mail gateway exited normally. yay");
+
 $u = RT::User->new($RT::SystemUser);
 $u->Load('doesnotexist-3@example.com');
 ok( $u->Id == 0, " user does not exist and was not created by ticket comment submission");
@@ -196,7 +225,7 @@ ok( $u->Id == 0, " user does not exist and was not created by ticket comment sub
 ok ($val, "Granted everybody the right to reply to  tickets - $msg");
 sleep(60); # gotta sleep so the remote process' ACL cache times out
 
-ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost/ --queue general --action comment"), "Opened the mailgate - $@");
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost".$RT::WebPath."/ --queue general --action comment"), "Opened the mailgate - $@");
 print MAIL <<EOF;
 From: doesnotexist-3\@example.com
 To: rt\@example.com
@@ -207,6 +236,8 @@ Foob!
 EOF
 close (MAIL);
 
+#Check the return value
+is ($? >> 8, 0, "The mail gateway exited normally. yay");
 
 $u = RT::User->new($RT::SystemUser);
 $u->Load('doesnotexist-3@example.com');
@@ -227,17 +258,20 @@ my $entity = MIME::Entity->build( From => 'root@localhost',
                                 Data => ['This is a test of a binary attachment']);
 
 # currently in lib/t/autogen
-$entity->attach(Path => '../../../html/NoAuth/images/spacer.gif', 
+$entity->attach(Path => '/opt/rt3/share/html/NoAuth/images/spacer.gif', 
                 Type => 'image/gif',
                 Encoding => 'base64');
 
 # Create a ticket with a binary attachment
-ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost/ --queue general --action correspond"), "Opened the mailgate - $@");
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost".$RT::WebPath."/ --queue general --action correspond"), "Opened the mailgate - $@");
 
 $entity->print(\*MAIL);
 
 close (MAIL);
 
+#Check the return value
+is ($? >> 8, 0, "The mail gateway exited normally. yay");
+
 my $tickets = RT::Tickets->new($RT::SystemUser);
 $tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
 $tickets->Limit(FIELD => 'id', OPERATOR => '>', VALUE => '0');
@@ -273,7 +307,7 @@ use LWP::UserAgent;
 # Grab the binary attachment via the web ui
 my $ua      = LWP::UserAgent->new();
 
-my $full_url = "http://localhost/Ticket/Attachment/".$attachment->TransactionId."/".$attachment->id."/spacer.gif?&user=root&pass=password";
+my $full_url = "http://localhost".$RT::WebPath."/Ticket/Attachment/".$attachment->TransactionId."/".$attachment->id."/spacer.gif?&user=root&pass=password";
 my $r = $ua->get( $full_url);
 
 
@@ -286,7 +320,7 @@ is($file, $r->content, 'The attachment isn\'t screwed up in download');
 
 # {{{ Simple I18N testing
 
-ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost/ --queue general --action correspond"), "Opened the mailgate - $@");
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost".$RT::WebPath."/ --queue general --action correspond"), "Opened the mailgate - $@");
                                                                          
 print MAIL <<EOF;
 From: root\@localhost
@@ -301,6 +335,9 @@ bye
 EOF
 close (MAIL);
 
+#Check the return value
+is ($? >> 8, 0, "The mail gateway exited normally. yay");
+
 my $unitickets = RT::Tickets->new($RT::SystemUser);
 $unitickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
 $unitickets->Limit(FIELD => 'id', OPERATOR => '>', VALUE => '0');
@@ -317,7 +354,7 @@ is ($unitick->Transactions->First->Content, $unitick->Transactions->First->Attac
 ok($unitick->Transactions->First->Attachments->First->Content =~ /$unistring/i, $unitick->Id." appears to be unicode ". $unitick->Transactions->First->Attachments->First->Id);
 # supposedly I18N fails on the second message sent in.
 
-ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost/ --queue general --action correspond"), "Opened the mailgate - $@");
+ok(open(MAIL, "|/opt/rt3/bin/rt-mailgate --url http://localhost".$RT::WebPath."/ --queue general --action correspond"), "Opened the mailgate - $@");
                                                                          
 print MAIL <<EOF;
 From: root\@localhost
@@ -332,6 +369,9 @@ bye
 EOF
 close (MAIL);
 
+#Check the return value
+is ($? >> 8, 0, "The mail gateway exited normally. yay");
+
 my $tickets2 = RT::Tickets->new($RT::SystemUser);
 $tickets2->OrderBy(FIELD => 'id', ORDER => 'DESC');
 $tickets2->Limit(FIELD => 'id', OPERATOR => '>', VALUE => '0');
@@ -367,7 +407,7 @@ use LWP::UserAgent;
 use constant EX_TEMPFAIL => 75;
 
 my %opts;
-GetOptions( \%opts, "queue=s", "action=s", "url=s", "jar=s", "help", "debug", "extension=s" );
+GetOptions( \%opts, "queue=s", "action=s", "url=s", "jar=s", "help", "debug", "extension=s", "timeout=i" );
 
 if ( $opts{help} ) {
     require Pod::Usage;
@@ -381,17 +421,18 @@ for (qw(url)) {
 }
 
 undef $/;
-my $message = <>;
 my $ua      = LWP::UserAgent->new();
 $ua->cookie_jar( { file => $opts{jar} } );
 
 my %args = (
     queue   => $opts{queue},
     action  => $opts{action},
-    message => $message,
     SessionType => 'REST',    # Surpress login box
 );
 
+# Read the message in from STDIN
+$args{'message'} = <>;
+
 
 if ($opts{'extension'}) {
         $args{$opts{'extension'}} = $ENV{'EXTENSION'};
@@ -404,6 +445,7 @@ warn "Connecting to $full_url" if $opts{'debug'};
 
 
 
+$ua->timeout(exists($opts{'timeout'}) ? $opts{'timeout'} : 180);
 my $r = $ua->post( $full_url, {%args} );
 check_failure($r);
 
@@ -414,7 +456,7 @@ if ( $content !~ /^(ok|not ok)/ ) {
 
     # It's not the server's fault if the mail is bogus. We just want to know that
     # *something* came out of the server.
-    die <<EOF
+    warn <<EOF;
 RT server error.
 
 The RT server which handled your email did not behave as expected. It
@@ -423,8 +465,13 @@ said:
 $content
 EOF
 
+exit EX_TEMPFAIL;
+
 }
 
+exit;
+
+
 sub check_failure {
     my $r = shift;
     return if $r->is_success();
@@ -455,7 +502,11 @@ Usual invocation (from MTA):
 
     rt-mailgate --action (correspond|comment) --queue queuename
                 --url http://your.rt.server/
-                [ --extension (queue|action|ticket)
+                [ --debug ]
+                [ --extension (queue|action|ticket) ]
+                [ --timeout seconds ]
+
+
 
 See C<man rt-mailgate> for more.
 
@@ -486,6 +537,16 @@ submitted to will be set to the value of $EXTENSION. By specifying
 is related to.  "action" will allow the user to specify either "comment" or
 "correspond" in the address extension.
 
+=item C<--debug> OPTIONAL
+
+Print debugging output to standard error
+
+
+=item C<--timeout> OPTIONAL
+
+Configure the timeout for posting the message to the web server.  The
+default timeout is 3 minutes (180 seconds).
+
 
 =head1 DESCRIPTION
 
diff --git a/rt/bin/webmux.pl b/rt/bin/webmux.pl
deleted file mode 100755 (executable)
index 21cb83f..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-#!/usr/bin/perl
-# 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
-
-use strict;
-
-BEGIN {
-    $ENV{'PATH'}   = '/bin:/usr/bin';                      # or whatever you need
-    $ENV{'CDPATH'} = '' if defined $ENV{'CDPATH'};
-    $ENV{'SHELL'}  = '/bin/sh' if defined $ENV{'SHELL'};
-    $ENV{'ENV'}    = '' if defined $ENV{'ENV'};
-    $ENV{'IFS'}    = '' if defined $ENV{'IFS'};
-}
-
-use lib ("/opt/rt3/local/lib", "/opt/rt3/lib");
-use RT;
-
-package RT::Mason;
-
-use CGI qw(-private_tempfiles);    #bring this in before mason, to make sure we
-                                   #set private_tempfiles
-
-BEGIN {
-    if ($CGI::MOD_PERL) {
-       require HTML::Mason::ApacheHandler;
-    }
-    else {
-       require HTML::Mason::CGIHandler;
-    }
-}
-
-use HTML::Mason;                   # brings in subpackages: Parser, Interp, etc.
-
-use vars qw($Nobody $SystemUser $r);
-
-#This drags in RT's config.pm
-RT::LoadConfig();
-
-use Carp;
-
-{
-    package HTML::Mason::Commands;
-    use vars qw(%session);
-
-    use RT::Tickets;
-    use RT::Transactions;
-    use RT::Users;
-    use RT::CurrentUser;
-    use RT::Templates;
-    use RT::Queues;
-    use RT::ScripActions;
-    use RT::ScripConditions;
-    use RT::Scrips;
-    use RT::Groups;
-    use RT::GroupMembers;
-    use RT::CustomFields;
-    use RT::CustomFieldValues;
-    use RT::TicketCustomFieldValues;
-
-    use RT::Interface::Web;
-    use MIME::Entity;
-    use Text::Wrapper;
-    use CGI::Cookie;
-    use Time::ParseDate;
-    use HTML::Entities;
-}
-
-
-# Activate the following if running httpd as root (the normal case).
-# Resets ownership of all files created by Mason at startup.
-# Note that mysql uses DB for sessions, so there's no need to do this.
-unless ($RT::DatabaseType =~ /(mysql|Pg)/) {
-    # Clean up our umask to protect session files
-    umask(0077);
-
-if ( $CGI::MOD_PERL)  {
-    chown( Apache->server->uid, Apache->server->gid, [$RT::MasonSessionDir] )
-       if Apache->server->can('uid');
-        }
-    # Die if WebSessionDir doesn't exist or we can't write to it
-    stat($RT::MasonSessionDir);
-    die "Can't read and write $RT::MasonSessionDir"
-       unless ( ( -d _ ) and ( -r _ ) and ( -w _ ) );
-}
-
-my $ah = &RT::Interface::Web::NewApacheHandler() if $CGI::MOD_PERL;
-
-sub handler {
-    ($r) = @_;
-
-    RT::Init();
-
-    # We don't need to handle non-text items
-    return -1 if defined( $r->content_type ) && $r->content_type !~ m|^text/|io;
-
-    my %session;
-    my $status = $ah->handle_request($r);
-    undef (%session);
-
-    $RT::Logger->crit("Transaction not committed. Usually indicates a software fault. Data loss may have occurred") if $RT::Handle->TransactionDepth;
-    return $status;
-}
-
-1;
diff --git a/rt/config.pld b/rt/config.pld
new file mode 100644 (file)
index 0000000..c71c7bb
--- /dev/null
@@ -0,0 +1,19 @@
+(test "x$prefix" = "xNONE" || test "x$prefix" = "x") && prefix=/opt/rt3
+(test "x$exec_prefix" = "xNONE" || test "x$exec_prefix" = "x") && exec_prefix=${prefix}
+bindir=${exec_prefix}/bin
+sbindir=${exec_prefix}/sbin
+sysconfdir=${prefix}/etc
+mandir=${prefix}/man
+libdir=${prefix}/lib
+datadir=${prefix}/share
+(test "x$htmldir" = "xNONE" || test "x$htmldir" = "x") && htmldir=${datadir}/html
+(test "x$manualdir" = "xNONE" || test "x$manualdir" = "x") && manualdir=${datadir}/doc
+localstatedir=${prefix}/var
+(test "x$logfiledir" = "xNONE" || test "x$logfiledir" = "x") && logfiledir=${localstatedir}/log
+(test "x$masonstatedir" = "xNONE" || test "x$masonstatedir" = "x") && masonstatedir=${localstatedir}/mason_data
+(test "x$sessionstatedir" = "xNONE" || test "x$sessionstatedir" = "x") && sessionstatedir=${localstatedir}/session_data
+(test "x$customdir" = "xNONE" || test "x$customdir" = "x") && customdir=${prefix}/local
+(test "x$custometcdir" = "xNONE" || test "x$custometcdir" = "x") && custometcdir=${customdir}/etc
+(test "x$customhtmldir" = "xNONE" || test "x$customhtmldir" = "x") && customhtmldir=${customdir}/html
+(test "x$customlexdir" = "xNONE" || test "x$customlexdir" = "x") && customlexdir=${customdir}/po
+(test "x$customlibdir" = "xNONE" || test "x$customlibdir" = "x") && customlibdir=${customdir}/lib
index c8667c0..ac29215 100644 (file)
@@ -1,10 +1,10 @@
 sub acl {
 return (
-"CREATE USER ${RT::DatabaseUser} identified by ${RT::DatabasePassword}".
-"temporary tablespace TEMP" .
-"default tablespace USERS" .
-"quota unlimited on USERS;" ,
-"grant connect, resource to ${RT::DatabaseUser};",
-"exit;");
+"CREATE USER ${RT::DatabaseUser} identified by ${RT::DatabasePassword} ".
+"default tablespace USERS " .
+"temporary tablespace TEMP " .
+"quota unlimited on USERS" ,
+"grant connect, resource to ${RT::DatabaseUser}"
+);
 }
 1;
index 16ea71b..49f938e 100755 (executable)
@@ -7,6 +7,8 @@ sub acl {
 
       attachments_id_seq
       Attachments
+      Attributes
+      attributes_id_seq
       queues_id_seq
       Queues
       links_id_seq
index 0ecaa3b..5bd8834 100755 (executable)
@@ -3,6 +3,6 @@ return  (
 "USE mysql;",
 "DELETE FROM user WHERE user = '${RT::DatabaseUser}';",
 "DELETE FROM db where db = '${RT::DatabaseName}';",
-"GRANT SELECT,INSERT,CREATE,INDEX,UPDATE,DELETE ON ${RT::DatabaseName}.* TO ${RT::DatabaseUser}\@${RT::DatabaseRTHost} IDENTIFIED BY '${RT::DatabasePassword}';");
+"GRANT SELECT,INSERT,CREATE,INDEX,UPDATE,DELETE ON ${RT::DatabaseName}.* TO ${RT::DatabaseUser}\@'${RT::DatabaseRTHost}' IDENTIFIED BY '${RT::DatabasePassword}';");
 }
 1;
index ba0d6fc..a5b68b3 100755 (executable)
@@ -3,9 +3,6 @@
 --
 ------------------------------------------------------------------
 
-BEGIN;
-
-
 
 
 --
@@ -93,6 +90,7 @@ CREATE TABLE Links (
 
 );
 CREATE UNIQUE INDEX Links1 ON Links (Base, Target, Type) ;
+CREATE INDEX Links4 ON Links(Type,LocalBase);
 
 -- }}}
 
@@ -136,7 +134,7 @@ CREATE TABLE Groups (
   Description varchar(255) NULL  ,
   Domain varchar(64),
   Type varchar(64),
-  Instance varchar(64),
+  Instance integer,
   PRIMARY KEY (id)
 
 );
@@ -192,7 +190,7 @@ CREATE TABLE Transactions (
   Field varchar(40) NULL  ,
   OldValue varchar(255) NULL  ,
   NewValue varchar(255) NULL  ,
-  Data varchar(100) NULL  ,
+  Data varchar(255) NULL  ,
 
   Creator integer NOT NULL DEFAULT 0  ,
   Created TIMESTAMP NULL  ,
@@ -500,6 +498,9 @@ CREATE TABLE TicketCustomFieldValues (
 
 );
 
+CREATE INDEX TicketCustomFieldValues1 ON TicketCustomFieldValues (CustomField,Ticket,Content); 
+CREATE INDEX TicketCustomFieldValues2 ON TicketCustomFieldValues (CustomField,Ticket); 
+
 -- }}}
 
 -- {{{ CustomFields
@@ -556,6 +557,34 @@ CREATE TABLE CustomFieldValues (
 
 );
 
+CREATE INDEX CustomFieldValues1 ON CustomFieldValues (CustomField);
+
+-- }}}
+
+
+-- {{{ Attributes
+
+CREATE SEQUENCE attributes_id_seq;
+
+CREATE TABLE Attributes (
+  id INTEGER DEFAULT nextval('attributes_id_seq'),
+  Name varchar(255) NOT NULL  ,
+  Description varchar(255) NULL  ,
+  Content text,
+  ContentType varchar(16),
+  ObjectType varchar(64),
+  ObjectId integer, # foreign key to anything
+  Creator integer NOT NULL DEFAULT 0  ,
+  Created TIMESTAMP NULL  ,
+  LastUpdatedBy integer NOT NULL DEFAULT 0  ,
+  LastUpdated TIMESTAMP NULL  ,
+  PRIMARY KEY (id)
+
+);
+
+CREATE INDEX Attributes1 on Attributes(Name);
+CREATE INDEX Attributes2 on Attributes(ObjectType, ObjectId);
+
 -- }}}
 
 -- {{{ Sessions
@@ -573,6 +602,3 @@ CREATE TABLE sessions (
 
 -- }}}
 
-
-
-COMMIT;
index 46f8ec5..0ab42e7 100755 (executable)
@@ -16,7 +16,6 @@ CREATE TABLE Attachments (
   PRIMARY KEY (id)
 ) TYPE=InnoDB;
 
-CREATE INDEX Attachments1 ON Attachments (Parent) ;
 CREATE INDEX Attachments2 ON Attachments (TransactionId) ;
 CREATE INDEX Attachments3 ON Attachments (Parent, TransactionId) ;
 # }}}
@@ -62,6 +61,7 @@ CREATE TABLE Links (
 CREATE UNIQUE INDEX Links1 ON Links (Base, Target, Type) ;
 CREATE INDEX Links2 ON Links (Base,  Type) ;
 CREATE INDEX Links3 ON Links (Target,  Type) ;
+CREATE INDEX Links4 ON Links (Type,LocalBase);
 
 # }}}
 
@@ -87,12 +87,12 @@ CREATE TABLE Groups (
   Description varchar(255) NULL  ,
   Domain varchar(64),
   Type varchar(64),
-  Instance varchar(64),
+  Instance integer,
   PRIMARY KEY (id)
 ) TYPE=InnoDB;
 
 CREATE INDEX Groups1 ON Groups (Domain,Instance,Type,id);
-CREATE INDEX Groups2 On Groups  (Type, Instance, Domain);   
+CREATE INDEX Groups2 On Groups (Type, Instance);   
 
 # }}}
 
@@ -125,7 +125,7 @@ CREATE TABLE Transactions (
   Field varchar(40) NULL  ,
   OldValue varchar(255) NULL  ,
   NewValue varchar(255) NULL  ,
-  Data varchar(100) NULL  ,
+  Data varchar(255) NULL  ,
 
   Creator integer NOT NULL DEFAULT 0  ,
   Created DATETIME NULL  ,
@@ -210,7 +210,6 @@ create table CachedGroupMembers (
 ) TYPE=InnoDB;
 
 CREATE INDEX DisGrouMem  on CachedGroupMembers (GroupId,MemberId,Disabled);
-CREATE INDEX GrouMem  on CachedGroupMembers (GroupId,MemberId);
 
 # }}}
 
@@ -257,8 +256,6 @@ CREATE TABLE Users (
 
 
 CREATE UNIQUE INDEX Users1 ON Users (Name) ;
-CREATE INDEX Users2 ON Users (Name);
-CREATE INDEX Users3 ON Users (id, EmailAddress);
 CREATE INDEX Users4 ON Users (EmailAddress);
 
 
@@ -299,9 +296,6 @@ CREATE TABLE Tickets (
 
 CREATE INDEX Tickets1 ON Tickets (Queue, Status) ;
 CREATE INDEX Tickets2 ON Tickets (Owner) ;
-CREATE INDEX Tickets3 ON Tickets (EffectiveId) ;
-CREATE INDEX Tickets4 ON Tickets (id, Status) ;
-CREATE INDEX Tickets5 ON Tickets (id, EffectiveId) ;
 CREATE INDEX Tickets6 ON Tickets (EffectiveId, Type) ;
 
 # }}}
@@ -358,6 +352,8 @@ CREATE TABLE TicketCustomFieldValues (
   PRIMARY KEY (id)
 ) TYPE=InnoDB;
 
+CREATE INDEX TicketCustomFieldValues1 ON TicketCustomFieldValues (CustomField,Ticket,Content); 
+
 # }}}
 
 # {{{ CustomFields
@@ -399,6 +395,31 @@ CREATE TABLE CustomFieldValues (
   PRIMARY KEY (id)
 ) TYPE=InnoDB;
 
+CREATE INDEX CustomFieldValues1 ON CustomFieldValues (CustomField);
+# }}}
+
+
+# {{{ Attributes
+
+CREATE TABLE Attributes (
+  id INTEGER NOT NULL  AUTO_INCREMENT,
+  Name varchar(255) NULL  ,
+  Description varchar(255) NULL  ,
+  Content text,
+  ContentType varchar(16),
+  ObjectType varchar(64),
+  ObjectId integer, # foreign key to anything
+  Creator integer NOT NULL DEFAULT 0  ,
+  Created DATETIME NULL  ,
+  LastUpdatedBy integer NOT NULL DEFAULT 0  ,
+  LastUpdated DATETIME NULL  ,
+  PRIMARY KEY (id)
+) TYPE=InnoDB;
+
+CREATE INDEX Attributes1 on Attributes(Name);
+CREATE INDEX Attributes2 on Attributes(ObjectType, ObjectId);
+
 # }}}
 
 # {{{ Sessions
index 90c332b..7e941a2 100644 (file)
@@ -47,7 +47,7 @@ use vars qw($VERSION $System $SystemUser $Nobody $Handle $Logger
         $MasonSessionDir
 );
 
-$VERSION = '3.0.4';
+$VERSION = '3.0.9';
 $CORE_CONFIG_FILE = "/opt/rt3/etc/RT_Config.pm";
 $SITE_CONFIG_FILE = "/opt/rt3/etc/RT_SiteConfig.pm";
 
@@ -117,13 +117,10 @@ sub LoadConfig {
 =cut
 
 sub Init {
-    require RT::Handle;
+
     #Get a database connection
-        unless ($Handle && $Handle->dbh->ping) {
-    $Handle = RT::Handle->new();
-        } 
-    $Handle->Connect();
-    
+    ConnectToDatabase();
+
     #RT's system user is a genuine database user. its id lives here
     $SystemUser = new RT::CurrentUser();
     $SystemUser->LoadByName('RT_System');
@@ -137,6 +134,21 @@ sub Init {
    InitLogging(); 
 }
 
+  
+=head2 ConnectToDatabase
+
+Get a database connection
+
+=cut
+sub ConnectToDatabase {
+    require RT::Handle;
+    unless ($Handle && $Handle->dbh && $Handle->dbh->ping) {
+        $Handle = RT::Handle->new();
+    } 
+    $Handle->Connect();
+}
+    
 =head2 InitLogging
 
 Create the RT::Logger object. 
@@ -282,8 +294,15 @@ sub DropSetGIDPermissions {
 
 =head1 BUGS
 
+Please report them to rt-3.0-bugs@fsck.com, if you know what's broken and have at least some idea of what needs to be fixed.
+If you're not sure what's going on, report them rt-devel@lists.fsck.com.
+
 =head1 SEE ALSO
 
+L<RT::StyleGuide>
+L<DBIx::SearchBuilder>
+
+
 
 =begin testing
 
index 1501a12..cbcd99f 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -61,7 +83,7 @@ sub _Init {
 
 
 
-=item Create PARAMHASH
+=head2 Create PARAMHASH
 
 Create takes a hash of values and creates a row in the database:
 
@@ -104,7 +126,7 @@ sub Create {
 
 
 
-=item id
+=head2 id
 
 Returns the current value of id. 
 (In the database, id is stored as int(11).)
@@ -113,14 +135,14 @@ Returns the current value of id.
 =cut
 
 
-=item PrincipalType
+=head2 PrincipalType
 
 Returns the current value of PrincipalType. 
 (In the database, PrincipalType is stored as varchar(25).)
 
 
 
-=item SetPrincipalType VALUE
+=head2 SetPrincipalType VALUE
 
 
 Set PrincipalType to VALUE. 
@@ -131,14 +153,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item PrincipalId
+=head2 PrincipalId
 
 Returns the current value of PrincipalId. 
 (In the database, PrincipalId is stored as int(11).)
 
 
 
-=item SetPrincipalId VALUE
+=head2 SetPrincipalId VALUE
 
 
 Set PrincipalId to VALUE. 
@@ -149,14 +171,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item RightName
+=head2 RightName
 
 Returns the current value of RightName. 
 (In the database, RightName is stored as varchar(25).)
 
 
 
-=item SetRightName VALUE
+=head2 SetRightName VALUE
 
 
 Set RightName to VALUE. 
@@ -167,14 +189,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item ObjectType
+=head2 ObjectType
 
 Returns the current value of ObjectType. 
 (In the database, ObjectType is stored as varchar(25).)
 
 
 
-=item SetObjectType VALUE
+=head2 SetObjectType VALUE
 
 
 Set ObjectType to VALUE. 
@@ -185,14 +207,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item ObjectId
+=head2 ObjectId
 
 Returns the current value of ObjectId. 
 (In the database, ObjectId is stored as int(11).)
 
 
 
-=item SetObjectId VALUE
+=head2 SetObjectId VALUE
 
 
 Set ObjectId to VALUE. 
@@ -203,14 +225,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item DelegatedBy
+=head2 DelegatedBy
 
 Returns the current value of DelegatedBy. 
 (In the database, DelegatedBy is stored as int(11).)
 
 
 
-=item SetDelegatedBy VALUE
+=head2 SetDelegatedBy VALUE
 
 
 Set DelegatedBy to VALUE. 
@@ -221,14 +243,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item DelegatedFrom
+=head2 DelegatedFrom
 
 Returns the current value of DelegatedFrom. 
 (In the database, DelegatedFrom is stored as int(11).)
 
 
 
-=item SetDelegatedFrom VALUE
+=head2 SetDelegatedFrom VALUE
 
 
 Set DelegatedFrom to VALUE. 
@@ -240,7 +262,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 
 
 
-sub _ClassAccessible {
+sub _CoreAccessible {
     {
      
         id =>
index 81f59c6..8fd548e 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -64,7 +86,7 @@ sub _Init {
 }
 
 
-=item NewItem
+=head2 NewItem
 
 Returns an empty new RT::ACE item
 
index 81f7bdd..6d2894f 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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:
 # 
-# END LICENSE BLOCK
+# (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.)
+# 
+# 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
 package RT::Action::Autoreply;
 require RT::Action::SendEmail;
 
@@ -28,6 +50,18 @@ use strict;
 use vars qw/@ISA/;
 @ISA = qw(RT::Action::SendEmail);
 
+=head2 Prepare
+
+Set up the relevant recipients, then call our parent.
+
+=cut
+
+
+sub Prepare {
+    my $self = shift;
+    $self->SetRecipients();
+    $self->SUPER::Prepare();
+}
 
 # {{{ sub SetRecipients
 
@@ -74,10 +108,18 @@ sub SetReturnAddress {
     }
     
     unless ($self->TemplateObj->MIMEObj->head->get('From')) {
-       my $friendly_name = $self->TicketObj->QueueObj->Description ||
-               $self->TicketObj->QueueObj->Name;
-       $friendly_name =~ s/"/\\"/g;
-       $self->SetHeader('From', "\"$friendly_name\" <$replyto>");
+       if ($RT::UseFriendlyFromLine) {
+           my $friendly_name = $self->TicketObj->QueueObj->Description ||
+                   $self->TicketObj->QueueObj->Name;
+           $friendly_name =~ s/"/\\"/g;
+           $self->SetHeader( 'From',
+                       sprintf($RT::FriendlyFromLineFormat, 
+                $self->MIMEEncodeString( $friendly_name, $RT::EmailOutputEncoding ), $replyto),
+           );
+       }
+       else {
+           $self->SetHeader( 'From', $replyto );
+       }
     }
     
     unless ($self->TemplateObj->MIMEObj->head->get('Reply-To')) {
index 007d299..5e80f40 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
-# END LICENSE BLOCK
+# 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
 =head1 NAME
 
   RT::Action::Generic - a generic baseclass for RT Actions
@@ -44,6 +66,9 @@ ok (require RT::Action::Generic);
 package RT::Action::Generic;
 
 use strict;
+use Scalar::Util;
+
+use base qw/RT::Base/;
 
 # {{{ sub new 
 sub new  {
@@ -56,13 +81,6 @@ sub new  {
 }
 # }}}
 
-# {{{ sub new 
-sub loc {
-    my $self = shift;
-    return $self->{'ScripObj'}->loc(@_);
-}
-# }}}
-
 # {{{ sub _Init 
 sub _Init  {
   my $self = shift;
@@ -72,6 +90,7 @@ sub _Init  {
               TemplateObj => undef,
               Argument => undef,
               Type => undef,
+            CurrentUser => undef,
               @_ );
   
   
@@ -81,6 +100,16 @@ sub _Init  {
   $self->{'TransactionObj'} = $args{'TransactionObj'};
   $self->{'TemplateObj'} = $args{'TemplateObj'};
   $self->{'Type'} = $args{'Type'};
+  $self->CurrentUser( $args{'CurrentUser'});
+    Scalar::Util::weaken($self->{'ScripObj'});
+    Scalar::Util::weaken($self->{'TicketObj'});
+    Scalar::Util::weaken($self->{'TemplateObj'});
+    Scalar::Util::weaken($self->{'TransactionObj'});
+
+
+
+
+
 }
 # }}}
 
index 1e4e4c0..4131a8c 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
+#
 package RT::Action::Notify;
 require RT::Action::SendEmail;
-
+use Mail::Address;
 use strict;
 use vars qw/@ISA/;
 @ISA = qw(RT::Action::SendEmail);
 
+
+=head2 Prepare
+
+Set up the relevant recipients, then call our parent.
+
+=cut
+
+
+sub Prepare {
+    my $self = shift;
+    $self->SetRecipients();
+    $self->SUPER::Prepare();
+}
+
 # {{{ sub SetRecipients
 
 =head2 SetRecipients
@@ -47,10 +84,18 @@ sub SetRecipients {
     my ( @To, @PseudoTo, @Cc, @Bcc );
 
 
-    if ($arg =~ /\bOtherRecipients\b/) {
-        if ($self->TransactionObj->Attachments->First) {
-            push (@Cc, $self->TransactionObj->Attachments->First->GetHeader('RT-Send-Cc'));
-            push (@Bcc, $self->TransactionObj->Attachments->First->GetHeader('RT-Send-Bcc'));
+    if ( $arg =~ /\bOtherRecipients\b/ ) {
+        if ( $self->TransactionObj->Attachments->First ) {
+            my @cc_addresses = Mail::Address->parse($self->TransactionObj->Attachments->First->GetHeader('RT-Send-Cc'));
+            foreach my $addr (@cc_addresses) {
+                  push @Cc, $addr->address;
+            }
+            my @bcc_addresses = Mail::Address->parse($self->TransactionObj->Attachments->First->GetHeader('RT-Send-Bcc'));
+
+            foreach my $addr (@bcc_addresses) {
+                  push @Bcc, $addr->address;
+            }
+
         }
     }
 
@@ -118,7 +163,7 @@ sub SetRecipients {
         @{ $self->{'Bcc'} } = grep ( !/^$creator$/, @Bcc );
     }
     @{ $self->{'PseudoTo'} } = @PseudoTo;
-    return (1);
+
 
 }
 
index 210e4ab..475e355 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 package RT::Action::NotifyAsComment;
 require RT::Action::Notify;
 
index 02ff3a5..4d751eb 100644 (file)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # This Action will resolve all members of a resolved group ticket
 
 package RT::Action::ResolveMembers;
index dac8fc8..a85c169 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
-# END LICENSE BLOCK
+# 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
 # Portions Copyright 2000 Tobias Brox <tobix@cpan.org>
 
 package RT::Action::SendEmail;
@@ -33,6 +55,7 @@ use vars qw/@ISA/;
 use MIME::Words qw(encode_mimeword);
 
 use RT::EmailParser;
+use Mail::Address;
 
 =head1 NAME
 
@@ -51,13 +74,6 @@ RT::Action::AutoReply is a good example subclass.
 Basically, you create another module RT::Action::YourAction which ISA
 RT::Action::SendEmail.
 
-If you want to set the recipients of the mail to something other than
-the addresses mentioned in the To, Cc, Bcc and headers in
-the template, you should subclass RT::Action::SendEmail and override
-either the SetRecipients method or the SetTo, SetCc, etc methods (see
-the comments for the SetRecipients sub).
-
-
 =begin testing
 
 ok (require RT::Action::SendEmail);
@@ -77,228 +93,201 @@ perl(1).
 
 # {{{ Scrip methods (_Init, Commit, Prepare, IsApplicable)
 
-# {{{ sub _Init
-# We use _Init from RT::Action
-# }}}
 
 # {{{ sub Commit
-#Do what we need to do and send it out.
+
 sub Commit {
     my $self = shift;
 
-    my $MIMEObj = $self->TemplateObj->MIMEObj;
-    my $msgid = $MIMEObj->head->get('Message-Id');
-    chomp $msgid;
-    $RT::Logger->info($msgid." #".$self->TicketObj->id."/".$self->TransactionObj->id." - Scrip ". $self->ScripObj->id ." ".$self->ScripObj->Description);
-    #send the email
+    return($self->SendMessage($self->TemplateObj->MIMEObj));
+}
 
-        # Weed out any RT addresses. We really don't want to talk to ourselves!
-        @{$self->{'To'}} = RT::EmailParser::CullRTAddresses("", @{$self->{'To'}});
-        @{$self->{'Cc'}} = RT::EmailParser::CullRTAddresses("", @{$self->{'Cc'}});
-        @{$self->{'Bcc'}} = RT::EmailParser::CullRTAddresses("", @{$self->{'Bcc'}});
-    # If there are no recipients, don't try to send the message.
-    # If the transaction has content and has the header RT-Squelch-Replies-To
+# }}}
 
-    if ( defined $self->TransactionObj->Attachments->First() ) {
+# {{{ sub Prepare
 
-        my $squelch = $self->TransactionObj->Attachments->First->GetHeader( 'RT-Squelch-Replies-To');
+sub Prepare {
+    my $self = shift;
 
-        if ($squelch) {
-            my @blacklist = split ( /,/, $squelch );
-
-            # Cycle through the people we're sending to and pull out anyone on the
-            # system blacklist
-
-            foreach my $person_to_yank (@blacklist) {
-                $person_to_yank =~ s/\s//g;
-                @{ $self->{'To'} } =
-                  grep ( !/^$person_to_yank$/, @{ $self->{'To'} } );
-                @{ $self->{'Cc'} } =
-                  grep ( !/^$person_to_yank$/, @{ $self->{'Cc'} } );
-                @{ $self->{'Bcc'} } =
-                  grep ( !/^$person_to_yank$/, @{ $self->{'Bcc'} } );
-            }
-        }
+    my ( $result, $message ) = $self->TemplateObj->Parse(
+        Argument       => $self->Argument,
+        TicketObj      => $self->TicketObj,
+        TransactionObj => $self->TransactionObj
+    );
+    if ( !$result ) {
+        return (undef);
     }
 
+    my $MIMEObj = $self->TemplateObj->MIMEObj;
+
+    # Header
+    $self->SetRTSpecialHeaders();
+
+    $self->RemoveInappropriateRecipients();
+
     # Go add all the Tos, Ccs and Bccs that we need to to the message to
     # make it happy, but only if we actually have values in those arrays.
 
-    $self->SetHeader( 'To', join ( ',', @{ $self->{'To'} } ) )
-      if ( $self->{'To'} && @{ $self->{'To'} } );
-    $self->SetHeader( 'Cc', join ( ',', @{ $self->{'Cc'} } ) )
-      if ( $self->{'Cc'} && @{ $self->{'Cc'} } );
-    $self->SetHeader( 'Bcc', join ( ',', @{ $self->{'Bcc'} } ) )
-      if ( $self->{'Cc'} && @{ $self->{'Bcc'} } );
+    # TODO: We should be pulling the recipients out of the template and shove them into To, Cc and Bcc
+
+    $self->SetHeader( 'To', join ( ', ', @{ $self->{'To'} } ) )
+      if ( ! $MIMEObj->head->get('To') &&  $self->{'To'} && @{ $self->{'To'} } );
+    $self->SetHeader( 'Cc', join ( ', ', @{ $self->{'Cc'} } ) )
+      if ( !$MIMEObj->head->get('Cc') && $self->{'Cc'} && @{ $self->{'Cc'} } );
+    $self->SetHeader( 'Bcc', join ( ', ', @{ $self->{'Bcc'} } ) )
+      if ( !$MIMEObj->head->get('Bcc') && $self->{'Bcc'} && @{ $self->{'Bcc'} } );
 
+    # PseudoTo (fake to headers) shouldn't get matched for message recipients.
+    # If we don't have any 'To' header (but do have other recipients), drop in
+    # the pseudo-to header.
+    $self->SetHeader( 'To', join ( ', ', @{ $self->{'PseudoTo'} } ) )
+      if ( $self->{'PseudoTo'} && ( @{ $self->{'PseudoTo'} } )
+        and ( !$MIMEObj->head->get('To') ) ) and ( $MIMEObj->head->get('Cc') or $MIMEObj->head->get('Bcc'));
 
-    $self->SetHeader('MIME-Version', '1.0');
+    # We should never have to set the MIME-Version header
+    $self->SetHeader( 'MIME-Version', '1.0' );
 
     # try to convert message body from utf-8 to $RT::EmailOutputEncoding
     $self->SetHeader( 'Content-Type', 'text/plain; charset="utf-8"' );
 
-    RT::I18N::SetMIMEEntityToEncoding( $MIMEObj, $RT::EmailOutputEncoding, 'mime_words_ok' );
+    RT::I18N::SetMIMEEntityToEncoding( $MIMEObj, $RT::EmailOutputEncoding,
+        'mime_words_ok' );
     $self->SetHeader( 'Content-Type', 'text/plain; charset="' . $RT::EmailOutputEncoding . '"' );
 
-
     # Build up a MIME::Entity that looks like the original message.
+    $self->AddAttachments() if ( $MIMEObj->head->get('RT-Attach-Message') );
 
-    my $do_attach = $self->TemplateObj->MIMEObj->head->get('RT-Attach-Message');
-
-    if ($do_attach) {
-        $self->TemplateObj->MIMEObj->head->delete('RT-Attach-Message');
-
-        my $attachments = RT::Attachments->new($RT::SystemUser);
-        $attachments->Limit( FIELD => 'TransactionId',
-                             VALUE => $self->TransactionObj->Id );
-        $attachments->OrderBy('id');
+    return $result;
 
-        my $transaction_content_obj = $self->TransactionObj->ContentObj;
+}
 
-        # attach any of this transaction's attachments
-        while ( my $attach = $attachments->Next ) {
+# }}}
 
-            # Don't attach anything blank
-            next unless ( $attach->ContentLength );
+# }}}
 
-            # We want to make sure that we don't include the attachment that's being sued as the "Content" of this message"
-            next
-              if (    $transaction_content_obj
-                   && $transaction_content_obj->Id == $attach->Id 
-                   && $transaction_content_obj->ContentType =~ qr{text/plain}i
-                );
-            $MIMEObj->make_multipart('mixed');
-            $MIMEObj->attach( Type => $attach->ContentType,
-                              Charset => $attach->OriginalEncoding,
-                              Data => $attach->OriginalContent,
-                              Filename => $self->MIMEEncodeString( $attach->Filename, $RT::EmailOutputEncoding ),
-                              Encoding    => '-SUGGEST');
-        }
 
-    }
 
+=head2 To
 
-    my $retval = $self->SendMessage($MIMEObj);
+Returns an array of Mail::Address objects containing all the To: recipients for this notification
 
+=cut
 
-    return ($retval);
+sub To {
+    my $self = shift;
+    return ($self->_AddressesFromHeader('To'));
 }
 
-# }}}
+=head2 Cc
 
-# {{{ sub Prepare
+Returns an array of Mail::Address objects containing all the Cc: recipients for this notification
 
-sub Prepare {
-    my $self = shift;
+=cut
 
-    # This actually populates the MIME::Entity fields in the Template Object
+sub Cc { 
+    my $self = shift;
+    return ($self->_AddressesFromHeader('Cc'));
+}
 
-    unless ( $self->TemplateObj ) {
-        $RT::Logger->warning("No template object handed to $self\n");
-    }
+=head2 Bcc
 
-    unless ( $self->TransactionObj ) {
-        $RT::Logger->warning("No transaction object handed to $self\n");
+Returns an array of Mail::Address objects containing all the Bcc: recipients for this notification
 
-    }
+=cut
 
-    unless ( $self->TicketObj ) {
-        $RT::Logger->warning("No ticket object handed to $self\n");
 
-    }
+sub Bcc {
+    my $self = shift;
+    return ($self->_AddressesFromHeader('Bcc'));
 
-    my ( $result, $message ) = $self->TemplateObj->Parse(
-                                         Argument       => $self->Argument,
-                                         TicketObj      => $self->TicketObj,
-                                         TransactionObj => $self->TransactionObj
-    );
-    if ($result) {
-
-        # Header
-        $self->SetSubject();
-        $self->SetSubjectToken();
-        $self->SetRecipients();
-        $self->SetReturnAddress();
-        $self->SetRTSpecialHeaders();
-        if ($RT::EmailOutputEncoding) {
-
-            # l10n related header
-            $self->SetHeaderAsEncoding( 'Subject', $RT::EmailOutputEncoding );
-        }
-    }
+}
 
-    return $result;
+sub _AddressesFromHeader  {
+    my $self = shift;
+    my $field = shift;
+    my $header = $self->TemplateObj->MIMEObj->head->get($field);
+    my @addresses = Mail::Address->parse($header);
 
+    return (@addresses);
 }
 
-# }}}
-
-# }}}
 
 # {{{ SendMessage
+
 =head2 SendMessage MIMEObj
 
 sends the message using RT's preferred API.
-TODO: Break this out to a seperate module
+TODO: Break this out to a separate module
 
 =cut
 
 sub SendMessage {
-    my $self = shift;
+    my $self    = shift;
     my $MIMEObj = shift;
 
     my $msgid = $MIMEObj->head->get('Message-Id');
+    chomp $msgid;
 
+    $RT::Logger->info( $msgid . " #"
+        . $self->TicketObj->id . "/"
+        . $self->TransactionObj->id
+        . " - Scrip "
+        . $self->ScripObj->id . " "
+        . $self->ScripObj->Description );
 
     #If we don't have any recipients to send to, don't send a message;
-    unless (    $MIMEObj->head->get('To')
-             || $MIMEObj->head->get('Cc')
-             || $MIMEObj->head->get('Bcc') ) {
-        $RT::Logger->info($msgid.  " No recipients found. Not sending.\n");
+    unless ( $MIMEObj->head->get('To')
+        || $MIMEObj->head->get('Cc')
+        || $MIMEObj->head->get('Bcc') )
+    {
+        $RT::Logger->info( $msgid . " No recipients found. Not sending.\n" );
         return (1);
     }
 
-    # PseudoTo (fake to headers) shouldn't get matched for message recipients.
-    # If we don't have any 'To' header, drop in the pseudo-to header.
 
-    $self->SetHeader( 'To', join ( ',', @{ $self->{'PseudoTo'} } ) )
-      if ( $self->{'PseudoTo'} && ( @{ $self->{'PseudoTo'} } )
-           and ( !$MIMEObj->head->get('To') ) );
     if ( $RT::MailCommand eq 'sendmailpipe' ) {
         eval {
-            open( MAIL, "|$RT::SendmailPath $RT::SendmailArguments" );
+            open( MAIL, "|$RT::SendmailPath $RT::SendmailArguments" ) || die $!;
             print MAIL $MIMEObj->as_string;
             close(MAIL);
-          };
-          if ($@) {
-            $RT::Logger->crit($msgid.  "Could not send mail. -".$@ );
+        };
+        if ($@) {
+            $RT::Logger->crit( $msgid . "Could not send mail. -" . $@ );
         }
     }
     else {
-       my @mailer_args = ($RT::MailCommand);
-       local $ENV{MAILADDRESS};
+        my @mailer_args = ($RT::MailCommand);
+
+        local $ENV{MAILADDRESS};
 
         if ( $RT::MailCommand eq 'sendmail' ) {
-           push @mailer_args, $RT::SendmailArguments;
+            push @mailer_args, split(/\s+/, $RT::SendmailArguments);
         }
         elsif ( $RT::MailCommand eq 'smtp' ) {
-           $ENV{MAILADDRESS} = $RT::SMTPFrom || $MIMEObj->head->get('From');
-           push @mailer_args, (Server => $RT::SMTPServer);
-           push @mailer_args, (Debug => $RT::SMTPDebug);
+            $ENV{MAILADDRESS} = $RT::SMTPFrom || $MIMEObj->head->get('From');
+            push @mailer_args, ( Server => $RT::SMTPServer );
+            push @mailer_args, ( Debug  => $RT::SMTPDebug );
+        }
+        else {
+            push @mailer_args, $RT::MailParams;
         }
-       else {
-           push @mailer_args, $RT::MailParams;
-       }
 
-        unless ( $MIMEObj->send( @mailer_args ) ) {
-            $RT::Logger->crit($msgid.  "Could not send mail." );
+        unless ( $MIMEObj->send(@mailer_args) ) {
+            $RT::Logger->crit( $msgid . "Could not send mail." );
             return (0);
         }
     }
 
-
-     my $success = ($msgid. " sent To: ".$MIMEObj->head->get('To') . " Cc: ".$MIMEObj->head->get('Cc') . " Bcc: ".$MIMEObj->head->get('Bcc'));
+    my $success =
+      ( $msgid
+      . " sent To: "
+      . $MIMEObj->head->get('To') . " Cc: "
+      . $MIMEObj->head->get('Cc') . " Bcc: "
+      . $MIMEObj->head->get('Bcc') );
     $success =~ s/\n//gi;
+
+    $self->RecordOutgoingMailTransaction($MIMEObj) if ($RT::RecordOutgoingEmail);
+
     $RT::Logger->info($success);
 
     return (1);
@@ -306,51 +295,139 @@ sub SendMessage {
 
 # }}}
 
-# {{{ Deal with message headers (Set* subs, designed for  easy overriding)
+# {{{ AddAttachments 
 
-# {{{ sub SetRTSpecialHeaders
+=head2 AddAttachments
 
-=head2 SetRTSpecialHeaders 
+Takes any attachments to this transaction and attaches them to the message
+we're building.
+
+=cut
 
-This routine adds all the random headers that RT wants in a mail message
-that don't matter much to anybody else.
+
+sub AddAttachments {
+    my $self = shift;
+
+    my $MIMEObj = $self->TemplateObj->MIMEObj;
+
+    $MIMEObj->head->delete('RT-Attach-Message');
+
+    my $attachments = RT::Attachments->new($RT::SystemUser);
+    $attachments->Limit(
+        FIELD => 'TransactionId',
+        VALUE => $self->TransactionObj->Id
+    );
+    $attachments->OrderBy('id');
+
+    my $transaction_content_obj = $self->TransactionObj->ContentObj;
+
+    # attach any of this transaction's attachments
+    while ( my $attach = $attachments->Next ) {
+
+        # Don't attach anything blank
+        next unless ( $attach->ContentLength );
+
+# We want to make sure that we don't include the attachment that's being sued as the "Content" of this message"
+        next
+          if ( $transaction_content_obj
+            && $transaction_content_obj->Id == $attach->Id
+            && $transaction_content_obj->ContentType =~ qr{text/plain}i );
+        $MIMEObj->make_multipart('mixed');
+        $MIMEObj->attach(
+            Type     => $attach->ContentType,
+            Charset  => $attach->OriginalEncoding,
+            Data     => $attach->OriginalContent,
+            Filename => $self->MIMEEncodeString( $attach->Filename,
+                $RT::EmailOutputEncoding ),
+            'RT-Attachment:' => $self->TicketObj->Id."/".$self->TransactionObj->Id."/".$attach->id,
+            Encoding => '-SUGGEST'
+        );
+    }
+
+}
+
+# }}}
+
+# {{{ RecordOutgoingMailTransaction
+
+=head2 RecordOutgoingMailTransaction MIMEObj
+
+Record a transaction in RT with this outgoing message for future record-keeping purposes
 
 =cut
 
-sub SetRTSpecialHeaders {
+
+
+sub RecordOutgoingMailTransaction {
     my $self = shift;
+    my $MIMEObj = shift;
+           
+
+    my @parts = $MIMEObj->parts;
+    my @attachments;
+    my @keep;
+    foreach my $part (@parts) {
+        my $attach = $part->head->get('RT-Attachment');
+        if ($attach) {
+            $RT::Logger->debug("We found an attachment. we want to not record it.");
+            push @attachments, $attach;
+        } else {
+            $RT::Logger->debug("We found a part. we want to record it.");
+            push @keep, $part;
+        }
+    }
+    $MIMEObj->parts(\@keep);
+    foreach my $attachment (@attachments) {
+        $MIMEObj->head->add('RT-Attachment', $attachment);
+    }
 
-    $self->SetReferences();
+    RT::I18N::SetMIMEEntityToEncoding( $MIMEObj, 'utf-8', 'mime_words_ok' );
 
-    $self->SetMessageID();
+    my $transaction = RT::Transaction->new($self->TransactionObj->CurrentUser);
 
-    $self->SetPrecedence();
+    # XXX: TODO -> Record attachments as references to things in the attachments table, maybe.
 
-    $self->SetHeader( 'X-RT-Loop-Prevention', $RT::rtname );
-    $self->SetHeader( 'RT-Ticket',
-                      $RT::rtname . " #" . $self->TicketObj->id() );
-    $self->SetHeader( 'Managed-by',
-                      "RT $RT::VERSION (http://www.bestpractical.com/rt/)" );
+    my $type;
+    if ($self->TransactionObj->Type eq 'Comment') {
+        $type = 'CommentEmailRecord';
+    } else {
+        $type = 'EmailRecord';
+    }
+
+
+      
+    my ( $id, $msg ) = $transaction->Create(
+        Ticket         => $self->TicketObj->Id,
+        Type           => $type,
+        Data           => $MIMEObj->head->get('Message-Id'),
+        MIMEObj        => $MIMEObj,
+        ActivateScrips => 0
+    );
 
-    $self->SetHeader( 'RT-Originator',
-                      $self->TransactionObj->CreatorObj->EmailAddress );
-    return ();
 
 }
 
-# {{{ sub SetReferences
+# }}}
+#
+
+# {{{ sub SetRTSpecialHeaders
+
+=head2 SetRTSpecialHeaders 
 
-=head2 SetReferences 
-  
-  # This routine will set the References: and In-Reply-To headers,
-# autopopulating it with all the correspondence on this ticket so
-# far. This should make RT responses threadable.
+This routine adds all the random headers that RT wants in a mail message
+that don't matter much to anybody else.
 
 =cut
 
-sub SetReferences {
+sub SetRTSpecialHeaders {
     my $self = shift;
 
+    $self->SetSubject();
+    $self->SetSubjectToken();
+    $self->SetHeaderAsEncoding( 'Subject', $RT::EmailOutputEncoding )
+      if ($RT::EmailOutputEncoding);
+    $self->SetReturnAddress();
+
     # TODO: this one is broken.  What is this email really a reply to?
     # If it's a reply to an incoming message, we'll need to use the
     # actual message-id from the appropriate Attachment object.  For
@@ -358,46 +435,93 @@ sub SetReferences {
     # References.
 
     $self->SetHeader( 'In-Reply-To',
-                   "<rt-" . $self->TicketObj->id() . "\@" . $RT::rtname . ">" );
+        "<rt-" . $self->TicketObj->id() . "\@" . $RT::rtname . ">" );
 
     # TODO We should always add References headers for all message-ids
     # of previous messages related to this ticket.
+
+    $self->SetHeader( 'Message-ID',
+        "<rt-"
+        . $RT::VERSION . "-"
+        . $self->TicketObj->id() . "-"
+        . $self->TransactionObj->id() . "-"
+        . $self->ScripObj->Id . "."
+        . rand(20) . "\@"
+        . $RT::Organization . ">" )
+      unless $self->TemplateObj->MIMEObj->head->get('Message-ID');
+
+    $self->SetHeader( 'Precedence', "bulk" )
+      unless ( $self->TemplateObj->MIMEObj->head->get("Precedence") );
+
+    $self->SetHeader( 'X-RT-Loop-Prevention', $RT::rtname );
+    $self->SetHeader( 'RT-Ticket',
+        $RT::rtname . " #" . $self->TicketObj->id() );
+    $self->SetHeader( 'Managed-by',
+        "RT $RT::VERSION (http://www.bestpractical.com/rt/)" );
+
+    $self->SetHeader( 'RT-Originator',
+        $self->TransactionObj->CreatorObj->EmailAddress );
+
 }
 
 # }}}
 
-# {{{ sub SetMessageID
 
-=head2 SetMessageID 
+# }}}
+
+# {{{ RemoveInappropriateRecipients
 
-Without this one, threading won't work very nice in email agents.
-Anyway, I'm not really sure it's that healthy if we need to send
-several separate/different emails about the same transaction.
+=head2 RemoveInappropriateRecipients
+
+Remove addresses that are RT addresses or that are on this transaction's blacklist
 
 =cut
 
-sub SetMessageID {
+sub RemoveInappropriateRecipients {
     my $self = shift;
 
-    # TODO this one might be sort of broken.  If we have several scrips +++
-    # sending several emails to several different persons, we need to
-    # pull out different message-ids.  I'd suggest message ids like
-    # "rt-ticket#-transaction#-scrip#-receipient#"
+    my @blacklist;
 
-    $self->SetHeader( 'Message-ID',
-                      "<rt-"
-                        . $RT::VERSION ."-"
-                        . $self->TicketObj->id() . "-"
-                        . $self->TransactionObj->id() . "."
-                        . rand(20) . "\@"
-                        . $RT::Organization . ">" )
-      unless $self->TemplateObj->MIMEObj->head->get('Message-ID');
-}
+    # Weed out any RT addresses. We really don't want to talk to ourselves!
+    @{ $self->{'To'} } =
+      RT::EmailParser::CullRTAddresses( "", @{ $self->{'To'} } );
+    @{ $self->{'Cc'} } =
+      RT::EmailParser::CullRTAddresses( "", @{ $self->{'Cc'} } );
+    @{ $self->{'Bcc'} } =
+      RT::EmailParser::CullRTAddresses( "", @{ $self->{'Bcc'} } );
 
-# }}}
+    # If there are no recipients, don't try to send the message.
+    # If the transaction has content and has the header RT-Squelch-Replies-To
 
-# }}}
+    if ( defined $self->TransactionObj->Attachments->First() ) {
+        my $squelch =
+          $self->TransactionObj->Attachments->First->GetHeader(
+            'RT-Squelch-Replies-To');
+
+        if ($squelch) {
+            @blacklist = split ( /,/, $squelch );
+        }
+    }
 
+# Let's grab the SquelchMailTo attribue and push those entries into the @blacklist
+    my @non_recipients = $self->TicketObj->SquelchMailTo;
+    foreach my $attribute (@non_recipients) {
+        push @blacklist, $attribute->Content;
+    }
+
+    # Cycle through the people we're sending to and pull out anyone on the
+    # system blacklist
+
+    foreach my $person_to_yank (@blacklist) {
+        $person_to_yank =~ s/\s//g;
+        @{ $self->{'To'} } = grep ( !/^$person_to_yank$/, @{ $self->{'To'} } );
+        @{ $self->{'Cc'} } = grep ( !/^$person_to_yank$/, @{ $self->{'Cc'} } );
+        @{ $self->{'Bcc'} } =
+          grep ( !/^$person_to_yank$/, @{ $self->{'Bcc'} } );
+    }
+}
+
+# }}}
 # {{{ sub SetReturnAddress
 
 =head2 SetReturnAddress is_comment => BOOLEAN
@@ -409,8 +533,10 @@ Calculate and set From and Reply-To headers based on the is_comment flag.
 sub SetReturnAddress {
 
     my $self = shift;
-    my %args = ( is_comment => 0,
-                 @_ );
+    my %args = (
+        is_comment => 0,
+        @_
+    );
 
     # From and Reply-To
     # $args{is_comment} should be set if the comment address is to be used.
@@ -426,21 +552,26 @@ sub SetReturnAddress {
     }
 
     unless ( $self->TemplateObj->MIMEObj->head->get('From') ) {
-       if ($RT::UseFriendlyFromLine) {
-           my $friendly_name = $self->TransactionObj->CreatorObj->RealName;
-           if ( $friendly_name =~ /^"(.*)"$/ ) {    # a quoted string
-               $friendly_name = $1;
-           }
-
-           $friendly_name =~ s/"/\\"/g;
-           $self->SetHeader( 'From',
-                       sprintf($RT::FriendlyFromLineFormat, 
-                $self->MIMEEncodeString( $friendly_name, $RT::EmailOutputEncoding ), $replyto),
-           );
-       }
-       else {
-           $self->SetHeader( 'From', $replyto );
-       }
+        if ($RT::UseFriendlyFromLine) {
+            my $friendly_name = $self->TransactionObj->CreatorObj->RealName;
+            if ( $friendly_name =~ /^"(.*)"$/ ) {    # a quoted string
+                $friendly_name = $1;
+            }
+
+            $friendly_name =~ s/"/\\"/g;
+            $self->SetHeader(
+                'From',
+                sprintf(
+                    $RT::FriendlyFromLineFormat,
+                    $self->MIMEEncodeString( $friendly_name,
+                        $RT::EmailOutputEncoding ),
+                    $replyto
+                ),
+            );
+        }
+        else {
+            $self->SetHeader( 'From', $replyto );
+        }
     }
 
     unless ( $self->TemplateObj->MIMEObj->head->get('Reply-To') ) {
@@ -473,82 +604,6 @@ sub SetHeader {
 
 # }}}
 
-# {{{ sub SetRecipients
-
-=head2 SetRecipients
-
-Dummy method to be overriden by subclasses which want to set the recipients.
-
-=cut
-
-sub SetRecipients {
-    my $self = shift;
-    return ();
-}
-
-# }}}
-
-# {{{ sub SetTo
-
-=head2 SetTo
-
-Takes a string that is the addresses you want to send mail to
-
-=cut
-
-sub SetTo {
-    my $self      = shift;
-    my $addresses = shift;
-    return $self->SetHeader( 'To', $addresses );
-}
-
-# }}}
-
-# {{{ sub SetCc
-
-=head2 SetCc
-
-Takes a string that is the addresses you want to Cc
-
-=cut
-
-sub SetCc {
-    my $self      = shift;
-    my $addresses = shift;
-
-    return $self->SetHeader( 'Cc', $addresses );
-}
-
-# }}}
-
-# {{{ sub SetBcc
-
-=head2 SetBcc
-
-Takes a string that is the addresses you want to Bcc
-
-=cut
-
-sub SetBcc {
-    my $self      = shift;
-    my $addresses = shift;
-
-    return $self->SetHeader( 'Bcc', $addresses );
-}
-
-# }}}
-
-# {{{ sub SetPrecedence
-
-sub SetPrecedence {
-    my $self = shift;
-
-    unless ( $self->TemplateObj->MIMEObj->head->get("Precedence") ) {
-        $self->SetHeader( 'Precedence', "bulk" );
-    }
-}
-
-# }}}
 
 # {{{ sub SetSubject
 
@@ -564,36 +619,33 @@ sub SetSubject {
     my $self = shift;
     my $subject;
 
-    unless ( $self->TemplateObj->MIMEObj->head->get('Subject') ) {
-        my $message = $self->TransactionObj->Attachments;
-        my $ticket  = $self->TicketObj->Id;
-
-        if ( $self->{'Subject'} ) {
-            $subject = $self->{'Subject'};
-        }
-        elsif (    ( $message->First() )
-                && ( $message->First->Headers ) ) {
-            my $header = $message->First->Headers();
-            $header =~ s/\n\s+/ /g;
-            if ( $header =~ /^Subject: (.*?)$/m ) {
-                $subject = $1;
-            }
-            else {
-                $subject = $self->TicketObj->Subject();
-            }
-
+    my $message = $self->TransactionObj->Attachments;
+    if ( $self->TemplateObj->MIMEObj->head->get('Subject') ) {
+        return ();
+    }
+    if ( $self->{'Subject'} ) {
+        $subject = $self->{'Subject'};
+    }
+    elsif ( ( $message->First() ) && ( $message->First->Headers ) ) {
+        my $header = $message->First->Headers();
+        $header =~ s/\n\s+/ /g;
+        if ( $header =~ /^Subject: (.*?)$/m ) {
+            $subject = $1;
         }
         else {
             $subject = $self->TicketObj->Subject();
         }
 
-        $subject =~ s/(\r\n|\n|\s)/ /gi;
+    }
+    else {
+        $subject = $self->TicketObj->Subject();
+    }
 
-        chomp $subject;
-        $self->SetHeader( 'Subject', $subject );
+    $subject =~ s/(\r\n|\n|\s)/ /gi;
+
+    chomp $subject;
+    $self->SetHeader( 'Subject', $subject );
 
-    }
-    return ($subject);
 }
 
 # }}}
@@ -621,7 +673,7 @@ sub SetSubjectToken {
 
 # }}}
 
-# {{{
+# {{{ SetHeadingAsEncoding
 
 =head2 SetHeaderAsEncoding($field_name, $charset_encoding)
 
@@ -652,7 +704,7 @@ sub SetHeaderAsEncoding {
 } 
 # }}}
 
-# {{{ MIMENcodeString
+# {{{ MIMEEncodeString
 
 =head2 MIMEEncodeString STRING ENCODING
 
@@ -663,15 +715,41 @@ Takes a string and a possible encoding and returns the string wrapped in MIME go
 sub MIMEEncodeString {
     my  $self = shift;
     my $value = shift;
-    my $enc = shift;
+    # using RFC2047 notation, sec 2.
+    # encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
+    my $charset = shift;
+    my $encoding = 'B';
+    # An 'encoded-word' may not be more than 75 characters long
+    #
+    # MIME encoding increases 4/3*(number of bytes), and always in multiples
+    # of 4. Thus we have to find the best available value of bytes available
+    # for each chunk.
+    #
+    # First we get the integer max which max*4/3 would fit on space.
+    # Then we find the greater multiple of 3 lower or equal than $max.
+    my $max = int(((75-length('=?'.$charset.'?'.$encoding.'?'.'?='))*3)/4);
+    $max = int($max/3)*3;
 
     chomp $value;
     return ($value) unless $value =~ /[^\x20-\x7e]/;
 
     $value =~ s/\s*$//;
     Encode::_utf8_off($value);
-    my $res = Encode::from_to( $value, "utf-8", $enc );
-    $value = encode_mimeword( $value,  'B', $enc );
+    my $res = Encode::from_to( $value, "utf-8", $charset );
+   
+    if ($max > 0) {
+      # copy value and split in chuncks
+      my $str=$value;
+      my @chunks = unpack("a$max" x int(length($str)/$max 
+                                  + ((length($str) % $max) ? 1:0)), $str);
+      # encode an join chuncks
+      $value = join " ", 
+                     map encode_mimeword( $_, $encoding, $charset ), @chunks ;
+      return($value); 
+    } else {
+      # gives an error...
+      $RT::Logger->crit("Can't encode! Charset or encoding too big.\n");
+    }
 }
 
 # }}}
index 2ed5201..71aa4d5 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -61,7 +83,7 @@ sub _Init {
 
 
 
-=item Create PARAMHASH
+=head2 Create PARAMHASH
 
 Create takes a hash of values and creates a row in the database:
 
@@ -110,7 +132,7 @@ sub Create {
 
 
 
-=item id
+=head2 id
 
 Returns the current value of id. 
 (In the database, id is stored as int(11).)
@@ -119,14 +141,14 @@ Returns the current value of id.
 =cut
 
 
-=item TransactionId
+=head2 TransactionId
 
 Returns the current value of TransactionId. 
 (In the database, TransactionId is stored as int(11).)
 
 
 
-=item SetTransactionId VALUE
+=head2 SetTransactionId VALUE
 
 
 Set TransactionId to VALUE. 
@@ -137,14 +159,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Parent
+=head2 Parent
 
 Returns the current value of Parent. 
 (In the database, Parent is stored as int(11).)
 
 
 
-=item SetParent VALUE
+=head2 SetParent VALUE
 
 
 Set Parent to VALUE. 
@@ -155,14 +177,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item MessageId
+=head2 MessageId
 
 Returns the current value of MessageId. 
 (In the database, MessageId is stored as varchar(160).)
 
 
 
-=item SetMessageId VALUE
+=head2 SetMessageId VALUE
 
 
 Set MessageId to VALUE. 
@@ -173,14 +195,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Subject
+=head2 Subject
 
 Returns the current value of Subject. 
 (In the database, Subject is stored as varchar(255).)
 
 
 
-=item SetSubject VALUE
+=head2 SetSubject VALUE
 
 
 Set Subject to VALUE. 
@@ -191,14 +213,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Filename
+=head2 Filename
 
 Returns the current value of Filename. 
 (In the database, Filename is stored as varchar(255).)
 
 
 
-=item SetFilename VALUE
+=head2 SetFilename VALUE
 
 
 Set Filename to VALUE. 
@@ -209,14 +231,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item ContentType
+=head2 ContentType
 
 Returns the current value of ContentType. 
 (In the database, ContentType is stored as varchar(80).)
 
 
 
-=item SetContentType VALUE
+=head2 SetContentType VALUE
 
 
 Set ContentType to VALUE. 
@@ -227,14 +249,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item ContentEncoding
+=head2 ContentEncoding
 
 Returns the current value of ContentEncoding. 
 (In the database, ContentEncoding is stored as varchar(80).)
 
 
 
-=item SetContentEncoding VALUE
+=head2 SetContentEncoding VALUE
 
 
 Set ContentEncoding to VALUE. 
@@ -245,14 +267,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Content
+=head2 Content
 
 Returns the current value of Content. 
 (In the database, Content is stored as longtext.)
 
 
 
-=item SetContent VALUE
+=head2 SetContent VALUE
 
 
 Set Content to VALUE. 
@@ -263,14 +285,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Headers
+=head2 Headers
 
 Returns the current value of Headers. 
 (In the database, Headers is stored as longtext.)
 
 
 
-=item SetHeaders VALUE
+=head2 SetHeaders VALUE
 
 
 Set Headers to VALUE. 
@@ -281,7 +303,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Creator
+=head2 Creator
 
 Returns the current value of Creator. 
 (In the database, Creator is stored as int(11).)
@@ -290,7 +312,7 @@ Returns the current value of Creator.
 =cut
 
 
-=item Created
+=head2 Created
 
 Returns the current value of Created. 
 (In the database, Created is stored as datetime.)
@@ -300,7 +322,7 @@ Returns the current value of Created.
 
 
 
-sub _ClassAccessible {
+sub _CoreAccessible {
     {
      
         id =>
index 177cdd0..9ab11f3 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -64,7 +86,7 @@ sub _Init {
 }
 
 
-=item NewItem
+=head2 NewItem
 
 Returns an empty new RT::Attachment item
 
index 4519fcf..a338523 100644 (file)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
  
 
 package RT::Condition::AnyTransaction;
index bd26931..1f291fc 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 =head1 NAME
 
   RT::Condition::Generic - ;
@@ -57,10 +79,8 @@ ok (require RT::Condition::Generic);
 
 package RT::Condition::Generic;
 
-use RT::Base;
 use strict;
-use vars qw/@ISA/;
-@ISA = qw(RT::Base);
+use base qw/RT::Base/;
 
 # {{{ sub new 
 sub new  {
@@ -82,6 +102,7 @@ sub _Init  {
               TemplateObj => undef,
               Argument => undef,
               ApplicableTransTypes => undef,
+           CurrentUser => undef,
               @_ );
   
   $self->{'Argument'} = $args{'Argument'};
@@ -89,6 +110,7 @@ sub _Init  {
   $self->{'TicketObj'} = $args{'TicketObj'};
   $self->{'TransactionObj'} = $args{'TransactionObj'};
   $self->{'ApplicableTransTypes'} = $args{'ApplicableTransTypes'};
+  $self->CurrentUser($args{'CurrentUser'});
 }
 # }}}
 
index 8afabcd..1182fcd 100644 (file)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
  
 
 
index 4ca2f98..d147fe6 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
-# END LICENSE BLOCK
+# 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
 =head1 NAME
 
   RT::CurrentUser - an RT object representing the current user
@@ -51,8 +73,7 @@ use RT::Record;
 use RT::I18N;
 
 use strict;
-use vars qw/@ISA/;
-@ISA= qw(RT::Record);
+use base qw/RT::Record/;
 
 # {{{ sub _Init 
 
@@ -60,17 +81,30 @@ use vars qw/@ISA/;
 # to be a CurrentUser object. but that's hard to do when we're trying to load
 # the CurrentUser object
 
-sub _Init  {
-  my $self = shift;
-  my $Name = shift;
+sub _Init {
+    my $self = shift;
+    my $User = shift;
 
-  $self->{'table'} = "Users";
+    $self->{'table'} = "Users";
 
-  if (defined($Name)) {
-    $self->Load($Name);
-  }
-  
-  $self->CurrentUser($self);
+    if ( defined($User) ) {
+
+        if (   UNIVERSAL::isa( $User, 'RT::User' )
+            || UNIVERSAL::isa( $User, 'RT::CurrentUser' ) )
+        {
+            $self->Load( $User->id );
+
+        }
+        elsif ( ref($User) ) {
+            $RT::Logger->crit(
+                "RT::CurrentUser->new() called with a bogus argument: $User");
+        }
+        else {
+            $self->Load($User);
+        }
+    }
+
+    $self->_BuildTableAttributes();
 
 }
 # }}}
@@ -104,15 +138,13 @@ sub Delete {
 sub UserObj {
     my $self = shift;
     
-    unless ($self->{'UserObj'}) {
        use RT::User;
-       $self->{'UserObj'} = RT::User->new($self);
-       unless ($self->{'UserObj'}->Load($self->Id)) {
+       my $user = RT::User->new($self);
+
+       unless ($user->Load($self->Id)) {
            $RT::Logger->err($self->loc("Couldn't load [_1] from the users database.\n", $self->Id));
        }
-       
-    }
-    return ($self->{'UserObj'});
+    return ($user);
 }
 # }}}
 
@@ -153,18 +185,18 @@ sub PrincipalId {
 
 
 # {{{ sub _Accessible 
-sub _Accessible  {
-  my $self = shift;
-  my %Cols = (
-             Name => 'read',
-             Gecos => 'read',
-             RealName => 'read',
-             Password => 'neither',
-             EmailAddress => 'read',
-             Privileged => 'read',
-             IsAdministrator => 'read'
-            );
-  return($self->SUPER::_Accessible(@_, %Cols));
+
+
+ sub _CoreAccessible  {
+     {
+         Name           => { 'read' => 1 },
+           Gecos        => { 'read' => 1 },
+           RealName     => { 'read' => 1 },
+           Lang     => { 'read' => 1 },
+           Password     => { 'read' => 0, 'write' => 0 },
+          EmailAddress => { 'read' => 1, 'write' => 0 }
+     };
+  
 }
 # }}}
 
@@ -241,6 +273,11 @@ sub Load  {
   if ($identifier !~ /\D/) {
     $self->SUPER::LoadById($identifier);
   }
+
+  elsif (UNIVERSAL::isa($identifier,"RT::User")) {
+         # DWIM if they pass a user in
+         $self->SUPER::LoadById($identifier->Id);
+  } 
   else {
       # This is a bit dangerous, we might get false authen if somebody
       # uses ambigous userids or real names:
@@ -326,16 +363,24 @@ ok ($cu->loc('Before') eq "Avant", "Localized TEST_STRING into Frenc");
 
 sub LanguageHandle {
     my $self = shift;
-    if  ((!defined $self->{'LangHandle'}) || 
-         (!UNIVERSAL::can($self->{'LangHandle'}, 'maketext')) || 
-         (@_))  {
+    if (   ( !defined $self->{'LangHandle'} )
+        || ( !UNIVERSAL::can( $self->{'LangHandle'}, 'maketext' ) )
+        || (@_) ) {
+        if ( (!$RT::SystemUser || $self->id == $RT::SystemUser->id() )) {
+            @_ = qw(en-US);
+        }
+
+        elsif ( $self->Lang ) {
+            push @_, $self->Lang;
+        }
         $self->{'LangHandle'} = RT::I18N->get_handle(@_);
     }
+
     # Fall back to english.
-    unless ($self->{'LangHandle'}) {
+    unless ( $self->{'LangHandle'} ) {
         die "We couldn't get a dictionary. Nye mogu naidti slovar. No puedo encontrar dictionario.";
     }
-    return ($self->{'LangHandle'});
+    return ( $self->{'LangHandle'} );
 }
 
 sub loc {
@@ -365,6 +410,20 @@ sub loc_fuzzy {
 }
 # }}}
 
+
+=head2 CurrentUser
+
+Return  the current currentuser object
+
+=cut
+
+sub CurrentUser {
+    my $self = shift;
+    return($self);
+
+}
+
+
 eval "require RT::CurrentUser_Vendor";
 die $@ if ($@ && $@ !~ qr{^Can't locate RT/CurrentUser_Vendor.pm});
 eval "require RT::CurrentUser_Local";
index 355370a..a000b8d 100644 (file)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
-# END LICENSE BLOCK
+# 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
 =head1 NAME
 
   RT::Date - a simple Object Oriented date.
@@ -330,7 +352,8 @@ sub DurationAsString {
         $s         = int( $duration / $YEAR );
         $time_unit = $self->loc("years");
     }
-    if (0) { # For now, never display the "AGO" # $negative) {
+
+    if ($negative) {
         return $self->loc( "[_1] [_2] ago", $s, $time_unit );
     }
     else {
@@ -529,6 +552,24 @@ sub ISO {
 
 # }}}
 
+# {{{ sub W3CDTF
+
+=head2 W3CDTF
+
+Takes nothing
+
+Returns the object's date in W3C DTF format
+
+=cut
+
+sub W3CDTF {
+    my $self = shift;
+    my $date = $self->ISO . 'Z';
+    $date =~ s/ /T/;
+    return $date;
+};
+
+# }}}
 
 # {{{ sub LocalTimezone 
 =head2 LocalTimezone
index 4dcef3f..60f7fb7 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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:
 # 
-# END LICENSE BLOCK
+# (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.)
+# 
+# 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
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -61,7 +83,7 @@ sub _Init {
 
 
 
-=item Create PARAMHASH
+=head2 Create PARAMHASH
 
 Create takes a hash of values and creates a row in the database:
 
@@ -69,7 +91,7 @@ Create takes a hash of values and creates a row in the database:
   varchar(255) 'Description'.
   varchar(64) 'Domain'.
   varchar(64) 'Type'.
-  varchar(64) 'Instance'.
+  int(11) 'Instance'.
 
 =cut
 
@@ -98,7 +120,7 @@ sub Create {
 
 
 
-=item id
+=head2 id
 
 Returns the current value of id. 
 (In the database, id is stored as int(11).)
@@ -107,14 +129,14 @@ Returns the current value of id.
 =cut
 
 
-=item Name
+=head2 Name
 
 Returns the current value of Name. 
 (In the database, Name is stored as varchar(200).)
 
 
 
-=item SetName VALUE
+=head2 SetName VALUE
 
 
 Set Name to VALUE. 
@@ -125,14 +147,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Description
+=head2 Description
 
 Returns the current value of Description. 
 (In the database, Description is stored as varchar(255).)
 
 
 
-=item SetDescription VALUE
+=head2 SetDescription VALUE
 
 
 Set Description to VALUE. 
@@ -143,14 +165,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Domain
+=head2 Domain
 
 Returns the current value of Domain. 
 (In the database, Domain is stored as varchar(64).)
 
 
 
-=item SetDomain VALUE
+=head2 SetDomain VALUE
 
 
 Set Domain to VALUE. 
@@ -161,14 +183,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Type
+=head2 Type
 
 Returns the current value of Type. 
 (In the database, Type is stored as varchar(64).)
 
 
 
-=item SetType VALUE
+=head2 SetType VALUE
 
 
 Set Type to VALUE. 
@@ -179,26 +201,26 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Instance
+=head2 Instance
 
 Returns the current value of Instance. 
-(In the database, Instance is stored as varchar(64).)
+(In the database, Instance is stored as int(11).)
 
 
 
-=item SetInstance VALUE
+=head2 SetInstance VALUE
 
 
 Set Instance to VALUE. 
 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
-(In the database, Instance will be stored as a varchar(64).)
+(In the database, Instance will be stored as a int(11).)
 
 
 =cut
 
 
 
-sub _ClassAccessible {
+sub _CoreAccessible {
     {
      
         id =>
@@ -212,7 +234,7 @@ sub _ClassAccessible {
         Type => 
                {read => 1, write => 1, type => 'varchar(64)', default => ''},
         Instance => 
-               {read => 1, write => 1, type => 'varchar(64)', default => ''},
+               {read => 1, write => 1, type => 'int(11)', default => ''},
 
  }
 };
index 8de1a73..e116519 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -61,7 +83,7 @@ sub _Init {
 
 
 
-=item Create PARAMHASH
+=head2 Create PARAMHASH
 
 Create takes a hash of values and creates a row in the database:
 
@@ -89,7 +111,7 @@ sub Create {
 
 
 
-=item id
+=head2 id
 
 Returns the current value of id. 
 (In the database, id is stored as int(11).)
@@ -98,14 +120,14 @@ Returns the current value of id.
 =cut
 
 
-=item GroupId
+=head2 GroupId
 
 Returns the current value of GroupId. 
 (In the database, GroupId is stored as int(11).)
 
 
 
-=item SetGroupId VALUE
+=head2 SetGroupId VALUE
 
 
 Set GroupId to VALUE. 
@@ -116,14 +138,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item MemberId
+=head2 MemberId
 
 Returns the current value of MemberId. 
 (In the database, MemberId is stored as int(11).)
 
 
 
-=item SetMemberId VALUE
+=head2 SetMemberId VALUE
 
 
 Set MemberId to VALUE. 
@@ -135,7 +157,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 
 
 
-sub _ClassAccessible {
+sub _CoreAccessible {
     {
      
         id =>
index 31cb953..bd74c51 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -64,7 +86,7 @@ sub _Init {
 }
 
 
-=item NewItem
+=head2 NewItem
 
 Returns an empty new RT::GroupMember item
 
index 29f12a5..1c4278c 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -64,7 +86,7 @@ sub _Init {
 }
 
 
-=item NewItem
+=head2 NewItem
 
 Returns an empty new RT::Group item
 
index 5cdb65e..8d4563b 100644 (file)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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:
 # 
-# END LICENSE BLOCK
+# (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.)
+# 
+# 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
 =head1 NAME
 
   RT::Handle - RT's database handle
@@ -48,7 +70,13 @@ use vars qw/@ISA/;
 
 eval "use DBIx::SearchBuilder::Handle::$RT::DatabaseType;
 \@ISA= qw(DBIx::SearchBuilder::Handle::$RT::DatabaseType);";
-#TODO check for errors here.
+
+if ($@) {
+    die "Unable to load DBIx::SearchBuilder database handle for '$RT::DatabaseType'.".
+        "\n".
+        "Perhaps you've picked an invalid database type or spelled it incorrectly.".
+        "\n". $@;
+}
 
 =head2 Connect
 
@@ -58,14 +86,18 @@ Takes nothing. Calls SUPER::Connect with the needed args
 =cut
 
 sub Connect {
-my $self=shift;
+    my $self = shift;
 
-# Unless the database port is a positive integer, we really don't want to pass it.
+    if ($RT::DatabaseType eq 'Oracle') {
+        $ENV{'NLS_LANG'} = ".UTF8";
+    }
 
-$self->SUPER::Connect(
+    $self->SUPER::Connect(
                         User => $RT::DatabaseUser,
                         Password => $RT::DatabasePassword,
                        );
+
+    $self->dbh->{LongReadLen} = $RT::MaxAttachmentSize;
    
 }
 
@@ -79,9 +111,11 @@ from the config file.
 
 sub BuildDSN {
     my $self = shift;
+# Unless the database port is a positive integer, we really don't want to pass it.
 $RT::DatabasePort = undef unless (defined $RT::DatabasePort && $RT::DatabasePort =~ /^(\d+)$/);
 $RT::DatabaseHost = undef unless (defined $RT::DatabaseHost && $RT::DatabaseHost ne '');
 
+
     $self->SUPER::BuildDSN(Host => $RT::DatabaseHost, 
                         Database => $RT::DatabaseName, 
                         Port => $RT::DatabasePort,
index ec0e877..4179994 100644 (file)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 use strict;
 
 use RT;
@@ -33,7 +55,7 @@ BEGIN {
     use vars qw ($VERSION  @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
     
     # set the version for version checking
-    $VERSION = do { my @r = (q$Revision: 1.2 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; # must be all one line, for MakeMaker
+    $VERSION = do { my @r = (q$Revision: 1.1.1.2 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; # must be all one line, for MakeMaker
     
     @ISA         = qw(Exporter);
     
index 7eec050..04539a3 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
-# END LICENSE BLOCK
+# 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
 package RT::Interface::Email;
 
 use strict;
 use Mail::Address;
 use MIME::Entity;
 use RT::EmailParser;
-
+use File::Temp;
 
 BEGIN {
     use Exporter ();
     use vars qw ($VERSION  @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
     
     # set the version for version checking
-    $VERSION = do { my @r = (q$Revision: 1.2 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; # must be all one line, for MakeMaker
+    $VERSION = do { my @r = (q$Revision: 1.1.1.4 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; # must be all one line, for MakeMaker
     
     @ISA         = qw(Exporter);
     
@@ -57,7 +79,7 @@ BEGIN {
 
 =head1 NAME
 
-  RT::Interface::CLI - helper functions for creating a commandline RT interface
+  RT::Interface::Email - helper functions for parsing email sent to RT
 
 =head1 SYNOPSIS
 
@@ -153,6 +175,7 @@ sub MailError {
                Subject => 'There has been an error',
                Explanation => 'Unexplained error',
                MIMEObj => undef,
+        Attach => undef,
                LogLevel => 'crit',
                @_);
 
@@ -165,6 +188,7 @@ sub MailError {
                                      Bcc => $args{'Bcc'},
                                      To => $args{'To'},
                                      Subject => $args{'Subject'},
+                                     Precedence => 'bulk',
                                      'X-RT-Loop-Prevention' => $RT::rtname,
                                    );
 
@@ -175,14 +199,19 @@ sub MailError {
         $mimeobj->sync_headers();
         $entity->add_part($mimeobj);
     }
-    
+   
+    if ($args{'Attach'}) {
+        $entity->attach(Data => $args{'Attach'}, Type => 'message/rfc822');
+
+    }
+
     if ($RT::MailCommand eq 'sendmailpipe') {
         open (MAIL, "|$RT::SendmailPath $RT::SendmailArguments") || return(0);
         print MAIL $entity->as_string;
         close(MAIL);
     }
     else {
-       $entity->send($RT::MailCommand, $RT::MailParams);
+       $entity->send($RT::MailCommand, $RT::MailParams);
     }
 }
 
@@ -194,12 +223,6 @@ sub CreateUser {
     my ($Username, $Address, $Name, $ErrorsTo, $entity) = @_;
     my $NewUser = RT::User->new($RT::SystemUser);
 
-    # This data is tainted by some Very Broken mailers.
-    # (Sometimes they send raw ISO 8859-1 data here. fear that.
-    require Encode;
-    $Username = Encode::encode(utf8 => $Username, Encode::FB_PERLQQ()) if defined $Username;
-    $Name = Encode::encode(utf8 => $Name, Encode::FB_PERLQQ()) if defined $Name;
-    
     my ($Val, $Message) = 
       $NewUser->Create(Name => ($Username || $Address),
                        EmailAddress => $Address,
@@ -361,36 +384,82 @@ sub ParseAddressFromHeader{
 
 
 
-=head2 Gateway
+=head2 Gateway ARGSREF
+
+
+Takes parameters:
+
+    action
+    queue
+    message
+
 
 This performs all the "guts" of the mail rt-mailgate program, and is
 designed to be called from the web interface with a message, user
 object, and so on.
 
+Can also take an optional 'ticket' parameter; this ticket id overrides
+any ticket id found in the subject.
+
+Returns:
+
+    An array of:
+    
+    (status code, message, optional ticket object)
+
+    status code is a numeric value.
+
+    for temporary failures, status code should be -75
+
+    for permanent failures which are handled by RT, status code should be 0
+    
+    for succces, the status code should be 1
+
+
+
 =cut
 
 sub Gateway {
-    my %args = ( message => undef,
-                 queue   => 1,
-                 action  => 'correspond',
-                 ticket  => undef,
-                 @_ );
+    my $argsref = shift;
+
+    my %args = %$argsref;
+
+    # Set some reasonable defaults
+    $args{'action'} = 'correspond' unless ( $args{'action'} );
+    $args{'queue'}  = '1'          unless ( $args{'queue'} );
 
     # Validate the action
     unless ( $args{'action'} =~ /^(comment|correspond|action)$/ ) {
 
         # Can't safely loc this. What object do we loc around?
-        return ( 0, "Invalid 'action' parameter", undef );
+        $RT::Logger->crit("Mail gateway called with an invalid action paramenter '".$args{'action'}."' for queue '".$args{'queue'}."'");
+
+        return ( -75, "Invalid 'action' parameter", undef );
     }
 
     my $parser = RT::EmailParser->new();
-    $parser->ParseMIMEEntityFromScalar( $args{'message'} );
+
+    $parser->SmartParseMIMEEntityFromScalar( Message => $args{'message'});
+
+    if (!$parser->Entity()) {
+        MailError(
+            To          => $RT::OwnerEmail,
+            Subject     => "RT Bounce: Unparseable message",
+            Explanation => "RT couldn't process the message below",
+            Attach     => $args{'message'}
+        );
+
+        return(0,"Failed to parse this message. Something is likely badly wrong with the message");
+    }
 
     my $Message = $parser->Entity();
-    my $head = $Message->head;
+    my $head    = $Message->head;
 
     my ( $CurrentUser, $AuthStat, $status, $error );
 
+    # Initalize AuthStat so comparisons work correctly
+    $AuthStat = -9999999;
+
     my $ErrorsTo = ParseErrorsToAddressFromHead($head);
 
     my $MessageId = $head->get('Message-Id')
@@ -400,88 +469,111 @@ sub Gateway {
     my $Subject = $head->get('Subject') || '';
     chomp $Subject;
 
-
     $args{'ticket'} ||= $parser->ParseTicketId($Subject);
 
     my $SystemTicket;
-    if ($args{'ticket'} ) {
+    my $Right = 'CreateTicket';
+    if ( $args{'ticket'} ) {
         $SystemTicket = RT::Ticket->new($RT::SystemUser);
-        $SystemTicket->Load($args{'ticket'});
+        $SystemTicket->Load( $args{'ticket'} );
+       # if there's an existing ticket, this must be a reply
+       $Right = 'ReplyToTicket';
     }
 
     #Set up a queue object
     my $SystemQueueObj = RT::Queue->new($RT::SystemUser);
     $SystemQueueObj->Load( $args{'queue'} );
 
-
     # We can safely have no queue of we have a known-good ticket
     unless ( $args{'ticket'} || $SystemQueueObj->id ) {
-        MailError(
-                 To          => $RT::OwnerEmail,
-                 Subject     => "RT Bounce: $Subject",
-                 Explanation => "RT couldn't find the queue: " . $args{'queue'},
-                 MIMEObj     => $Message );
-        return ( 0, "RT couldn't find the queue: " . $args{'queue'}, undef );
+        return ( -75, "RT couldn't find the queue: " . $args{'queue'}, undef );
     }
 
     # Authentication Level
-    # -1 - Get out.  this user has been explicitly declined 
+    # -1 - Get out.  this user has been explicitly declined
     # 0 - User may not do anything (Not used at the moment)
     # 1 - Normal user
     # 2 - User is allowed to specify status updates etc. a la enhanced-mailgate
 
-    push @RT::MailPlugins, "Auth::MailFrom"   unless @RT::MailPlugins;
+    push @RT::MailPlugins, "Auth::MailFrom" unless @RT::MailPlugins;
+
     # Since this needs loading, no matter what
 
-    for (@RT::MailPlugins) {
+    foreach (@RT::MailPlugins) {
         my $Code;
         my $NewAuthStat;
         if ( ref($_) eq "CODE" ) {
             $Code = $_;
         }
         else {
-            $_ = "RT::Interface::Email::$_" unless /^RT::Interface::Email::/;
+            $_ = "RT::Interface::Email::".$_ unless $_ =~ /^RT::Interface::Email::/;
             eval "require $_;";
             if ($@) {
-                die ("Couldn't load module $_: $@");
+                $RT::Logger->crit("Couldn't load module '$_': $@");
                 next;
             }
             no strict 'refs';
             if ( !defined( $Code = *{ $_ . "::GetCurrentUser" }{CODE} ) ) {
-                die ("No GetCurrentUser code found in $_ module");
+                $RT::Logger->crit("No GetCurrentUser code found in $_ module");
                 next;
             }
         }
 
-        ( $CurrentUser, $NewAuthStat ) = $Code->( Message     => $Message,
-                                                  CurrentUser => $CurrentUser,
-                                                  AuthLevel   => $AuthStat,
-                                                  Action => $args{'action'},
-                                                  Ticket => $SystemTicket,
-                                                  Queue  => $SystemQueueObj );
+        ( $CurrentUser, $NewAuthStat ) = $Code->(
+            Message     => $Message,
+            RawMessageRef => \$args{'message'},
+            CurrentUser => $CurrentUser,
+            AuthLevel   => $AuthStat,
+            Action      => $args{'action'},
+            Ticket      => $SystemTicket,
+            Queue       => $SystemQueueObj
+        );
+
+
+        # If a module returns a "-1" then we discard the ticket, so.
+        $AuthStat = -1 if $NewAuthStat == -1;
 
         # You get the highest level of authentication you were assigned.
-        last if $AuthStat == -1;
         $AuthStat = $NewAuthStat if $NewAuthStat > $AuthStat;
+        last if $AuthStat == -1;
     }
 
     # {{{ If authentication fails and no new user was created, get out.
     if ( !$CurrentUser or !$CurrentUser->Id or $AuthStat == -1 ) {
 
         # If the plugins refused to create one, they lose.
-        MailError(
-            Subject     => "Could not load a valid user",
-            Explanation => <<EOT,
+        unless ( $AuthStat == -1 ) {
+
+            # Notify the RT Admin of the failure.
+            # XXX Should this be configurable?
+            MailError(
+                To          => $RT::OwnerEmail,
+                Subject     => "Could not load a valid user",
+                Explanation => <<EOT,
 RT could not load a valid user, and RT's configuration does not allow
-for the creation of a new user for your email.
+for the creation of a new user for this email ($ErrorsTo).
 
-Your RT administrator needs to grant 'Everyone' the right 'CreateTicket'
-for this queue.
+You might need to grant 'Everyone' the right '$Right' for the
+queue @{[$args{'queue'}]}.
 
 EOT
-            MIMEObj  => $Message,
-            LogLevel => 'error' )
-          unless $AuthStat == -1;
+                MIMEObj  => $Message,
+                LogLevel => 'error'
+            );
+
+            # Also notify the requestor that his request has been dropped.
+            MailError(
+                To          => $ErrorsTo,
+                Subject     => "Could not load a valid user",
+                Explanation => <<EOT,
+RT could not load a valid user, and RT's configuration does not allow
+for the creation of a new user for your email.
+
+EOT
+                MIMEObj  => $Message,
+                LogLevel => 'error'
+            );
+        }
         return ( 0, "Could not load a valid user", undef );
     }
 
@@ -508,10 +600,11 @@ EOT
     # {{{ Drop it if it's disallowed
     if ( $AuthStat == 0 ) {
         MailError(
-             To          => $ErrorsTo,
-             Subject     => "Permission Denied",
-             Explanation => "You do not have permission to communicate with RT",
-             MIMEObj     => $Message );
+            To          => $ErrorsTo,
+            Subject     => "Permission Denied",
+            Explanation => "You do not have permission to communicate with RT",
+            MIMEObj     => $Message
+        );
     }
 
     # }}}
@@ -523,14 +616,16 @@ EOT
 
         #Should we mail it to RTOwner?
         if ($RT::LoopsToRTOwner) {
-            MailError( To          => $RT::OwnerEmail,
-                       Subject     => "RT Bounce: $Subject",
-                       Explanation => "RT thinks this message may be a bounce",
-                       MIMEObj     => $Message );
-
-            #Do we actually want to store it?
-            return ( 0, "Message Bounced", undef ) unless ($RT::StoreLoops);
+            MailError(
+                To          => $RT::OwnerEmail,
+                Subject     => "RT Bounce: $Subject",
+                Explanation => "RT thinks this message may be a bounce",
+                MIMEObj     => $Message
+            );
         }
+
+        #Do we actually want to store it?
+        return ( 0, "Message Bounced", undef ) unless ($RT::StoreLoops);
     }
 
     # }}}
@@ -538,8 +633,10 @@ EOT
     # {{{ Squelch replies if necessary
     # Don't let the user stuff the RT-Squelch-Replies-To header.
     if ( $head->get('RT-Squelch-Replies-To') ) {
-        $head->add( 'RT-Relocated-Squelch-Replies-To',
-                    $head->get('RT-Squelch-Replies-To') );
+        $head->add(
+            'RT-Relocated-Squelch-Replies-To',
+            $head->get('RT-Squelch-Replies-To')
+        );
         $head->delete('RT-Squelch-Replies-To');
     }
 
@@ -564,22 +661,27 @@ EOT
         my @Requestors = ( $CurrentUser->id );
 
         if ($RT::ParseNewMessageForTicketCcs) {
-            @Cc = ParseCcAddressesFromHead( Head        => $head,
-                                            CurrentUser => $CurrentUser,
-                                            QueueObj    => $SystemQueueObj );
+            @Cc = ParseCcAddressesFromHead(
+                Head        => $head,
+                CurrentUser => $CurrentUser,
+                QueueObj    => $SystemQueueObj
+            );
         }
 
         my ( $id, $Transaction, $ErrStr ) = $Ticket->Create(
-                                                      Queue     => $SystemQueueObj->Id,
-                                                      Subject   => $Subject,
-                                                      Requestor => \@Requestors,
-                                                      Cc        => \@Cc,
-                                                      MIMEObj   => $Message );
+            Queue     => $SystemQueueObj->Id,
+            Subject   => $Subject,
+            Requestor => \@Requestors,
+            Cc        => \@Cc,
+            MIMEObj   => $Message
+        );
         if ( $id == 0 ) {
-            MailError( To          => $ErrorsTo,
-                       Subject     => "Ticket creation failed",
-                       Explanation => $ErrStr,
-                       MIMEObj     => $Message );
+            MailError(
+                To          => $ErrorsTo,
+                Subject     => "Ticket creation failed",
+                Explanation => $ErrStr,
+                MIMEObj     => $Message
+            );
             $RT::Logger->error("Create failed: $id / $Transaction / $ErrStr ");
             return ( 0, "Ticket creation failed", $Ticket );
         }
@@ -591,15 +693,17 @@ EOT
 
     #   If the action is comment, add a comment.
     elsif ( $args{'action'} =~ /^(comment|correspond)$/i ) {
-        $Ticket->Load($args{'ticket'});
+        $Ticket->Load( $args{'ticket'} );
         unless ( $Ticket->Id ) {
-            my $message = "Could not find a ticket with id ".$args{'ticket'};
-            MailError( To          => $ErrorsTo,
-                     Subject     => "Message not recorded",
-                     Explanation => $message,
-                     MIMEObj     => $Message );
-
-            return ( 0, $message);
+            my $message = "Could not find a ticket with id " . $args{'ticket'};
+            MailError(
+                To          => $ErrorsTo,
+                Subject     => "Message not recorded",
+                Explanation => $message,
+                MIMEObj     => $Message
+            );
+
+            return ( 0, $message );
         }
 
         my ( $status, $msg );
@@ -612,10 +716,12 @@ EOT
         unless ($status) {
 
             #Warn the sender that we couldn't actually submit the comment.
-            MailError( To          => $ErrorsTo,
-                       Subject     => "Message not recorded",
-                       Explanation => $msg,
-                       MIMEObj     => $Message );
+            MailError(
+                To          => $ErrorsTo,
+                Subject     => "Message not recorded",
+                Explanation => $msg,
+                MIMEObj     => $Message
+            );
             return ( 0, "Message not recorded", $Ticket );
         }
     }
@@ -623,23 +729,31 @@ EOT
     else {
 
         #Return mail to the sender with an error
-        MailError( To          => $ErrorsTo,
-                   Subject     => "RT Configuration error",
-                   Explanation => "'"
-                     . $args{'action'}
-                     . "' not a recognized action."
-                     . " Your RT administrator has misconfigured "
-                     . "the mail aliases which invoke RT",
-                   MIMEObj => $Message );
+        MailError(
+            To          => $ErrorsTo,
+            Subject     => "RT Configuration error",
+            Explanation => "'"
+              . $args{'action'}
+              . "' not a recognized action."
+              . " Your RT administrator has misconfigured "
+              . "the mail aliases which invoke RT",
+            MIMEObj => $Message
+        );
         $RT::Logger->crit( $args{'action'} . " type unknown for $MessageId" );
-        return ( 0, "Configuration error: " . $args{'action'} . " not a recognized action", $Ticket );
+        return (
+            -75,
+            "Configuration error: "
+              . $args{'action'}
+              . " not a recognized action",
+            $Ticket
+        );
 
     }
 
-
-return ( 1, "Success", $Ticket );
+    return ( 1, "Success", $Ticket );
 }
 
+
 eval "require RT::Interface::Email_Vendor";
 die $@ if ($@ && $@ !~ qr{^Can't locate RT/Interface/Email_Vendor.pm});
 eval "require RT::Interface::Email_Local";
index 5097f54..0151cc1 100644 (file)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 ## Portions Copyright 2000 Tobias Brox <tobix@fsck.com>
 
 ## This is a library of static subs to be used by the Mason web
@@ -45,94 +67,83 @@ use strict;
 
 
 
+# {{{ EscapeUTF8
 
+=head2 EscapeUTF8 SCALARREF
 
-# {{{ sub NewApacheHandler 
-
-=head2 NewApacheHandler
-
-  Takes extra options to pass to HTML::Mason::ApacheHandler->new
-  Returns a new Mason::ApacheHandler object
+does a css-busting but minimalist escaping of whatever html you're passing in.
 
 =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",
-        @_
-    );
+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);
+
 
-    $ah->interp->set_escape( h => \&RT::Interface::Web::EscapeUTF8 );
-    
-    return ($ah);
 }
 
 # }}}
 
-# {{{ sub NewCGIHandler 
+# {{{ WebCanonicalizeInfo
 
-=head2 NewCGIHandler
+=head2 WebCanonicalizeInfo();
 
-  Returns a new Mason::CGIHandler object
+Different web servers set different environmental varibles. This
+function must return something suitable for REMOTE_USER. By default,
+just downcase $ENV{'REMOTE_USER'}
 
 =cut
 
-sub NewCGIHandler {
-    my %args = (
-        @_
-    );
+sub WebCanonicalizeInfo {
+    my $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)]
-    );
-  
+    if ( defined $ENV{'REMOTE_USER'} ) {
+       $user = lc ( $ENV{'REMOTE_USER'} ) if( length($ENV{'REMOTE_USER'}) );
+    }
+
+    return $user;
+}
 
-    $handler->interp->set_escape( h => \&RT::Interface::Web::EscapeUTF8 );
+# }}}
 
+# {{{ WebExternalAutoInfo
 
-    return ($handler);
+=head2 WebExternalAutoInfo($user);
 
-}
-# }}}
+Returns a hash of user attributes, used when WebExternalAuto is set.
 
+=cut
 
-# {{{ EscapeUTF8
+sub WebExternalAutoInfo {
+    my $user = shift;
 
-=head2 EscapeUTF8 SCALARREF
+    my %user_info;
 
-does a css-busting but minimalist escaping of whatever html you're passing in.
+    $user_info{'Privileged'} = 1;
 
-=cut
+    if ($^O !~ /^(?:riscos|MacOS|MSWin32|dos|os2)$/) {
+       # Populate fields with information from Unix /etc/passwd
 
-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);
+       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
+    }
 
+    # and return the wad of stuff
+    return {%user_info};
 }
 
 # }}}
@@ -160,10 +171,13 @@ sub loc {
         UNIVERSAL::can($session{'CurrentUser'}, 'loc')){
         return($session{'CurrentUser'}->loc(@_));
     }
-    else  {
-        my $u = RT::CurrentUser->new($RT::SystemUser);
+    elsif ( my $u = eval { RT::CurrentUser->new($RT::SystemUser->Id) } ) {
         return ($u->loc(@_));
     }
+    else {
+       # pathetic case -- SystemUser is gone.
+       return $_[0];
+    }
 }
 
 # }}}
@@ -189,7 +203,7 @@ sub loc_fuzzy {
         return($session{'CurrentUser'}->loc_fuzzy($msg));
     }
     else  {
-        my $u = RT::CurrentUser->new($RT::SystemUser);
+        my $u = RT::CurrentUser->new($RT::SystemUser->Id);
         return ($u->loc_fuzzy($msg));
     }
 }
@@ -261,6 +275,7 @@ sub CreateTicket {
     }
 
     my %create_args = (
+        Type            => $ARGS{'Type'} || 'ticket',
         Queue           => $ARGS{'Queue'},
         Owner           => $ARGS{'Owner'},
         InitialPriority => $ARGS{'InitialPriority'},
@@ -277,36 +292,54 @@ 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"};
         }
     }
-    my ( $id, $Trans, $ErrMsg ) = $Ticket->Create(%create_args);
-    unless ( $id && $Trans ) {
-        Abort($ErrMsg);
+
+    # 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;
     }
-    my @linktypes = qw( DependsOn MemberOf RefersTo );
+    $create_args{'DependsOn'} = \@dependson;
 
-    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{"DependsOn-new"} ) ) {
+       push @dependedonby, $luri;
+    }
+    $create_args{'DependedOnBy'} = \@dependedonby;
 
-        foreach my $luri ( split ( / /, $ARGS{"$linktype-new"} ) ) {
-            my ( $val, $msg ) = $Ticket->AddLink(
-                Base => $luri,
-                Type => $linktype
-            );
+    foreach my $luri ( split ( / /, $ARGS{"new-MemberOf"} ) ) {
+       $luri =~ s/\s*$//;    # Strip trailing whitespace
+       push @parents, $luri;
+    }
+    $create_args{'Parents'} = \@parents;
 
-            push ( @Actions, $msg ) unless ($val);
-        }
+    foreach my $luri ( split ( / /, $ARGS{"MemberOf-new"} ) ) {
+       push @children, $luri;
+    }
+    $create_args{'Children'} = \@children;
+
+    foreach my $luri ( split ( / /, $ARGS{"new-RefersTo"} ) ) {
+       $luri =~ s/\s*$//;    # Strip trailing whitespace
+       push @refersto, $luri;
+    }
+    $create_args{'RefersTo'} = \@refersto;
+
+    foreach my $luri ( split ( / /, $ARGS{"RefersTo-new"} ) ) {
+       push @referredtoby, $luri;
+    }
+    $create_args{'ReferredToBy'} = \@referredtoby;
+
+    my ( $id, $Trans, $ErrMsg ) = $Ticket->Create(%create_args);
+    unless ( $id && $Trans ) {
+        Abort($ErrMsg);
     }
 
     push ( @Actions, split("\n", $ErrMsg) );
@@ -365,7 +398,9 @@ sub ProcessUpdateMessage {
     );
 
     #Make the update content have no 'weird' newlines in it
-    if ( $args{ARGSRef}->{'UpdateContent'} ) {
+    if ( $args{ARGSRef}->{'UpdateTimeWorked'} ||
+        $args{ARGSRef}->{'UpdateContent'} ||
+        $args{ARGSRef}->{'UpdateAttachments'}) {
 
         if (
             $args{ARGSRef}->{'UpdateSubject'} eq $args{'TicketObj'}->Subject() )
@@ -385,7 +420,7 @@ sub ProcessUpdateMessage {
 
         ## TODO: Implement public comments
         if ( $args{ARGSRef}->{'UpdateType'} =~ /^(private|public)$/ ) {
-            my ( $Transaction, $Description ) = $args{TicketObj}->Comment(
+            my ( $Transaction, $Description, $Object ) = $args{TicketObj}->Comment(
                 CcMessageTo  => $args{ARGSRef}->{'UpdateCc'},
                 BccMessageTo => $args{ARGSRef}->{'UpdateBcc'},
                 MIMEObj      => $Message,
@@ -394,7 +429,7 @@ sub ProcessUpdateMessage {
             push ( @{ $args{Actions} }, $Description );
         }
         elsif ( $args{ARGSRef}->{'UpdateType'} eq 'response' ) {
-            my ( $Transaction, $Description ) = $args{TicketObj}->Correspond(
+            my ( $Transaction, $Description, $Object ) = $args{TicketObj}->Correspond(
                 CcMessageTo  => $args{ARGSRef}->{'UpdateCc'},
                 BccMessageTo => $args{ARGSRef}->{'UpdateBcc'},
                 MIMEObj      => $Message,
@@ -433,7 +468,8 @@ 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
@@ -449,6 +485,7 @@ sub MakeMIMEEntity {
             Subject => $args{'Subject'} || "",
             From    => $args{'From'},
             Cc      => $args{'Cc'},
+            Charset => 'utf8',
             Data    => [ $args{'Body'} ]
         );
     }
@@ -463,7 +500,14 @@ sub MakeMIMEEntity {
 
     #foreach my $filehandle (@filenames) {
 
-    my ( $fh, $temp_file ) = tempfile();
+    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;
+    }
 
     binmode $fh;    #thank you, windows
     my ($buffer);
@@ -481,7 +525,7 @@ sub MakeMIMEEntity {
 
     $Message->attach(
         Path     => $temp_file,
-        Filename => $filename,
+        Filename => Encode::decode_utf8($filename),
         Type     => $uploadinfo->{'Content-Type'},
     );
     close($fh);
@@ -594,13 +638,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'},
         );
-
     }
 
     # }}}
@@ -780,17 +824,13 @@ sub ProcessACLChanges {
 
             my $obj;
 
-            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') {
+             if ($object_type eq 'RT::System') {
                 $obj = $RT::System;
+           } elsif ($RT::ACE::OBJECT_TYPES{$object_type}) {
+                $obj = $object_type->new($session{'CurrentUser'});
+                $obj->Load($object_id);      
             } else {
-                push (@results, loc("System Error").
+                push (@results, loc("System Error"). ': '.
                                 loc("Rights could not be granted for [_1]", $object_type));
                 next;
             }
@@ -813,17 +853,14 @@ sub ProcessACLChanges {
             next unless ($right);
             my $obj;
 
-            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') {
+             if ($object_type eq 'RT::System') {
                 $obj = $RT::System;
+           } elsif ($RT::ACE::OBJECT_TYPES{$object_type}) {
+                $obj = $object_type->new($session{'CurrentUser'});
+                $obj->Load($object_id);      
             } else {
-                push (@results, loc("System Error").
+               die;
+                push (@results, loc("System Error"). ': '.
                                 loc("Rights could not be revoked for [_1]", $object_type));
                 next;
             }
@@ -859,52 +896,12 @@ sub UpdateRecordObject {
         @_
     );
 
-    my (@results);
+    my $Object = $args{'Object'};
+    my @results = $Object->Update(AttributesRef => $args{'AttributesRef'},
+                                 ARGSRef       => $args{'ARGSRef'},
+                  AttributePrefix => $args{'AttributePrefix'}
+                                 );
 
-    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);
 }
 
@@ -953,6 +950,17 @@ 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);
 }
 
@@ -985,6 +993,7 @@ sub ProcessTicketBasics {
       TimeEstimated
       TimeWorked
       TimeLeft
+      Type
       Status
       Queue
     );
@@ -997,6 +1006,8 @@ sub ProcessTicketBasics {
         }
     }
 
+    $ARGSRef->{'Status'} ||= $TicketObj->Status;
+    
     my @results = UpdateRecordObject(
         AttributesRef => \@attribs,
         Object        => $TicketObj,
@@ -1050,8 +1061,11 @@ sub ProcessTicketCustomFieldUpdates {
 
     # For each of those tickets
     foreach my $tick ( keys %custom_fields_to_mod ) {
-        my $Ticket = RT::Ticket->new( $session{'CurrentUser'} );
-        $Ticket->Load($tick);
+        my $Ticket = $args{'TicketObj'};
+       if (!$Ticket or $Ticket->id != $tick) {
+           $Ticket = RT::Ticket->new( $session{'CurrentUser'} );
+           $Ticket->Load($tick);
+       }
 
         # For each custom field  
         foreach my $cf ( keys %{ $custom_fields_to_mod{$tick} } ) {
@@ -1074,10 +1088,15 @@ sub ProcessTicketCustomFieldUpdates {
                 my @values =
                   ( ref( $ARGSRef->{$arg} ) eq 'ARRAY' ) 
                   ? @{ $ARGSRef->{$arg} }
-                  : ( $ARGSRef->{$arg} );
+                  : split /\n/, $ARGSRef->{$arg} ;
+
+               #for poor windows boxen that pass in "\r\n"
+               local $/ = "\r";
+               chomp @values;
+
                 if ( ( $arg =~ /-AddValue$/ ) || ( $arg =~ /-Value$/ ) ) {
                     foreach my $value (@values) {
-                        next unless ($value);
+                        next unless length($value);
                         my ( $val, $msg ) = $Ticket->AddCustomFieldValue(
                             Field => $cf,
                             Value => $value
@@ -1087,7 +1106,7 @@ sub ProcessTicketCustomFieldUpdates {
                 }
                 elsif ( $arg =~ /-DeleteValues$/ ) {
                     foreach my $value (@values) {
-                        next unless ($value);
+                        next unless length($value);
                         my ( $val, $msg ) = $Ticket->DeleteCustomFieldValue(
                             Field => $cf,
                             Value => $value
@@ -1100,7 +1119,7 @@ sub ProcessTicketCustomFieldUpdates {
 
                     my %values_hash;
                     foreach my $value (@values) {
-                        next unless ($value);
+                        next unless length($value);
 
                         # build up a hash of values that the new set has
                         $values_hash{$value} = 1;
@@ -1185,7 +1204,7 @@ sub ProcessTicketWatchers {
     foreach my $key ( keys %$ARGSRef ) {
 
         # {{{ Delete deletable watchers
-        if ( ( $key =~ /^Ticket-DelWatcher-Type-(.*)-Principal-(\d+)$/ )  ) {
+        if ( ( $key =~ /^Ticket-DeleteWatcher-Type-(.*)-Principal-(\d+)$/ )  ) {
             my ( $code, $msg ) = 
                 $Ticket->DeleteWatcher(PrincipalId => $2,
                                        Type => $1);
@@ -1193,8 +1212,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( Type => $ARGSRef->{$key}, PrincipalId => $1 );
+        elsif ( $key =~ /^Delete(Requestor|Cc|AdminCc)$/ ) {       
+            my ( $code, $msg ) = $Ticket->DeleteWatcher( Email => $ARGSRef->{$key}, Type => $1 );
             push @results, $msg;
         }
 
@@ -1314,6 +1333,29 @@ 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.
@@ -1325,7 +1367,7 @@ sub ProcessTicketLinks {
 
             push @results,
               "Trying to delete: Base: $base Target: $target  Type $type";
-            my ( $val, $msg ) = $Ticket->DeleteLink( Base   => $base,
+            my ( $val, $msg ) = $Record->DeleteLink( Base   => $base,
                                                      Type   => $type,
                                                      Target => $target );
 
@@ -1338,18 +1380,18 @@ sub ProcessTicketLinks {
     my @linktypes = qw( DependsOn MemberOf RefersTo );
 
     foreach my $linktype (@linktypes) {
-        if ( $ARGSRef->{ $Ticket->Id . "-$linktype" } ) {
-            for my $luri ( split ( / /, $ARGSRef->{ $Ticket->Id . "-$linktype" } ) ) {
+        if ( $ARGSRef->{ $Record->Id . "-$linktype" } ) {
+            for my $luri ( split ( / /, $ARGSRef->{ $Record->Id . "-$linktype" } ) ) {
                 $luri =~ s/\s*$//;    # Strip trailing whitespace
-                my ( $val, $msg ) = $Ticket->AddLink( Target => $luri,
+                my ( $val, $msg ) = $Record->AddLink( Target => $luri,
                                                       Type   => $linktype );
                 push @results, $msg;
             }
         }
-        if ( $ARGSRef->{ "$linktype-" . $Ticket->Id } ) {
+        if ( $ARGSRef->{ "$linktype-" . $Record->Id } ) {
 
-            for my $luri ( split ( / /, $ARGSRef->{ "$linktype-" . $Ticket->Id } ) ) {
-                my ( $val, $msg ) = $Ticket->AddLink( Base => $luri,
+            for my $luri ( split ( / /, $ARGSRef->{ "$linktype-" . $Record->Id } ) ) {
+                my ( $val, $msg ) = $Record->AddLink( Base => $luri,
                                                       Type => $linktype );
 
                 push @results, $msg;
@@ -1357,18 +1399,9 @@ sub ProcessTicketLinks {
         } 
     }
 
-    #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";
index 962c378..d9595fb 100644 (file)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -61,7 +83,7 @@ sub _Init {
 
 
 
-=item Create PARAMHASH
+=head2 Create PARAMHASH
 
 Create takes a hash of values and creates a row in the database:
 
@@ -98,7 +120,7 @@ sub Create {
 
 
 
-=item id
+=head2 id
 
 Returns the current value of id. 
 (In the database, id is stored as int(11).)
@@ -107,14 +129,14 @@ Returns the current value of id.
 =cut
 
 
-=item Base
+=head2 Base
 
 Returns the current value of Base. 
 (In the database, Base is stored as varchar(240).)
 
 
 
-=item SetBase VALUE
+=head2 SetBase VALUE
 
 
 Set Base to VALUE. 
@@ -125,14 +147,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Target
+=head2 Target
 
 Returns the current value of Target. 
 (In the database, Target is stored as varchar(240).)
 
 
 
-=item SetTarget VALUE
+=head2 SetTarget VALUE
 
 
 Set Target to VALUE. 
@@ -143,14 +165,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Type
+=head2 Type
 
 Returns the current value of Type. 
 (In the database, Type is stored as varchar(20).)
 
 
 
-=item SetType VALUE
+=head2 SetType VALUE
 
 
 Set Type to VALUE. 
@@ -161,14 +183,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item LocalTarget
+=head2 LocalTarget
 
 Returns the current value of LocalTarget. 
 (In the database, LocalTarget is stored as int(11).)
 
 
 
-=item SetLocalTarget VALUE
+=head2 SetLocalTarget VALUE
 
 
 Set LocalTarget to VALUE. 
@@ -179,14 +201,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item LocalBase
+=head2 LocalBase
 
 Returns the current value of LocalBase. 
 (In the database, LocalBase is stored as int(11).)
 
 
 
-=item SetLocalBase VALUE
+=head2 SetLocalBase VALUE
 
 
 Set LocalBase to VALUE. 
@@ -197,7 +219,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item LastUpdatedBy
+=head2 LastUpdatedBy
 
 Returns the current value of LastUpdatedBy. 
 (In the database, LastUpdatedBy is stored as int(11).)
@@ -206,7 +228,7 @@ Returns the current value of LastUpdatedBy.
 =cut
 
 
-=item LastUpdated
+=head2 LastUpdated
 
 Returns the current value of LastUpdated. 
 (In the database, LastUpdated is stored as datetime.)
@@ -215,7 +237,7 @@ Returns the current value of LastUpdated.
 =cut
 
 
-=item Creator
+=head2 Creator
 
 Returns the current value of Creator. 
 (In the database, Creator is stored as int(11).)
@@ -224,7 +246,7 @@ Returns the current value of Creator.
 =cut
 
 
-=item Created
+=head2 Created
 
 Returns the current value of Created. 
 (In the database, Created is stored as datetime.)
@@ -234,7 +256,7 @@ Returns the current value of Created.
 
 
 
-sub _ClassAccessible {
+sub _CoreAccessible {
     {
      
         id =>
index 7a1773a..07dcae7 100644 (file)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -64,7 +86,7 @@ sub _Init {
 }
 
 
-=item NewItem
+=head2 NewItem
 
 Returns an empty new RT::Link item
 
index b362c9f..03bb2de 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -61,7 +83,7 @@ sub _Init {
 
 
 
-=item Create PARAMHASH
+=head2 Create PARAMHASH
 
 Create takes a hash of values and creates a row in the database:
 
@@ -107,7 +129,7 @@ sub Create {
 
 
 
-=item id
+=head2 id
 
 Returns the current value of id. 
 (In the database, id is stored as int(11).)
@@ -116,14 +138,14 @@ Returns the current value of id.
 =cut
 
 
-=item Name
+=head2 Name
 
 Returns the current value of Name. 
 (In the database, Name is stored as varchar(200).)
 
 
 
-=item SetName VALUE
+=head2 SetName VALUE
 
 
 Set Name to VALUE. 
@@ -134,14 +156,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Description
+=head2 Description
 
 Returns the current value of Description. 
 (In the database, Description is stored as varchar(255).)
 
 
 
-=item SetDescription VALUE
+=head2 SetDescription VALUE
 
 
 Set Description to VALUE. 
@@ -152,14 +174,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item CorrespondAddress
+=head2 CorrespondAddress
 
 Returns the current value of CorrespondAddress. 
 (In the database, CorrespondAddress is stored as varchar(120).)
 
 
 
-=item SetCorrespondAddress VALUE
+=head2 SetCorrespondAddress VALUE
 
 
 Set CorrespondAddress to VALUE. 
@@ -170,14 +192,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item CommentAddress
+=head2 CommentAddress
 
 Returns the current value of CommentAddress. 
 (In the database, CommentAddress is stored as varchar(120).)
 
 
 
-=item SetCommentAddress VALUE
+=head2 SetCommentAddress VALUE
 
 
 Set CommentAddress to VALUE. 
@@ -188,14 +210,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item InitialPriority
+=head2 InitialPriority
 
 Returns the current value of InitialPriority. 
 (In the database, InitialPriority is stored as int(11).)
 
 
 
-=item SetInitialPriority VALUE
+=head2 SetInitialPriority VALUE
 
 
 Set InitialPriority to VALUE. 
@@ -206,14 +228,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item FinalPriority
+=head2 FinalPriority
 
 Returns the current value of FinalPriority. 
 (In the database, FinalPriority is stored as int(11).)
 
 
 
-=item SetFinalPriority VALUE
+=head2 SetFinalPriority VALUE
 
 
 Set FinalPriority to VALUE. 
@@ -224,14 +246,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item DefaultDueIn
+=head2 DefaultDueIn
 
 Returns the current value of DefaultDueIn. 
 (In the database, DefaultDueIn is stored as int(11).)
 
 
 
-=item SetDefaultDueIn VALUE
+=head2 SetDefaultDueIn VALUE
 
 
 Set DefaultDueIn to VALUE. 
@@ -242,7 +264,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Creator
+=head2 Creator
 
 Returns the current value of Creator. 
 (In the database, Creator is stored as int(11).)
@@ -251,7 +273,7 @@ Returns the current value of Creator.
 =cut
 
 
-=item Created
+=head2 Created
 
 Returns the current value of Created. 
 (In the database, Created is stored as datetime.)
@@ -260,7 +282,7 @@ Returns the current value of Created.
 =cut
 
 
-=item LastUpdatedBy
+=head2 LastUpdatedBy
 
 Returns the current value of LastUpdatedBy. 
 (In the database, LastUpdatedBy is stored as int(11).)
@@ -269,7 +291,7 @@ Returns the current value of LastUpdatedBy.
 =cut
 
 
-=item LastUpdated
+=head2 LastUpdated
 
 Returns the current value of LastUpdated. 
 (In the database, LastUpdated is stored as datetime.)
@@ -278,14 +300,14 @@ Returns the current value of LastUpdated.
 =cut
 
 
-=item Disabled
+=head2 Disabled
 
 Returns the current value of Disabled. 
 (In the database, Disabled is stored as smallint(6).)
 
 
 
-=item SetDisabled VALUE
+=head2 SetDisabled VALUE
 
 
 Set Disabled to VALUE. 
@@ -297,7 +319,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 
 
 
-sub _ClassAccessible {
+sub _CoreAccessible {
     {
      
         id =>
index 60aec90..e1be353 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -64,7 +86,7 @@ sub _Init {
 }
 
 
-=item NewItem
+=head2 NewItem
 
 Returns an empty new RT::Queue item
 
index 6962221..57a5ea7 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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:
 # 
-# END LICENSE BLOCK
+# (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.)
+# 
+# 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
 =head1 NAME
 
   RT::Record - Base class for RT record objects
@@ -44,12 +66,12 @@ ok (require RT::Record);
 package RT::Record;
 use RT::Date;
 use RT::User;
-
+use RT::Attributes;
 use RT::Base;
 use DBIx::SearchBuilder::Record::Cachable;
 
 use strict;
-use vars qw/@ISA/;
+use vars qw/@ISA $_TABLE_ATTR/;
 
 @ISA = qw(RT::Base);
 
@@ -64,8 +86,8 @@ if ($RT::DontCacheSearchBuilderRecords ) {
 
 sub _Init {
     my $self = shift;
+    $self->_BuildTableAttributes unless ($_TABLE_ATTR->{ref($self)});
     $self->CurrentUser(@_);
-
 }
 
 # }}}
@@ -85,6 +107,102 @@ sub _PrimaryKeys {
 
 # }}}
 
+=head2 Attributes
+
+Return this object's attributes as an RT::Attributes object
+
+=cut
+
+sub Attributes {
+    my $self = shift;
+    
+    unless ($self->{'attributes'}) {
+        $self->{'attributes'} = RT::Attributes->new($self->CurrentUser);     
+       $self->{'attributes'}->LimitToObject($self); 
+    }
+    return ($self->{'attributes'}); 
+
+}
+
+
+=head2 AddAttribute { Name, Description, Content }
+
+Adds a new attribute for this object.
+
+=cut
+
+sub AddAttribute {
+    my $self = shift;
+    my %args = ( Name        => undef,
+                 Description => undef,
+                 Content     => undef,
+                 @_ );
+
+    my $attr = RT::Attribute->new( $self->CurrentUser );
+    my ( $id, $msg ) = $attr->Create( 
+                                      Object    => $self,
+                                      Name        => $args{'Name'},
+                                      Description => $args{'Description'},
+                                      Content     => $args{'Content'} );
+
+    $self->Attributes->RedoSearch;
+    
+    return ($id, $msg);
+}
+
+
+=head2 SetAttribute { Name, Description, Content }
+
+Like AddAttribute, but replaces all existing attributes with the same Name.
+
+=cut
+
+sub SetAttribute {
+    my $self = shift;
+    my %args = ( Name        => undef,
+                 Description => undef,
+                 Content     => undef,
+                 @_ );
+
+    my @AttributeObjs = $self->Attributes->Named( $args{'Name'} )
+        or return $self->AddAttribute( %args );
+
+    my $AttributeObj = pop( @AttributeObjs );
+    $_->Delete foreach @AttributeObjs;
+
+    $AttributeObj->SetDescription( $args{'Description'} );
+    $AttributeObj->SetContent( $args{'Content'} );
+
+    $self->Attributes->RedoSearch;
+    return 1;
+}
+
+=head2 DeleteAttribute NAME
+
+Deletes all attributes with the matching name for this object.
+
+=cut
+
+sub DeleteAttribute {
+    my $self = shift;
+    my $name = shift;
+    return $self->Attributes->DeleteEntry( Name => $name );
+}
+
+=head2 FirstAttribute NAME
+
+Returns the value of the first attribute with the matching name
+for this object, or C<undef> if no such attributes exist.
+
+=cut
+
+sub FirstAttribute {
+    my $self = shift;
+    my $name = shift;
+    return ($self->Attributes->Named( $name ))[0];
+}
+
+
 # {{{ sub _Handle 
 sub _Handle {
     my $self = shift;
@@ -195,6 +313,9 @@ sub LoadByCols {
     my $self = shift;
     my %hash = (@_);
 
+    # We don't want to hang onto this
+    delete $self->{'attributes'};
+
     # If this database is case sensitive we need to uncase objects for
     # explicit loading
     if ( $self->_Handle->CaseSensitive ) {
@@ -211,7 +332,10 @@ sub LoadByCols {
                 $newhash{$key} = $hash{$key};
             }
             else {
-                $newhash{ "lower(" . $key . ")" } = lc( $hash{$key} );
+                my ($op, $val);
+                ($key, $op, $val) = $self->_Handle->_MakeClauseCaseInsensitive($key, '=', $hash{$key});
+                $newhash{$key}->{operator} = $op;
+                $newhash{$key}->{value} = $val;
             }
         }
 
@@ -410,10 +534,47 @@ sub LastUpdatedByObj {
 
 # }}}
 
+# {{{ sub URI 
+
+=head2 URI
+
+Returns this record's URI
+
+=cut
+
+sub URI {
+    my $self = shift;
+    my $uri = RT::URI::fsck_com_rt->new($self->CurrentUser);
+    return($uri->URIForObject($self));
+}
+
+# }}}
+
+
+
+
+=head2 SQLType attribute
+
+return the SQL type for the attribute 'attribute' as stored in _ClassAccessible
+
+=cut
+
+sub SQLType {
+    my $self = shift;
+    my $field = shift;
+
+    return ($self->_Accessible($field, 'type'));
+
+
+}
 
 require Encode::compat if $] < 5.007001;
 require Encode;
 
+
+
+
 sub __Value {
     my $self  = shift;
     my $field = shift;
@@ -436,17 +597,674 @@ sub __Value {
 sub _CacheConfig {
   {
      'cache_p'        => 1,
-     'fast_update_p'  => 1,
      'cache_for_sec'  => 30,
   }
 }
 
-=head2 _DecodeUTF8
 
- When passed a string will "decode" it int a proper UTF-8 string
+
+sub _BuildTableAttributes {
+    my $self = shift;
+
+    my $attributes;
+    if ( UNIVERSAL::can( $self, '_CoreAccessible' ) ) {
+       $attributes = $self->_CoreAccessible();
+    } elsif ( UNIVERSAL::can( $self, '_ClassAccessible' ) ) {
+       $attributes = $self->_ClassAccessible();
+
+    }
+
+    foreach my $column (%$attributes) {
+        foreach my $attr ( %{ $attributes->{$column} } ) {
+            $_TABLE_ATTR->{ref($self)}->{$column}->{$attr} = $attributes->{$column}->{$attr};
+        }
+    }
+    if ( UNIVERSAL::can( $self, '_OverlayAccessible' ) ) {
+        $attributes = $self->_OverlayAccessible();
+
+        foreach my $column (%$attributes) {
+            foreach my $attr ( %{ $attributes->{$column} } ) {
+                $_TABLE_ATTR->{ref($self)}->{$column}->{$attr} = $attributes->{$column}->{$attr};
+            }
+        }
+    }
+    if ( UNIVERSAL::can( $self, '_VendorAccessible' ) ) {
+        $attributes = $self->_VendorAccessible();
+
+        foreach my $column (%$attributes) {
+            foreach my $attr ( %{ $attributes->{$column} } ) {
+                $_TABLE_ATTR->{ref($self)}->{$column}->{$attr} = $attributes->{$column}->{$attr};
+            }
+        }
+    }
+    if ( UNIVERSAL::can( $self, '_LocalAccessible' ) ) {
+        $attributes = $self->_LocalAccessible();
+
+        foreach my $column (%$attributes) {
+            foreach my $attr ( %{ $attributes->{$column} } ) {
+                $_TABLE_ATTR->{ref($self)}->{$column}->{$attr} = $attributes->{$column}->{$attr};
+            }
+        }
+    }
+
+}
+
+
+=head2 _ClassAccessible 
+
+Overrides the "core" _ClassAccessible using $_TABLE_ATTR. Behaves identical to the version in
+DBIx::SearchBuilder::Record
+
+=cut
+
+sub _ClassAccessible {
+    my $self = shift;
+    return $_TABLE_ATTR->{ref($self)};
+}
+
+=head2 _Accessible COLUMN ATTRIBUTE
+
+returns the value of ATTRIBUTE for COLUMN
+
+
+=cut 
+
+sub _Accessible  {
+  my $self = shift;
+  my $column = shift;
+  my $attribute = lc(shift);
+  return 0 unless defined ($_TABLE_ATTR->{ref($self)}->{$column});
+  return $_TABLE_ATTR->{ref($self)}->{$column}->{$attribute} || 0;
+
+}
+
+=head2 _EncodeLOB BODY MIME_TYPE
+
+Takes a potentially large attachment. Returns (ContentEncoding, EncodedBody) based on system configuration and selected database
+
+=cut
+
+sub _EncodeLOB {
+        my $self = shift;
+        my $Body = shift;
+        my $MIMEType = shift;
+
+        my $ContentEncoding = 'none';
+
+        #get the max attachment length from RT
+        my $MaxSize = $RT::MaxAttachmentSize;
+
+        #if the current attachment contains nulls and the
+        #database doesn't support embedded nulls
+
+        if ( $RT::AlwaysUseBase64 or
+             ( !$RT::Handle->BinarySafeBLOBs ) && ( $Body =~ /\x00/ ) ) {
+
+            # set a flag telling us to mimencode the attachment
+            $ContentEncoding = 'base64';
+
+            #cut the max attchment size by 25% (for mime-encoding overhead.
+            $RT::Logger->debug("Max size is $MaxSize\n");
+            $MaxSize = $MaxSize * 3 / 4;
+        # Some databases (postgres) can't handle non-utf8 data
+        } elsif (    !$RT::Handle->BinarySafeBLOBs
+                  && $MIMEType !~ /text\/plain/gi
+                  && !Encode::is_utf8( $Body, 1 ) ) {
+              $ContentEncoding = 'quoted-printable';
+        }
+
+        #if the attachment is larger than the maximum size
+        if ( ($MaxSize) and ( $MaxSize < length($Body) ) ) {
+
+            # if we're supposed to truncate large attachments
+            if ($RT::TruncateLongAttachments) {
+
+                # truncate the attachment to that length.
+                $Body = substr( $Body, 0, $MaxSize );
+
+            }
+
+            # elsif we're supposed to drop large attachments on the floor,
+            elsif ($RT::DropLongAttachments) {
+
+                # drop the attachment on the floor
+                $RT::Logger->info( "$self: Dropped an attachment of size " . length($Body) . "\n" . "It started: " . substr( $Body, 0, 60 ) . "\n" );
+                return ("none", "Large attachment dropped" );
+            }
+        }
+
+        # if we need to mimencode the attachment
+        if ( $ContentEncoding eq 'base64' ) {
+
+            # base64 encode the attachment
+            Encode::_utf8_off($Body);
+            $Body = MIME::Base64::encode_base64($Body);
+
+        } elsif ($ContentEncoding eq 'quoted-printable') {
+            Encode::_utf8_off($Body);
+            $Body = MIME::QuotedPrint::encode($Body);
+        }
+
+
+        return ($ContentEncoding, $Body);
+
+}
+
+
+# {{{ LINKDIRMAP
+# A helper table for links mapping to make it easier
+# to build and parse links between tickets
+
+use vars '%LINKDIRMAP';
+
+%LINKDIRMAP = (
+    MemberOf => { Base => 'MemberOf',
+                  Target => 'HasMember', },
+    RefersTo => { Base => 'RefersTo',
+                Target => 'ReferredToBy', },
+    DependsOn => { Base => 'DependsOn',
+                   Target => 'DependedOnBy', },
+    MergedInto => { Base => 'MergedInto',
+                   Target => 'MergedInto', },
+
+);
+
+sub Update {
+    my $self = shift;
+
+    my %args = (
+        ARGSRef         => undef,
+        AttributesRef   => undef,
+        AttributePrefix => undef,
+        @_
+    );
+
+    my $attributes = $args{'AttributesRef'};
+    my $ARGSRef    = $args{'ARGSRef'};
+    my @results;
+
+    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 Queue is 'General', we want to resolve the queue name for
+        # the object.
+
+        # This is in an eval block because $object might not exist.
+        # and might not have a Name method. But "can" won't find autoloaded
+        # items. If it fails, we don't care
+        eval {
+            my $object = $attribute . "Obj";
+            next if ($self->$object->Name eq $value);
+        };
+        next if ( $value eq $self->$attribute() );
+        my $method = "Set$attribute";
+        my ( $code, $msg ) = $self->$method($value);
+
+        my ($prefix) = ref($self) =~ /RT::(\w+)/;
+        push @results,
+          $self->loc( "$prefix [_1]", $self->id ) . ': '
+          . $self->loc($attribute) . ': '
+          . $self->CurrentUser->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;
+}
+
+# {{{ Routines dealing with Links between tickets
+
+# {{{ Link Collections
+
+# {{{ sub Members
+
+=head2 Members
+
+  This returns an RT::Links object which references all the tickets 
+which are 'MembersOf' this ticket
 
 =cut
 
+sub Members {
+    my $self = shift;
+    return ( $self->_Links( 'Target', 'MemberOf' ) );
+}
+
+# }}}
+
+# {{{ sub MemberOf
+
+=head2 MemberOf
+
+  This returns an RT::Links object which references all the tickets that this
+ticket is a 'MemberOf'
+
+=cut
+
+sub MemberOf {
+    my $self = shift;
+    return ( $self->_Links( 'Base', 'MemberOf' ) );
+}
+
+# }}}
+
+# {{{ RefersTo
+
+=head2 RefersTo
+
+  This returns an RT::Links object which shows all references for which this ticket is a base
+
+=cut
+
+sub RefersTo {
+    my $self = shift;
+    return ( $self->_Links( 'Base', 'RefersTo' ) );
+}
+
+# }}}
+
+# {{{ ReferredToBy
+
+=head2 ReferredToBy
+
+  This returns an RT::Links object which shows all references for which this ticket is a target
+
+=cut
+
+sub ReferredToBy {
+    my $self = shift;
+    return ( $self->_Links( 'Target', 'RefersTo' ) );
+}
+
+# }}}
+
+# {{{ DependedOnBy
+
+=head2 DependedOnBy
+
+  This returns an RT::Links object which references all the tickets that depend on this one
+
+=cut
+
+sub DependedOnBy {
+    my $self = shift;
+    return ( $self->_Links( 'Target', 'DependsOn' ) );
+}
+
+# }}}
+
+
+
+=head2 HasUnresolvedDependencies
+
+  Takes a paramhash of Type (default to '__any').  Returns true if
+$self->UnresolvedDependencies returns an object with one or more members
+of that type.  Returns false otherwise
+
+
+=begin testing
+
+my $t1 = RT::Ticket->new($RT::SystemUser);
+my ($id, $trans, $msg) = $t1->Create(Subject => 'DepTest1', Queue => 'general');
+ok($id, "Created dep test 1 - $msg");
+
+my $t2 = RT::Ticket->new($RT::SystemUser);
+my ($id2, $trans, $msg2) = $t2->Create(Subject => 'DepTest2', Queue => 'general');
+ok($id2, "Created dep test 2 - $msg2");
+my $t3 = RT::Ticket->new($RT::SystemUser);
+my ($id3, $trans, $msg3) = $t3->Create(Subject => 'DepTest3', Queue => 'general', Type => 'approval');
+ok($id3, "Created dep test 3 - $msg3");
+my ($addid, $addmsg);
+ok (($addid, $addmsg) =$t1->AddLink( Type => 'DependsOn', Target => $t2->id));
+ok ($addid, $addmsg);
+ok (($addid, $addmsg) =$t1->AddLink( Type => 'DependsOn', Target => $t3->id));
+
+ok ($addid, $addmsg);
+ok ($t1->HasUnresolvedDependencies, "Ticket ".$t1->Id." has unresolved deps");
+ok (!$t1->HasUnresolvedDependencies( Type => 'blah' ), "Ticket ".$t1->Id." has no unresolved blahs");
+ok ($t1->HasUnresolvedDependencies( Type => 'approval' ), "Ticket ".$t1->Id." has unresolved approvals");
+ok (!$t2->HasUnresolvedDependencies, "Ticket ".$t2->Id." has no unresolved deps");
+;
+
+my ($rid, $rmsg)= $t1->Resolve();
+ok(!$rid, $rmsg);
+ok($t2->Resolve);
+($rid, $rmsg)= $t1->Resolve();
+ok(!$rid, $rmsg);
+ok($t3->Resolve);
+($rid, $rmsg)= $t1->Resolve();
+ok($rid, $rmsg);
+
+
+=end testing
+
+=cut
+
+sub HasUnresolvedDependencies {
+    my $self = shift;
+    my %args = (
+        Type   => undef,
+        @_
+    );
+
+    my $deps = $self->UnresolvedDependencies;
+
+    if ($args{Type}) {
+        $deps->Limit( FIELD => 'Type', 
+              OPERATOR => '=',
+              VALUE => $args{Type}); 
+    }
+    else {
+           $deps->IgnoreType;
+    }
+
+    if ($deps->Count > 0) {
+        return 1;
+    }
+    else {
+        return (undef);
+    }
+}
+
+
+# {{{ UnresolvedDependencies 
+
+=head2 UnresolvedDependencies
+
+Returns an RT::Tickets object of tickets which this ticket depends on
+and which have a status of new, open or stalled. (That list comes from
+RT::Queue->ActiveStatusArray
+
+=cut
+
+
+sub UnresolvedDependencies {
+    my $self = shift;
+    my $deps = RT::Tickets->new($self->CurrentUser);
+
+    my @live_statuses = RT::Queue->ActiveStatusArray();
+    foreach my $status (@live_statuses) {
+        $deps->LimitStatus(VALUE => $status);
+    }
+    $deps->LimitDependedOnBy($self->Id);
+
+    return($deps);
+
+}
+
+# }}}
+
+# {{{ AllDependedOnBy
+
+=head2 AllDependedOnBy
+
+Returns an array of RT::Ticket objects which (directly or indirectly)
+depends on this ticket; takes an optional 'Type' argument in the param
+hash, which will limit returned tickets to that type, as well as cause
+tickets with that type to serve as 'leaf' nodes that stops the recursive
+dependency search.
+
+=cut
+
+sub AllDependedOnBy {
+    my $self = shift;
+    my $dep = $self->DependedOnBy;
+    my %args = (
+        Type   => undef,
+       _found => {},
+       _top   => 1,
+        @_
+    );
+
+    while (my $link = $dep->Next()) {
+       next unless ($link->BaseURI->IsLocal());
+       next if $args{_found}{$link->BaseObj->Id};
+
+       if (!$args{Type}) {
+           $args{_found}{$link->BaseObj->Id} = $link->BaseObj;
+           $link->BaseObj->AllDependedOnBy( %args, _top => 0 );
+       }
+       elsif ($link->BaseObj->Type eq $args{Type}) {
+           $args{_found}{$link->BaseObj->Id} = $link->BaseObj;
+       }
+       else {
+           $link->BaseObj->AllDependedOnBy( %args, _top => 0 );
+       }
+    }
+
+    if ($args{_top}) {
+       return map { $args{_found}{$_} } sort keys %{$args{_found}};
+    }
+    else {
+       return 1;
+    }
+}
+
+# }}}
+
+# {{{ DependsOn
+
+=head2 DependsOn
+
+  This returns an RT::Links object which references all the tickets that this ticket depends on
+
+=cut
+
+sub DependsOn {
+    my $self = shift;
+    return ( $self->_Links( 'Base', 'DependsOn' ) );
+}
+
+# }}}
+
+
+
+
+# {{{ sub _Links 
+
+sub _Links {
+    my $self = shift;
+
+    #TODO: Field isn't the right thing here. but I ahave no idea what mnemonic ---
+    #tobias meant by $f
+    my $field = shift;
+    my $type  = shift || "";
+
+    unless ( $self->{"$field$type"} ) {
+        $self->{"$field$type"} = new RT::Links( $self->CurrentUser );
+            # at least to myself
+            $self->{"$field$type"}->Limit( FIELD => $field,
+                                           VALUE => $self->URI,
+                                           ENTRYAGGREGATOR => 'OR' );
+            $self->{"$field$type"}->Limit( FIELD => 'Type',
+                                           VALUE => $type )
+              if ($type);
+    }
+    return ( $self->{"$field$type"} );
+}
+
+# }}}
+
+# }}}
+
+# {{{ sub _AddLink
+
+=head2 _AddLink
+
+Takes a paramhash of Type and one of Base or Target. Adds that link to this ticket.
+
+
+=cut
+
+
+sub _AddLink {
+    my $self = shift;
+    my %args = ( Target => '',
+                 Base   => '',
+                 Type   => '',
+                 Silent => undef,
+                 @_ );
+
+
+    # Remote_link is the URI of the object that is not this ticket
+    my $remote_link;
+    my $direction;
+
+    if ( $args{'Base'} and $args{'Target'} ) {
+        $RT::Logger->debug(
+"$self tried to delete a link. both base and target were specified\n" );
+        return ( 0, $self->loc("Can't specifiy both base and target") );
+    }
+    elsif ( $args{'Base'} ) {
+        $args{'Target'} = $self->URI();
+       my $class = ref($self);
+        $remote_link    = $args{'Base'};
+        $direction      = 'Target';
+    }
+    elsif ( $args{'Target'} ) {
+        $args{'Base'} = $self->URI();
+       my $class = ref($self);
+        $remote_link  = $args{'Target'};
+        $direction    = 'Base';
+    }
+    else {
+        return ( 0, $self->loc('Either base or target must be specified') );
+    }
+
+    # {{{ Check if the link already exists - we don't want duplicates
+    use RT::Link;
+    my $old_link = RT::Link->new( $self->CurrentUser );
+    $old_link->LoadByParams( Base   => $args{'Base'},
+                             Type   => $args{'Type'},
+                             Target => $args{'Target'} );
+    if ( $old_link->Id ) {
+        $RT::Logger->debug("$self Somebody tried to duplicate a link");
+        return ( $old_link->id, $self->loc("Link already exists"), 0 );
+    }
+
+    # }}}
+
+
+    # Storing the link in the DB.
+    my $link = RT::Link->new( $self->CurrentUser );
+    my ($linkid, $linkmsg) = $link->Create( Target => $args{Target},
+                                  Base   => $args{Base},
+                                  Type   => $args{Type} );
+
+    unless ($linkid) {
+        $RT::Logger->error("Link could not be created: ".$linkmsg);
+        return ( 0, $self->loc("Link could not be created") );
+    }
+
+    my $TransString =
+      "Record $args{'Base'} $args{Type} record $args{'Target'}.";
+
+    return ( 1, $self->loc( "Link created ([_1])", $TransString ) );
+}
+
+# }}}
+
+# {{{ sub _DeleteLink 
+
+=head2 _DeleteLink
+
+Delete a link. takes a paramhash of Base, Target and Type.
+Either Base or Target must be null. The null value will 
+be replaced with this ticket\'s id
+
+=cut 
+
+sub _DeleteLink {
+    my $self = shift;
+    my %args = (
+        Base   => undef,
+        Target => undef,
+        Type   => undef,
+        @_
+    );
+
+    #we want one of base and target. we don't care which
+    #but we only want _one_
+
+    my $direction;
+    my $remote_link;
+
+    if ( $args{'Base'} and $args{'Target'} ) {
+        $RT::Logger->debug("$self ->_DeleteLink. got both Base and Target\n");
+        return ( 0, $self->loc("Can't specifiy both base and target") );
+    }
+    elsif ( $args{'Base'} ) {
+        $args{'Target'} = $self->URI();
+       $remote_link = $args{'Base'};
+       $direction = 'Target';
+    }
+    elsif ( $args{'Target'} ) {
+        $args{'Base'} = $self->URI();
+       $remote_link = $args{'Target'};
+        $direction='Base';
+    }
+    else {
+        $RT::Logger->debug("$self: Base or Target must be specified\n");
+        return ( 0, $self->loc('Either base or target must be specified') );
+    }
+
+    my $link = new RT::Link( $self->CurrentUser );
+    $RT::Logger->debug( "Trying to load link: " . $args{'Base'} . " " . $args{'Type'} . " " . $args{'Target'} . "\n" );
+
+
+    $link->LoadByParams( Base=> $args{'Base'}, Type=> $args{'Type'}, Target=>  $args{'Target'} );
+    #it's a real link. 
+    if ( $link->id ) {
+
+        my $linkid = $link->id;
+        $link->Delete();
+
+        my $TransString = "Record $args{'Base'} no longer $args{Type} record $args{'Target'}.";
+        return ( 1, $self->loc("Link deleted ([_1])", $TransString));
+    }
+
+    #if it's not a link we can find
+    else {
+        $RT::Logger->debug("Couldn't find that link\n");
+        return ( 0, $self->loc("Link not found") );
+    }
+}
+
+# }}}
+
 eval "require RT::Record_Vendor";
 die $@ if ($@ && $@ !~ qr{^Can't locate RT/Record_Vendor.pm});
 eval "require RT::Record_Local";
index a69dde0..1c414d8 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -65,7 +87,7 @@ sub _Init {
 
 
 
-=item Create PARAMHASH
+=head2 Create PARAMHASH
 
 Create takes a hash of values and creates a row in the database:
 
@@ -120,7 +142,7 @@ sub Create {
 
 
 
-=item id
+=head2 id
 
 Returns the current value of id. 
 (In the database, id is stored as int(11).)
@@ -129,14 +151,14 @@ Returns the current value of id.
 =cut
 
 
-=item Description
+=head2 Description
 
 Returns the current value of Description. 
 (In the database, Description is stored as varchar(255).)
 
 
 
-=item SetDescription VALUE
+=head2 SetDescription VALUE
 
 
 Set Description to VALUE. 
@@ -147,14 +169,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item ScripCondition
+=head2 ScripCondition
 
 Returns the current value of ScripCondition. 
 (In the database, ScripCondition is stored as int(11).)
 
 
 
-=item SetScripCondition VALUE
+=head2 SetScripCondition VALUE
 
 
 Set ScripCondition to VALUE. 
@@ -165,7 +187,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item ScripConditionObj
+=head2 ScripConditionObj
 
 Returns the ScripCondition Object which has the id returned by ScripCondition
 
@@ -179,14 +201,14 @@ sub ScripConditionObj {
        return($ScripCondition);
 }
 
-=item ScripAction
+=head2 ScripAction
 
 Returns the current value of ScripAction. 
 (In the database, ScripAction is stored as int(11).)
 
 
 
-=item SetScripAction VALUE
+=head2 SetScripAction VALUE
 
 
 Set ScripAction to VALUE. 
@@ -197,7 +219,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item ScripActionObj
+=head2 ScripActionObj
 
 Returns the ScripAction Object which has the id returned by ScripAction
 
@@ -211,14 +233,14 @@ sub ScripActionObj {
        return($ScripAction);
 }
 
-=item ConditionRules
+=head2 ConditionRules
 
 Returns the current value of ConditionRules. 
 (In the database, ConditionRules is stored as text.)
 
 
 
-=item SetConditionRules VALUE
+=head2 SetConditionRules VALUE
 
 
 Set ConditionRules to VALUE. 
@@ -229,14 +251,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item ActionRules
+=head2 ActionRules
 
 Returns the current value of ActionRules. 
 (In the database, ActionRules is stored as text.)
 
 
 
-=item SetActionRules VALUE
+=head2 SetActionRules VALUE
 
 
 Set ActionRules to VALUE. 
@@ -247,14 +269,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item CustomIsApplicableCode
+=head2 CustomIsApplicableCode
 
 Returns the current value of CustomIsApplicableCode. 
 (In the database, CustomIsApplicableCode is stored as text.)
 
 
 
-=item SetCustomIsApplicableCode VALUE
+=head2 SetCustomIsApplicableCode VALUE
 
 
 Set CustomIsApplicableCode to VALUE. 
@@ -265,14 +287,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item CustomPrepareCode
+=head2 CustomPrepareCode
 
 Returns the current value of CustomPrepareCode. 
 (In the database, CustomPrepareCode is stored as text.)
 
 
 
-=item SetCustomPrepareCode VALUE
+=head2 SetCustomPrepareCode VALUE
 
 
 Set CustomPrepareCode to VALUE. 
@@ -283,14 +305,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item CustomCommitCode
+=head2 CustomCommitCode
 
 Returns the current value of CustomCommitCode. 
 (In the database, CustomCommitCode is stored as text.)
 
 
 
-=item SetCustomCommitCode VALUE
+=head2 SetCustomCommitCode VALUE
 
 
 Set CustomCommitCode to VALUE. 
@@ -301,14 +323,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Stage
+=head2 Stage
 
 Returns the current value of Stage. 
 (In the database, Stage is stored as varchar(32).)
 
 
 
-=item SetStage VALUE
+=head2 SetStage VALUE
 
 
 Set Stage to VALUE. 
@@ -319,14 +341,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Queue
+=head2 Queue
 
 Returns the current value of Queue. 
 (In the database, Queue is stored as int(11).)
 
 
 
-=item SetQueue VALUE
+=head2 SetQueue VALUE
 
 
 Set Queue to VALUE. 
@@ -337,7 +359,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item QueueObj
+=head2 QueueObj
 
 Returns the Queue Object which has the id returned by Queue
 
@@ -351,14 +373,14 @@ sub QueueObj {
        return($Queue);
 }
 
-=item Template
+=head2 Template
 
 Returns the current value of Template. 
 (In the database, Template is stored as int(11).)
 
 
 
-=item SetTemplate VALUE
+=head2 SetTemplate VALUE
 
 
 Set Template to VALUE. 
@@ -369,7 +391,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item TemplateObj
+=head2 TemplateObj
 
 Returns the Template Object which has the id returned by Template
 
@@ -383,7 +405,7 @@ sub TemplateObj {
        return($Template);
 }
 
-=item Creator
+=head2 Creator
 
 Returns the current value of Creator. 
 (In the database, Creator is stored as int(11).)
@@ -392,7 +414,7 @@ Returns the current value of Creator.
 =cut
 
 
-=item Created
+=head2 Created
 
 Returns the current value of Created. 
 (In the database, Created is stored as datetime.)
@@ -401,7 +423,7 @@ Returns the current value of Created.
 =cut
 
 
-=item LastUpdatedBy
+=head2 LastUpdatedBy
 
 Returns the current value of LastUpdatedBy. 
 (In the database, LastUpdatedBy is stored as int(11).)
@@ -410,7 +432,7 @@ Returns the current value of LastUpdatedBy.
 =cut
 
 
-=item LastUpdated
+=head2 LastUpdated
 
 Returns the current value of LastUpdated. 
 (In the database, LastUpdated is stored as datetime.)
@@ -420,7 +442,7 @@ Returns the current value of LastUpdated.
 
 
 
-sub _ClassAccessible {
+sub _CoreAccessible {
     {
      
         id =>
index 26824df..e3d2a90 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -61,7 +83,7 @@ sub _Init {
 
 
 
-=item Create PARAMHASH
+=head2 Create PARAMHASH
 
 Create takes a hash of values and creates a row in the database:
 
@@ -95,7 +117,7 @@ sub Create {
 
 
 
-=item id
+=head2 id
 
 Returns the current value of id. 
 (In the database, id is stored as int(11).)
@@ -104,14 +126,14 @@ Returns the current value of id.
 =cut
 
 
-=item Name
+=head2 Name
 
 Returns the current value of Name. 
 (In the database, Name is stored as varchar(200).)
 
 
 
-=item SetName VALUE
+=head2 SetName VALUE
 
 
 Set Name to VALUE. 
@@ -122,14 +144,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Description
+=head2 Description
 
 Returns the current value of Description. 
 (In the database, Description is stored as varchar(255).)
 
 
 
-=item SetDescription VALUE
+=head2 SetDescription VALUE
 
 
 Set Description to VALUE. 
@@ -140,14 +162,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item ExecModule
+=head2 ExecModule
 
 Returns the current value of ExecModule. 
 (In the database, ExecModule is stored as varchar(60).)
 
 
 
-=item SetExecModule VALUE
+=head2 SetExecModule VALUE
 
 
 Set ExecModule to VALUE. 
@@ -158,14 +180,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Argument
+=head2 Argument
 
 Returns the current value of Argument. 
 (In the database, Argument is stored as varchar(255).)
 
 
 
-=item SetArgument VALUE
+=head2 SetArgument VALUE
 
 
 Set Argument to VALUE. 
@@ -176,7 +198,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Creator
+=head2 Creator
 
 Returns the current value of Creator. 
 (In the database, Creator is stored as int(11).)
@@ -185,7 +207,7 @@ Returns the current value of Creator.
 =cut
 
 
-=item Created
+=head2 Created
 
 Returns the current value of Created. 
 (In the database, Created is stored as datetime.)
@@ -194,7 +216,7 @@ Returns the current value of Created.
 =cut
 
 
-=item LastUpdatedBy
+=head2 LastUpdatedBy
 
 Returns the current value of LastUpdatedBy. 
 (In the database, LastUpdatedBy is stored as int(11).)
@@ -203,7 +225,7 @@ Returns the current value of LastUpdatedBy.
 =cut
 
 
-=item LastUpdated
+=head2 LastUpdated
 
 Returns the current value of LastUpdated. 
 (In the database, LastUpdated is stored as datetime.)
@@ -213,7 +235,7 @@ Returns the current value of LastUpdated.
 
 
 
-sub _ClassAccessible {
+sub _CoreAccessible {
     {
      
         id =>
index 614ff37..677fd85 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -64,7 +86,7 @@ sub _Init {
 }
 
 
-=item NewItem
+=head2 NewItem
 
 Returns an empty new RT::ScripAction item
 
index fe0aa2d..4e0398c 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -61,7 +83,7 @@ sub _Init {
 
 
 
-=item Create PARAMHASH
+=head2 Create PARAMHASH
 
 Create takes a hash of values and creates a row in the database:
 
@@ -98,7 +120,7 @@ sub Create {
 
 
 
-=item id
+=head2 id
 
 Returns the current value of id. 
 (In the database, id is stored as int(11).)
@@ -107,14 +129,14 @@ Returns the current value of id.
 =cut
 
 
-=item Name
+=head2 Name
 
 Returns the current value of Name. 
 (In the database, Name is stored as varchar(200).)
 
 
 
-=item SetName VALUE
+=head2 SetName VALUE
 
 
 Set Name to VALUE. 
@@ -125,14 +147,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Description
+=head2 Description
 
 Returns the current value of Description. 
 (In the database, Description is stored as varchar(255).)
 
 
 
-=item SetDescription VALUE
+=head2 SetDescription VALUE
 
 
 Set Description to VALUE. 
@@ -143,14 +165,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item ExecModule
+=head2 ExecModule
 
 Returns the current value of ExecModule. 
 (In the database, ExecModule is stored as varchar(60).)
 
 
 
-=item SetExecModule VALUE
+=head2 SetExecModule VALUE
 
 
 Set ExecModule to VALUE. 
@@ -161,14 +183,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Argument
+=head2 Argument
 
 Returns the current value of Argument. 
 (In the database, Argument is stored as varchar(255).)
 
 
 
-=item SetArgument VALUE
+=head2 SetArgument VALUE
 
 
 Set Argument to VALUE. 
@@ -179,14 +201,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item ApplicableTransTypes
+=head2 ApplicableTransTypes
 
 Returns the current value of ApplicableTransTypes. 
 (In the database, ApplicableTransTypes is stored as varchar(60).)
 
 
 
-=item SetApplicableTransTypes VALUE
+=head2 SetApplicableTransTypes VALUE
 
 
 Set ApplicableTransTypes to VALUE. 
@@ -197,7 +219,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Creator
+=head2 Creator
 
 Returns the current value of Creator. 
 (In the database, Creator is stored as int(11).)
@@ -206,7 +228,7 @@ Returns the current value of Creator.
 =cut
 
 
-=item Created
+=head2 Created
 
 Returns the current value of Created. 
 (In the database, Created is stored as datetime.)
@@ -215,7 +237,7 @@ Returns the current value of Created.
 =cut
 
 
-=item LastUpdatedBy
+=head2 LastUpdatedBy
 
 Returns the current value of LastUpdatedBy. 
 (In the database, LastUpdatedBy is stored as int(11).)
@@ -224,7 +246,7 @@ Returns the current value of LastUpdatedBy.
 =cut
 
 
-=item LastUpdated
+=head2 LastUpdated
 
 Returns the current value of LastUpdated. 
 (In the database, LastUpdated is stored as datetime.)
@@ -234,7 +256,7 @@ Returns the current value of LastUpdated.
 
 
 
-sub _ClassAccessible {
+sub _CoreAccessible {
     {
      
         id =>
index 34f788d..8daaea9 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -64,7 +86,7 @@ sub _Init {
 }
 
 
-=item NewItem
+=head2 NewItem
 
 Returns an empty new RT::ScripCondition item
 
index a394431..0ec2ad7 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -64,7 +86,7 @@ sub _Init {
 }
 
 
-=item NewItem
+=head2 NewItem
 
 Returns an empty new RT::Scrip item
 
index f73ea3e..c18a750 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -62,7 +84,7 @@ sub _Init {
 
 
 
-=item Create PARAMHASH
+=head2 Create PARAMHASH
 
 Create takes a hash of values and creates a row in the database:
 
@@ -105,7 +127,7 @@ sub Create {
 
 
 
-=item id
+=head2 id
 
 Returns the current value of id. 
 (In the database, id is stored as int(11).)
@@ -114,14 +136,14 @@ Returns the current value of id.
 =cut
 
 
-=item Queue
+=head2 Queue
 
 Returns the current value of Queue. 
 (In the database, Queue is stored as int(11).)
 
 
 
-=item SetQueue VALUE
+=head2 SetQueue VALUE
 
 
 Set Queue to VALUE. 
@@ -132,7 +154,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item QueueObj
+=head2 QueueObj
 
 Returns the Queue Object which has the id returned by Queue
 
@@ -146,14 +168,14 @@ sub QueueObj {
        return($Queue);
 }
 
-=item Name
+=head2 Name
 
 Returns the current value of Name. 
 (In the database, Name is stored as varchar(200).)
 
 
 
-=item SetName VALUE
+=head2 SetName VALUE
 
 
 Set Name to VALUE. 
@@ -164,14 +186,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Description
+=head2 Description
 
 Returns the current value of Description. 
 (In the database, Description is stored as varchar(255).)
 
 
 
-=item SetDescription VALUE
+=head2 SetDescription VALUE
 
 
 Set Description to VALUE. 
@@ -182,14 +204,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Type
+=head2 Type
 
 Returns the current value of Type. 
 (In the database, Type is stored as varchar(16).)
 
 
 
-=item SetType VALUE
+=head2 SetType VALUE
 
 
 Set Type to VALUE. 
@@ -200,14 +222,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Language
+=head2 Language
 
 Returns the current value of Language. 
 (In the database, Language is stored as varchar(16).)
 
 
 
-=item SetLanguage VALUE
+=head2 SetLanguage VALUE
 
 
 Set Language to VALUE. 
@@ -218,14 +240,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item TranslationOf
+=head2 TranslationOf
 
 Returns the current value of TranslationOf. 
 (In the database, TranslationOf is stored as int(11).)
 
 
 
-=item SetTranslationOf VALUE
+=head2 SetTranslationOf VALUE
 
 
 Set TranslationOf to VALUE. 
@@ -236,14 +258,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Content
+=head2 Content
 
 Returns the current value of Content. 
 (In the database, Content is stored as blob.)
 
 
 
-=item SetContent VALUE
+=head2 SetContent VALUE
 
 
 Set Content to VALUE. 
@@ -254,7 +276,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item LastUpdated
+=head2 LastUpdated
 
 Returns the current value of LastUpdated. 
 (In the database, LastUpdated is stored as datetime.)
@@ -263,7 +285,7 @@ Returns the current value of LastUpdated.
 =cut
 
 
-=item LastUpdatedBy
+=head2 LastUpdatedBy
 
 Returns the current value of LastUpdatedBy. 
 (In the database, LastUpdatedBy is stored as int(11).)
@@ -272,7 +294,7 @@ Returns the current value of LastUpdatedBy.
 =cut
 
 
-=item Creator
+=head2 Creator
 
 Returns the current value of Creator. 
 (In the database, Creator is stored as int(11).)
@@ -281,7 +303,7 @@ Returns the current value of Creator.
 =cut
 
 
-=item Created
+=head2 Created
 
 Returns the current value of Created. 
 (In the database, Created is stored as datetime.)
@@ -291,7 +313,7 @@ Returns the current value of Created.
 
 
 
-sub _ClassAccessible {
+sub _CoreAccessible {
     {
      
         id =>
index 37db840..925107e 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -64,7 +86,7 @@ sub _Init {
 }
 
 
-=item NewItem
+=head2 NewItem
 
 Returns an empty new RT::Template item
 
index 2f075a2..0d3c787 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -62,7 +84,7 @@ sub _Init {
 
 
 
-=item Create PARAMHASH
+=head2 Create PARAMHASH
 
 Create takes a hash of values and creates a row in the database:
 
@@ -144,7 +166,7 @@ sub Create {
 
 
 
-=item id
+=head2 id
 
 Returns the current value of id. 
 (In the database, id is stored as int(11).)
@@ -153,14 +175,14 @@ Returns the current value of id.
 =cut
 
 
-=item EffectiveId
+=head2 EffectiveId
 
 Returns the current value of EffectiveId. 
 (In the database, EffectiveId is stored as int(11).)
 
 
 
-=item SetEffectiveId VALUE
+=head2 SetEffectiveId VALUE
 
 
 Set EffectiveId to VALUE. 
@@ -171,14 +193,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Queue
+=head2 Queue
 
 Returns the current value of Queue. 
 (In the database, Queue is stored as int(11).)
 
 
 
-=item SetQueue VALUE
+=head2 SetQueue VALUE
 
 
 Set Queue to VALUE. 
@@ -189,7 +211,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item QueueObj
+=head2 QueueObj
 
 Returns the Queue Object which has the id returned by Queue
 
@@ -203,14 +225,14 @@ sub QueueObj {
        return($Queue);
 }
 
-=item Type
+=head2 Type
 
 Returns the current value of Type. 
 (In the database, Type is stored as varchar(16).)
 
 
 
-=item SetType VALUE
+=head2 SetType VALUE
 
 
 Set Type to VALUE. 
@@ -221,14 +243,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item IssueStatement
+=head2 IssueStatement
 
 Returns the current value of IssueStatement. 
 (In the database, IssueStatement is stored as int(11).)
 
 
 
-=item SetIssueStatement VALUE
+=head2 SetIssueStatement VALUE
 
 
 Set IssueStatement to VALUE. 
@@ -239,14 +261,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Resolution
+=head2 Resolution
 
 Returns the current value of Resolution. 
 (In the database, Resolution is stored as int(11).)
 
 
 
-=item SetResolution VALUE
+=head2 SetResolution VALUE
 
 
 Set Resolution to VALUE. 
@@ -257,14 +279,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Owner
+=head2 Owner
 
 Returns the current value of Owner. 
 (In the database, Owner is stored as int(11).)
 
 
 
-=item SetOwner VALUE
+=head2 SetOwner VALUE
 
 
 Set Owner to VALUE. 
@@ -275,14 +297,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Subject
+=head2 Subject
 
 Returns the current value of Subject. 
 (In the database, Subject is stored as varchar(200).)
 
 
 
-=item SetSubject VALUE
+=head2 SetSubject VALUE
 
 
 Set Subject to VALUE. 
@@ -293,14 +315,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item InitialPriority
+=head2 InitialPriority
 
 Returns the current value of InitialPriority. 
 (In the database, InitialPriority is stored as int(11).)
 
 
 
-=item SetInitialPriority VALUE
+=head2 SetInitialPriority VALUE
 
 
 Set InitialPriority to VALUE. 
@@ -311,14 +333,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item FinalPriority
+=head2 FinalPriority
 
 Returns the current value of FinalPriority. 
 (In the database, FinalPriority is stored as int(11).)
 
 
 
-=item SetFinalPriority VALUE
+=head2 SetFinalPriority VALUE
 
 
 Set FinalPriority to VALUE. 
@@ -329,14 +351,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Priority
+=head2 Priority
 
 Returns the current value of Priority. 
 (In the database, Priority is stored as int(11).)
 
 
 
-=item SetPriority VALUE
+=head2 SetPriority VALUE
 
 
 Set Priority to VALUE. 
@@ -347,14 +369,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item TimeEstimated
+=head2 TimeEstimated
 
 Returns the current value of TimeEstimated. 
 (In the database, TimeEstimated is stored as int(11).)
 
 
 
-=item SetTimeEstimated VALUE
+=head2 SetTimeEstimated VALUE
 
 
 Set TimeEstimated to VALUE. 
@@ -365,14 +387,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item TimeWorked
+=head2 TimeWorked
 
 Returns the current value of TimeWorked. 
 (In the database, TimeWorked is stored as int(11).)
 
 
 
-=item SetTimeWorked VALUE
+=head2 SetTimeWorked VALUE
 
 
 Set TimeWorked to VALUE. 
@@ -383,14 +405,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Status
+=head2 Status
 
 Returns the current value of Status. 
 (In the database, Status is stored as varchar(10).)
 
 
 
-=item SetStatus VALUE
+=head2 SetStatus VALUE
 
 
 Set Status to VALUE. 
@@ -401,14 +423,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item TimeLeft
+=head2 TimeLeft
 
 Returns the current value of TimeLeft. 
 (In the database, TimeLeft is stored as int(11).)
 
 
 
-=item SetTimeLeft VALUE
+=head2 SetTimeLeft VALUE
 
 
 Set TimeLeft to VALUE. 
@@ -419,14 +441,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Told
+=head2 Told
 
 Returns the current value of Told. 
 (In the database, Told is stored as datetime.)
 
 
 
-=item SetTold VALUE
+=head2 SetTold VALUE
 
 
 Set Told to VALUE. 
@@ -437,14 +459,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Starts
+=head2 Starts
 
 Returns the current value of Starts. 
 (In the database, Starts is stored as datetime.)
 
 
 
-=item SetStarts VALUE
+=head2 SetStarts VALUE
 
 
 Set Starts to VALUE. 
@@ -455,14 +477,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Started
+=head2 Started
 
 Returns the current value of Started. 
 (In the database, Started is stored as datetime.)
 
 
 
-=item SetStarted VALUE
+=head2 SetStarted VALUE
 
 
 Set Started to VALUE. 
@@ -473,14 +495,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Due
+=head2 Due
 
 Returns the current value of Due. 
 (In the database, Due is stored as datetime.)
 
 
 
-=item SetDue VALUE
+=head2 SetDue VALUE
 
 
 Set Due to VALUE. 
@@ -491,14 +513,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Resolved
+=head2 Resolved
 
 Returns the current value of Resolved. 
 (In the database, Resolved is stored as datetime.)
 
 
 
-=item SetResolved VALUE
+=head2 SetResolved VALUE
 
 
 Set Resolved to VALUE. 
@@ -509,7 +531,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item LastUpdatedBy
+=head2 LastUpdatedBy
 
 Returns the current value of LastUpdatedBy. 
 (In the database, LastUpdatedBy is stored as int(11).)
@@ -518,7 +540,7 @@ Returns the current value of LastUpdatedBy.
 =cut
 
 
-=item LastUpdated
+=head2 LastUpdated
 
 Returns the current value of LastUpdated. 
 (In the database, LastUpdated is stored as datetime.)
@@ -527,7 +549,7 @@ Returns the current value of LastUpdated.
 =cut
 
 
-=item Creator
+=head2 Creator
 
 Returns the current value of Creator. 
 (In the database, Creator is stored as int(11).)
@@ -536,7 +558,7 @@ Returns the current value of Creator.
 =cut
 
 
-=item Created
+=head2 Created
 
 Returns the current value of Created. 
 (In the database, Created is stored as datetime.)
@@ -545,14 +567,14 @@ Returns the current value of Created.
 =cut
 
 
-=item Disabled
+=head2 Disabled
 
 Returns the current value of Disabled. 
 (In the database, Disabled is stored as smallint(6).)
 
 
 
-=item SetDisabled VALUE
+=head2 SetDisabled VALUE
 
 
 Set Disabled to VALUE. 
@@ -564,7 +586,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 
 
 
-sub _ClassAccessible {
+sub _CoreAccessible {
     {
      
         id =>
index b6b3491..7bf452d 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -64,7 +86,7 @@ sub _Init {
 }
 
 
-=item NewItem
+=head2 NewItem
 
 Returns an empty new RT::Ticket item
 
index ca491a6..431d39a 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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:
 # 
-# END LICENSE BLOCK
+# (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.)
+# 
+# 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
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -62,7 +84,7 @@ sub _Init {
 
 
 
-=item Create PARAMHASH
+=head2 Create PARAMHASH
 
 Create takes a hash of values and creates a row in the database:
 
@@ -73,7 +95,7 @@ Create takes a hash of values and creates a row in the database:
   varchar(40) 'Field'.
   varchar(255) 'OldValue'.
   varchar(255) 'NewValue'.
-  varchar(100) 'Data'.
+  varchar(255) 'Data'.
 
 =cut
 
@@ -108,7 +130,7 @@ sub Create {
 
 
 
-=item id
+=head2 id
 
 Returns the current value of id. 
 (In the database, id is stored as int(11).)
@@ -117,14 +139,14 @@ Returns the current value of id.
 =cut
 
 
-=item EffectiveTicket
+=head2 EffectiveTicket
 
 Returns the current value of EffectiveTicket. 
 (In the database, EffectiveTicket is stored as int(11).)
 
 
 
-=item SetEffectiveTicket VALUE
+=head2 SetEffectiveTicket VALUE
 
 
 Set EffectiveTicket to VALUE. 
@@ -135,14 +157,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Ticket
+=head2 Ticket
 
 Returns the current value of Ticket. 
 (In the database, Ticket is stored as int(11).)
 
 
 
-=item SetTicket VALUE
+=head2 SetTicket VALUE
 
 
 Set Ticket to VALUE. 
@@ -153,7 +175,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item TicketObj
+=head2 TicketObj
 
 Returns the Ticket Object which has the id returned by Ticket
 
@@ -167,14 +189,14 @@ sub TicketObj {
        return($Ticket);
 }
 
-=item TimeTaken
+=head2 TimeTaken
 
 Returns the current value of TimeTaken. 
 (In the database, TimeTaken is stored as int(11).)
 
 
 
-=item SetTimeTaken VALUE
+=head2 SetTimeTaken VALUE
 
 
 Set TimeTaken to VALUE. 
@@ -185,14 +207,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Type
+=head2 Type
 
 Returns the current value of Type. 
 (In the database, Type is stored as varchar(20).)
 
 
 
-=item SetType VALUE
+=head2 SetType VALUE
 
 
 Set Type to VALUE. 
@@ -203,14 +225,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Field
+=head2 Field
 
 Returns the current value of Field. 
 (In the database, Field is stored as varchar(40).)
 
 
 
-=item SetField VALUE
+=head2 SetField VALUE
 
 
 Set Field to VALUE. 
@@ -221,14 +243,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item OldValue
+=head2 OldValue
 
 Returns the current value of OldValue. 
 (In the database, OldValue is stored as varchar(255).)
 
 
 
-=item SetOldValue VALUE
+=head2 SetOldValue VALUE
 
 
 Set OldValue to VALUE. 
@@ -239,14 +261,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item NewValue
+=head2 NewValue
 
 Returns the current value of NewValue. 
 (In the database, NewValue is stored as varchar(255).)
 
 
 
-=item SetNewValue VALUE
+=head2 SetNewValue VALUE
 
 
 Set NewValue to VALUE. 
@@ -257,25 +279,25 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Data
+=head2 Data
 
 Returns the current value of Data. 
-(In the database, Data is stored as varchar(100).)
+(In the database, Data is stored as varchar(255).)
 
 
 
-=item SetData VALUE
+=head2 SetData VALUE
 
 
 Set Data to VALUE. 
 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
-(In the database, Data will be stored as a varchar(100).)
+(In the database, Data will be stored as a varchar(255).)
 
 
 =cut
 
 
-=item Creator
+=head2 Creator
 
 Returns the current value of Creator. 
 (In the database, Creator is stored as int(11).)
@@ -284,7 +306,7 @@ Returns the current value of Creator.
 =cut
 
 
-=item Created
+=head2 Created
 
 Returns the current value of Created. 
 (In the database, Created is stored as datetime.)
@@ -294,7 +316,7 @@ Returns the current value of Created.
 
 
 
-sub _ClassAccessible {
+sub _CoreAccessible {
     {
      
         id =>
@@ -314,7 +336,7 @@ sub _ClassAccessible {
         NewValue => 
                {read => 1, write => 1, type => 'varchar(255)', default => ''},
         Data => 
-               {read => 1, write => 1, type => 'varchar(100)', default => ''},
+               {read => 1, write => 1, type => 'varchar(255)', default => ''},
         Creator => 
                {read => 1, auto => 1, type => 'int(11)', default => '0'},
         Created => 
index 23a475a..1e8a97b 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -64,7 +86,7 @@ sub _Init {
 }
 
 
-=item NewItem
+=head2 NewItem
 
 Returns an empty new RT::Transaction item
 
index cbc10f5..10e7e84 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -61,7 +83,7 @@ sub _Init {
 
 
 
-=item Create PARAMHASH
+=head2 Create PARAMHASH
 
 Create takes a hash of values and creates a row in the database:
 
@@ -170,7 +192,7 @@ sub Create {
 
 
 
-=item id
+=head2 id
 
 Returns the current value of id. 
 (In the database, id is stored as int(11).)
@@ -179,14 +201,14 @@ Returns the current value of id.
 =cut
 
 
-=item Name
+=head2 Name
 
 Returns the current value of Name. 
 (In the database, Name is stored as varchar(200).)
 
 
 
-=item SetName VALUE
+=head2 SetName VALUE
 
 
 Set Name to VALUE. 
@@ -197,14 +219,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Password
+=head2 Password
 
 Returns the current value of Password. 
 (In the database, Password is stored as varchar(40).)
 
 
 
-=item SetPassword VALUE
+=head2 SetPassword VALUE
 
 
 Set Password to VALUE. 
@@ -215,14 +237,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Comments
+=head2 Comments
 
 Returns the current value of Comments. 
 (In the database, Comments is stored as blob.)
 
 
 
-=item SetComments VALUE
+=head2 SetComments VALUE
 
 
 Set Comments to VALUE. 
@@ -233,14 +255,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Signature
+=head2 Signature
 
 Returns the current value of Signature. 
 (In the database, Signature is stored as blob.)
 
 
 
-=item SetSignature VALUE
+=head2 SetSignature VALUE
 
 
 Set Signature to VALUE. 
@@ -251,14 +273,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item EmailAddress
+=head2 EmailAddress
 
 Returns the current value of EmailAddress. 
 (In the database, EmailAddress is stored as varchar(120).)
 
 
 
-=item SetEmailAddress VALUE
+=head2 SetEmailAddress VALUE
 
 
 Set EmailAddress to VALUE. 
@@ -269,14 +291,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item FreeformContactInfo
+=head2 FreeformContactInfo
 
 Returns the current value of FreeformContactInfo. 
 (In the database, FreeformContactInfo is stored as blob.)
 
 
 
-=item SetFreeformContactInfo VALUE
+=head2 SetFreeformContactInfo VALUE
 
 
 Set FreeformContactInfo to VALUE. 
@@ -287,14 +309,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Organization
+=head2 Organization
 
 Returns the current value of Organization. 
 (In the database, Organization is stored as varchar(200).)
 
 
 
-=item SetOrganization VALUE
+=head2 SetOrganization VALUE
 
 
 Set Organization to VALUE. 
@@ -305,14 +327,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item RealName
+=head2 RealName
 
 Returns the current value of RealName. 
 (In the database, RealName is stored as varchar(120).)
 
 
 
-=item SetRealName VALUE
+=head2 SetRealName VALUE
 
 
 Set RealName to VALUE. 
@@ -323,14 +345,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item NickName
+=head2 NickName
 
 Returns the current value of NickName. 
 (In the database, NickName is stored as varchar(16).)
 
 
 
-=item SetNickName VALUE
+=head2 SetNickName VALUE
 
 
 Set NickName to VALUE. 
@@ -341,14 +363,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Lang
+=head2 Lang
 
 Returns the current value of Lang. 
 (In the database, Lang is stored as varchar(16).)
 
 
 
-=item SetLang VALUE
+=head2 SetLang VALUE
 
 
 Set Lang to VALUE. 
@@ -359,14 +381,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item EmailEncoding
+=head2 EmailEncoding
 
 Returns the current value of EmailEncoding. 
 (In the database, EmailEncoding is stored as varchar(16).)
 
 
 
-=item SetEmailEncoding VALUE
+=head2 SetEmailEncoding VALUE
 
 
 Set EmailEncoding to VALUE. 
@@ -377,14 +399,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item WebEncoding
+=head2 WebEncoding
 
 Returns the current value of WebEncoding. 
 (In the database, WebEncoding is stored as varchar(16).)
 
 
 
-=item SetWebEncoding VALUE
+=head2 SetWebEncoding VALUE
 
 
 Set WebEncoding to VALUE. 
@@ -395,14 +417,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item ExternalContactInfoId
+=head2 ExternalContactInfoId
 
 Returns the current value of ExternalContactInfoId. 
 (In the database, ExternalContactInfoId is stored as varchar(100).)
 
 
 
-=item SetExternalContactInfoId VALUE
+=head2 SetExternalContactInfoId VALUE
 
 
 Set ExternalContactInfoId to VALUE. 
@@ -413,14 +435,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item ContactInfoSystem
+=head2 ContactInfoSystem
 
 Returns the current value of ContactInfoSystem. 
 (In the database, ContactInfoSystem is stored as varchar(30).)
 
 
 
-=item SetContactInfoSystem VALUE
+=head2 SetContactInfoSystem VALUE
 
 
 Set ContactInfoSystem to VALUE. 
@@ -431,14 +453,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item ExternalAuthId
+=head2 ExternalAuthId
 
 Returns the current value of ExternalAuthId. 
 (In the database, ExternalAuthId is stored as varchar(100).)
 
 
 
-=item SetExternalAuthId VALUE
+=head2 SetExternalAuthId VALUE
 
 
 Set ExternalAuthId to VALUE. 
@@ -449,14 +471,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item AuthSystem
+=head2 AuthSystem
 
 Returns the current value of AuthSystem. 
 (In the database, AuthSystem is stored as varchar(30).)
 
 
 
-=item SetAuthSystem VALUE
+=head2 SetAuthSystem VALUE
 
 
 Set AuthSystem to VALUE. 
@@ -467,14 +489,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Gecos
+=head2 Gecos
 
 Returns the current value of Gecos. 
 (In the database, Gecos is stored as varchar(16).)
 
 
 
-=item SetGecos VALUE
+=head2 SetGecos VALUE
 
 
 Set Gecos to VALUE. 
@@ -485,14 +507,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item HomePhone
+=head2 HomePhone
 
 Returns the current value of HomePhone. 
 (In the database, HomePhone is stored as varchar(30).)
 
 
 
-=item SetHomePhone VALUE
+=head2 SetHomePhone VALUE
 
 
 Set HomePhone to VALUE. 
@@ -503,14 +525,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item WorkPhone
+=head2 WorkPhone
 
 Returns the current value of WorkPhone. 
 (In the database, WorkPhone is stored as varchar(30).)
 
 
 
-=item SetWorkPhone VALUE
+=head2 SetWorkPhone VALUE
 
 
 Set WorkPhone to VALUE. 
@@ -521,14 +543,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item MobilePhone
+=head2 MobilePhone
 
 Returns the current value of MobilePhone. 
 (In the database, MobilePhone is stored as varchar(30).)
 
 
 
-=item SetMobilePhone VALUE
+=head2 SetMobilePhone VALUE
 
 
 Set MobilePhone to VALUE. 
@@ -539,14 +561,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item PagerPhone
+=head2 PagerPhone
 
 Returns the current value of PagerPhone. 
 (In the database, PagerPhone is stored as varchar(30).)
 
 
 
-=item SetPagerPhone VALUE
+=head2 SetPagerPhone VALUE
 
 
 Set PagerPhone to VALUE. 
@@ -557,14 +579,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Address1
+=head2 Address1
 
 Returns the current value of Address1. 
 (In the database, Address1 is stored as varchar(200).)
 
 
 
-=item SetAddress1 VALUE
+=head2 SetAddress1 VALUE
 
 
 Set Address1 to VALUE. 
@@ -575,14 +597,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Address2
+=head2 Address2
 
 Returns the current value of Address2. 
 (In the database, Address2 is stored as varchar(200).)
 
 
 
-=item SetAddress2 VALUE
+=head2 SetAddress2 VALUE
 
 
 Set Address2 to VALUE. 
@@ -593,14 +615,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item City
+=head2 City
 
 Returns the current value of City. 
 (In the database, City is stored as varchar(100).)
 
 
 
-=item SetCity VALUE
+=head2 SetCity VALUE
 
 
 Set City to VALUE. 
@@ -611,14 +633,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item State
+=head2 State
 
 Returns the current value of State. 
 (In the database, State is stored as varchar(100).)
 
 
 
-=item SetState VALUE
+=head2 SetState VALUE
 
 
 Set State to VALUE. 
@@ -629,14 +651,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Zip
+=head2 Zip
 
 Returns the current value of Zip. 
 (In the database, Zip is stored as varchar(16).)
 
 
 
-=item SetZip VALUE
+=head2 SetZip VALUE
 
 
 Set Zip to VALUE. 
@@ -647,14 +669,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Country
+=head2 Country
 
 Returns the current value of Country. 
 (In the database, Country is stored as varchar(50).)
 
 
 
-=item SetCountry VALUE
+=head2 SetCountry VALUE
 
 
 Set Country to VALUE. 
@@ -665,14 +687,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Timezone
+=head2 Timezone
 
 Returns the current value of Timezone. 
 (In the database, Timezone is stored as varchar(50).)
 
 
 
-=item SetTimezone VALUE
+=head2 SetTimezone VALUE
 
 
 Set Timezone to VALUE. 
@@ -683,14 +705,14 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item PGPKey
+=head2 PGPKey
 
 Returns the current value of PGPKey. 
 (In the database, PGPKey is stored as text.)
 
 
 
-=item SetPGPKey VALUE
+=head2 SetPGPKey VALUE
 
 
 Set PGPKey to VALUE. 
@@ -701,7 +723,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=item Creator
+=head2 Creator
 
 Returns the current value of Creator. 
 (In the database, Creator is stored as int(11).)
@@ -710,7 +732,7 @@ Returns the current value of Creator.
 =cut
 
 
-=item Created
+=head2 Created
 
 Returns the current value of Created. 
 (In the database, Created is stored as datetime.)
@@ -719,7 +741,7 @@ Returns the current value of Created.
 =cut
 
 
-=item LastUpdatedBy
+=head2 LastUpdatedBy
 
 Returns the current value of LastUpdatedBy. 
 (In the database, LastUpdatedBy is stored as int(11).)
@@ -728,7 +750,7 @@ Returns the current value of LastUpdatedBy.
 =cut
 
 
-=item LastUpdated
+=head2 LastUpdated
 
 Returns the current value of LastUpdated. 
 (In the database, LastUpdated is stored as datetime.)
@@ -738,7 +760,7 @@ Returns the current value of LastUpdated.
 
 
 
-sub _ClassAccessible {
+sub _CoreAccessible {
     {
      
         id =>
index d58f696..95aec3b 100755 (executable)
@@ -1,8 +1,14 @@
-# BEGIN LICENSE BLOCK
+# {{{ BEGIN BPS TAGGED BLOCK
 # 
-# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC 
+#                                          <jesse@bestpractical.com>
 # 
-# (Except where explictly superceded by other copyright notices)
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
 # 
 # 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.
 # 
-# 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.
+# 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.)
 # 
+# 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 LICENSE BLOCK
+# }}} END BPS TAGGED BLOCK
 # Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
 # WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
 # 
@@ -64,7 +86,7 @@ sub _Init {
 }
 
 
-=item NewItem
+=head2 NewItem
 
 Returns an empty new RT::User item