add per-agent invoice templates, add per-package suspend invoice events, fix automati...
[freeside.git] / FS / FS / svc_forward.pm
index 1476dbf..b8d55fe 100644 (file)
@@ -1,11 +1,9 @@
 package FS::svc_forward;
 
 use strict;
 package FS::svc_forward;
 
 use strict;
-use vars qw( @ISA $nossh_hack $conf $shellmachine @qmailmachines
-             @vpopmailmachines );
-use Net::SSH qw(ssh);
+use vars qw( @ISA );
 use FS::Conf;
 use FS::Conf;
-use FS::Record qw( fields qsearch qsearchs );
+use FS::Record qw( fields qsearch qsearchs dbh );
 use FS::svc_Common;
 use FS::cust_svc;
 use FS::svc_acct;
 use FS::svc_Common;
 use FS::cust_svc;
 use FS::svc_acct;
@@ -13,21 +11,6 @@ use FS::svc_domain;
 
 @ISA = qw( FS::svc_Common );
 
 
 @ISA = qw( FS::svc_Common );
 
-#ask FS::UID to run this stuff for us later
-$FS::UID::callback{'FS::svc_forward'} = sub { 
-  $conf = new FS::Conf;
-  if ( $conf->exists('qmailmachines') ) {
-    $shellmachine = $conf->config('shellmachine')
-  } else {
-    $shellmachine = '';
-  }
-  if ( $conf->exists('vpopmailmachines') ) {
-    @vpopmailmachines = $conf->config('vpopmailmachines');
-  } else {
-    @vpopmailmachines = ();
-  }
-};
-
 =head1 NAME
 
 FS::svc_forward - Object methods for svc_forward records
 =head1 NAME
 
 FS::svc_forward - Object methods for svc_forward records
@@ -64,9 +47,11 @@ inherits from FS::Record.  The following fields are currently supported:
 
 =item srcsvc - svcnum of the source of the forward (see L<FS::svc_acct>)
 
 
 =item srcsvc - svcnum of the source of the forward (see L<FS::svc_acct>)
 
+=item src - literal source (username or full email address)
+
 =item dstsvc - svcnum of the destination of the forward (see L<FS::svc_acct>)
 
 =item dstsvc - svcnum of the destination of the forward (see L<FS::svc_acct>)
 
-=item dst - foreign destination (email address) - forward not local to freeside
+=item dst - literal destination (username or full email address)
 
 =back
 
 
 =back
 
@@ -83,7 +68,7 @@ database, see L<"insert">.
 
 sub table { 'svc_forward'; }
 
 
 sub table { 'svc_forward'; }
 
-=item insert
+=item insert [ , OPTION => VALUE ... ]
 
 Adds this mail forwarding alias to the database.  If there is an error, returns
 the error, otherwise returns false.
 
 Adds this mail forwarding alias to the database.  If there is an error, returns
 the error, otherwise returns false.
@@ -91,16 +76,11 @@ the error, otherwise returns false.
 The additional fields pkgnum and svcpart (see L<FS::cust_svc>) should be 
 defined.  An FS::cust_svc record will be created and inserted.
 
 The additional fields pkgnum and svcpart (see L<FS::cust_svc>) should be 
 defined.  An FS::cust_svc record will be created and inserted.
 
-If the configuration value (see L<FS::Conf>) vpopmailmachines exists, then
-the command:
+Currently available options are: I<depend_jobnum>
 
 
-  [ -d $vpopdir/$domain/$source ] || {
-    echo "$destination" >> $vpopdir/$domain/$username/.$qmail
-    chown $vpopuid:$vpopgid $vpopdir/$domain/$username/.$qmail
-  }
-
-is executed on each vpopmailmachine via ssh (see the vpopmail documentation).
-This behaviour can be supressed by setting $FS::svc_forward::nossh_hack true.
+If I<depend_jobnum> is set (to a scalar jobnum or an array reference of
+jobnums), all provisioning jobs will have a dependancy on the supplied
+jobnum(s) (they will not run until the specific job(s) complete(s)).
 
 =cut
 
 
 =cut
 
@@ -115,29 +95,20 @@ sub insert {
   local $SIG{TSTP} = 'IGNORE';
   local $SIG{PIPE} = 'IGNORE';
 
   local $SIG{TSTP} = 'IGNORE';
   local $SIG{PIPE} = 'IGNORE';
 
-  $error = $self->check;
-  return $error if $error;
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
 
 
-  $error = $self->SUPER::insert;
+  $error = $self->check;
   return $error if $error;
 
   return $error if $error;
 
-  my $svc_acct = qsearchs( 'svc_acct', { 'svcnum' => $self->srcsvc } );
-  my $username = $svc_acct->username;
-  my $domain = $svc_acct->domain;
-  my $destination;
-  if ($self->dstsvc) {
-    my $dst_svc_acct = qsearchs( 'svc_acct', { 'svcnum' => $self->dstsvc } );
-    $destination = $dst_svc_acct->email;
-  } else {
-    $destination = $self->dst;
-  }
-    
-  foreach my $vpopmailmachine ( @vpopmailmachines ) {
-    my($machine, $vpopdir, $vpopuid, $vpopgid) = split(/\s+/, $vpopmailmachine);
-    ssh("root\@$machine","[ -d $vpopdir/$domain/$username ] || { echo \"$destination\" >> $vpopdir/$domain/$username/.qmail; chown $vpopuid:$vpopgid $vpopdir/$domain/$username/.qmail; }") 
-      unless $nossh_hack;
+  $error = $self->SUPER::insert(@_);
+  if ($error) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
   }
 
   }
 
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
   ''; #no error
 
 }
   ''; #no error
 
 }
@@ -149,29 +120,37 @@ returns the error, otherwise returns false.
 
 The corresponding FS::cust_svc record will be deleted as well.
 
 
 The corresponding FS::cust_svc record will be deleted as well.
 
-=item replace OLD_RECORD
+=cut
 
 
-Replaces OLD_RECORD with this one in the database.  If there is an error,
-returns the error, otherwise returns false.
+sub delete {
+  my $self = shift;
 
 
-If srcsvc changes, and the configuration value vpopmailmachines exists, then
-the command:
+  local $SIG{HUP} = 'IGNORE';
+  local $SIG{INT} = 'IGNORE';
+  local $SIG{QUIT} = 'IGNORE';
+  local $SIG{TERM} = 'IGNORE';
+  local $SIG{TSTP} = 'IGNORE';
+  local $SIG{PIPE} = 'IGNORE';
 
 
-  rm $vpopdir/$domain/$username/.qmail
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::Autocommit = 0;
+  my $dbh = dbh;
 
 
-is executed on each vpopmailmachine via ssh.  This behaviour can be supressed
-by setting $FS::svc_forward_nossh_hack true.
+  my $error = $self->SUPER::delete;
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
 
 
-If dstsvc changes (or dstsvc is 0 and dst changes), and the configuration value
-vpopmailmachines exists, then the command:
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+  '';
+}
 
 
-  [ -d $vpopdir/$domain/$source ] || {
-    echo "$destination" >> $vpopdir/$domain/$username/.$qmail
-    chown $vpopuid:$vpopgid $vpopdir/$domain/$username/.$qmail
-  }
 
 
-is executed on each vpopmailmachine via ssh.  This behaviour can be supressed
-by setting $FS::svc_forward_nossh_hack true.
+=item replace OLD_RECORD
+
+Replaces OLD_RECORD with this one in the database.  If there is an error,
+returns the error, otherwise returns false.
 
 =cut
 
 
 =cut
 
@@ -193,40 +172,17 @@ sub replace {
   local $SIG{TSTP} = 'IGNORE';
   local $SIG{PIPE} = 'IGNORE';
 
   local $SIG{TSTP} = 'IGNORE';
   local $SIG{PIPE} = 'IGNORE';
 
-  my $error = $new->SUPER::replace($old);
-  return $error if $error;
-
-  if ( $new->srcsvc != $old->srcsvc ) {
-    my $old_svc_acct = qsearchs( 'svc_acct', { 'svcnum' => $old->srcsvc } );
-    my $old_username = $old_svc_acct->username;
-    my $old_domain = $old_svc_acct->domain;
-    foreach my $vpopmailmachine ( @vpopmailmachines ) {
-      my($machine, $vpopdir, $vpopuid, $vpopgid) =
-        split(/\s+/, $vpopmailmachine);
-      ssh("root\@$machine","rm $vpopdir/$old_domain/$old_username/.qmail")
-        unless $nossh_hack;
-    }
-  }
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
 
 
-  #false laziness with stuff in insert, should subroutine
-  my $svc_acct = qsearchs( 'svc_acct', { 'svcnum' => $new->srcsvc } );
-  my $username = $svc_acct->username;
-  my $domain = $svc_acct->domain;
-  my $destination;
-  if ($new->dstsvc) {
-    my $dst_svc_acct = qsearchs( 'svc_acct', { 'svcnum' => $new->dstsvc } );
-    $destination = $dst_svc_acct->email;
-  } else {
-    $destination = $new->dst;
-  }
-  
-  foreach my $vpopmailmachine ( @vpopmailmachines ) {
-    my($machine, $vpopdir, $vpopuid, $vpopgid) = split(/\s+/, $vpopmailmachine);
-    ssh("root\@$machine","[ -d $vpopdir/$domain/$username ] || { echo \"$destination\" >> $vpopdir/$domain/$username/.qmail; chown $vpopuid:$vpopgid $vpopdir/$domain/$username/.qmail; }") 
-      unless $nossh_hack;
+  my $error = $new->SUPER::replace($old);
+  if ($error) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
   }
   }
-  #end subroutinable bits
 
 
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
   '';
 }
 
   '';
 }
 
@@ -266,35 +222,55 @@ sub check {
   #my $part_svc = $x;
 
   my $error = $self->ut_numbern('svcnum')
   #my $part_svc = $x;
 
   my $error = $self->ut_numbern('svcnum')
-              || $self->ut_number('srcsvc')
+              || $self->ut_numbern('srcsvc')
               || $self->ut_numbern('dstsvc')
   ;
   return $error if $error;
 
               || $self->ut_numbern('dstsvc')
   ;
   return $error if $error;
 
-  return "Unknown srcsvc" unless $self->srcsvc_acct;
+  return "Both srcsvc and src were defined; only one can be specified"
+    if $self->srcsvc && $self->src;
 
 
-  return "Both dstsvc and dst were defined; one one can be specified"
+  return "one of srcsvc or src is required"
+    unless $self->srcsvc || $self->src;
+
+  return "Unknown srcsvc: ". $self->srcsvc
+    unless ! $self->srcsvc || $self->srcsvc_acct;
+
+  return "Both dstsvc and dst were defined; only one can be specified"
     if $self->dstsvc && $self->dst;
 
   return "one of dstsvc or dst is required"
     unless $self->dstsvc || $self->dst;
 
     if $self->dstsvc && $self->dst;
 
   return "one of dstsvc or dst is required"
     unless $self->dstsvc || $self->dst;
 
-  return "Unknown dstsvc" unless $self->dstsvc_acct || ! $self->dstsvc;
+  return "Unknown dstsvc: ". $self->dstsvc
+    unless ! $self->dstsvc || $self->dstsvc_acct;
+  #return "Unknown dstsvc"
+  #  unless qsearchs('svc_acct', { 'svcnum' => $self->dstsvc } )
+  #         || ! $self->dstsvc;
+
+  if ( $self->src ) {
+    $self->src =~ /^([\w\.\-\&]*)(\@([\w\-]+\.)+\w+)?$/
+       or return "Illegal src: ". $self->dst;
+    $self->src("$1$2");
+  } else {
+    $self->src('');
+  }
 
   if ( $self->dst ) {
 
   if ( $self->dst ) {
-    $self->dst =~ /^([\w\.\-]+)\@(([\w\-]+\.)+\w+)$/
+    $self->dst =~ /^([\w\.\-\&]*)(\@([\w\-]+\.)+\w+)?$/
        or return "Illegal dst: ". $self->dst;
        or return "Illegal dst: ". $self->dst;
-    $self->dst("$1\@$2");
+    $self->dst("$1$2");
   } else {
     $self->dst('');
   }
 
   } else {
     $self->dst('');
   }
 
-  ''; #no error
+  $self->SUPER::check;
 }
 
 =item srcsvc_acct
 
 }
 
 =item srcsvc_acct
 
-Returns the FS::svc_acct object referenced by the srcsvc column.
+Returns the FS::svc_acct object referenced by the srcsvc column, or false for
+literally specified forwards.
 
 =cut
 
 
 =cut
 
@@ -306,28 +282,23 @@ sub srcsvc_acct {
 =item dstsvc_acct
 
 Returns the FS::svc_acct object referenced by the srcsvc column, or false for
 =item dstsvc_acct
 
 Returns the FS::svc_acct object referenced by the srcsvc column, or false for
-forwards not local to freeside.
+literally specified forwards.
 
 
-=back
+=cut
 
 sub dstsvc_acct {
   my $self = shift;
   qsearchs('svc_acct', { 'svcnum' => $self->dstsvc } );
 }
 
 
 sub dstsvc_acct {
   my $self = shift;
   qsearchs('svc_acct', { 'svcnum' => $self->dstsvc } );
 }
 
-=head1 VERSION
-
-$Id: svc_forward.pm,v 1.8 2001-10-29 20:53:38 ivan Exp $
+=back
 
 =head1 BUGS
 
 
 =head1 BUGS
 
-The remote commands should be configurable.
-
 =head1 SEE ALSO
 
 L<FS::Record>, L<FS::Conf>, L<FS::cust_svc>, L<FS::part_svc>, L<FS::cust_pkg>,
 =head1 SEE ALSO
 
 L<FS::Record>, L<FS::Conf>, L<FS::cust_svc>, L<FS::part_svc>, L<FS::cust_pkg>,
-L<FS::svc_acct>, L<FS::svc_domain>, L<Net::SSH>, L<ssh>, L<dot-qmail>,
-schema.html from the base documentation.
+L<FS::svc_acct>, L<FS::svc_domain>, schema.html from the base documentation.
 
 =cut
 
 
 =cut