export host selection per service, RT#17914
authorIvan Kohler <ivan@freeside.biz>
Tue, 18 Sep 2012 09:18:04 +0000 (02:18 -0700)
committerIvan Kohler <ivan@freeside.biz>
Tue, 18 Sep 2012 09:18:04 +0000 (02:18 -0700)
66 files changed:
FS/FS.pm
FS/FS/Record.pm
FS/FS/Schema.pm
FS/FS/part_export.pm
FS/FS/part_export/acct_google.pm
FS/FS/part_export/acct_http.pm
FS/FS/part_export/acct_plesk.pm
FS/FS/part_export/acct_sql.pm
FS/FS/part_export/acct_sql_status.pm
FS/FS/part_export/acct_xmlrpc.pm
FS/FS/part_export/amazon_ec2.pm
FS/FS/part_export/artera_turbo.pm
FS/FS/part_export/broadband_http.pm
FS/FS/part_export/broadband_nas.pm
FS/FS/part_export/broadband_shellcommands.pm
FS/FS/part_export/broadband_snmp.pm
FS/FS/part_export/broadband_sql.pm
FS/FS/part_export/broadband_sqlradius.pm
FS/FS/part_export/communigate_pro.pm
FS/FS/part_export/communigate_pro_singledomain.pm
FS/FS/part_export/cp.pm
FS/FS/part_export/cpanel.pm
FS/FS/part_export/cust_http.pm
FS/FS/part_export/cyrus.pm
FS/FS/part_export/dashcs_e911.pm
FS/FS/part_export/domain_sql.pm
FS/FS/part_export/everyone_net.pm
FS/FS/part_export/ez_prepaid.pm
FS/FS/part_export/forward_sql.pm
FS/FS/part_export/globalpops_voip.pm
FS/FS/part_export/http.pm
FS/FS/part_export/http_status.pm
FS/FS/part_export/ikano.pm
FS/FS/part_export/indosoft.pm
FS/FS/part_export/infostreet.pm
FS/FS/part_export/internal_diddb.pm
FS/FS/part_export/ldap.pm
FS/FS/part_export/netsapiens.pm
FS/FS/part_export/null.pm
FS/FS/part_export/phone_shellcommands.pm
FS/FS/part_export/phone_sqlopensips.pm
FS/FS/part_export/phone_sqlradius.pm
FS/FS/part_export/postfix.pm
FS/FS/part_export/prizm.pm
FS/FS/part_export/radiator.pm
FS/FS/part_export/router.pm
FS/FS/part_export/rt_ticket.pm
FS/FS/part_export/send_email.pm
FS/FS/part_export/shellcommands.pm
FS/FS/part_export/sqlmail.pm
FS/FS/part_export/sqlradius.pm
FS/FS/part_export/textradius.pm
FS/FS/part_export/trango.pm
FS/FS/part_export/vitelity.pm
FS/FS/part_export/vpopmail.pm
FS/FS/part_export/www_plesk.pm
FS/FS/part_export/www_shellcommands.pm
FS/FS/part_export_machine.pm [new file with mode: 0644]
FS/FS/part_svc.pm
FS/FS/svc_export_machine.pm [new file with mode: 0644]
FS/MANIFEST
FS/t/part_export_machine.t [new file with mode: 0644]
FS/t/svc_export_machine.t [new file with mode: 0644]
httemplate/browse/part_export.cgi
httemplate/edit/part_export.cgi
httemplate/edit/process/part_export.cgi

index 5ab3f71..2d963b5 100644 (file)
--- a/FS/FS.pm
+++ b/FS/FS.pm
@@ -284,6 +284,10 @@ L<FS::agent_payment_gateway> - Agent payment gateway class
 
 L<FS::cust_svc> - Service class
 
 
 L<FS::cust_svc> - Service class
 
+L<FS::part_export_machine> - Export hostname choice class
+
+L<FS::svc_export_machine> - Customer export hostname class
+
 L<FS::cust_pkg> - Customer package class
 
 L<FS::cust_pkg_option> - Customer package option class
 L<FS::cust_pkg> - Customer package class
 
 L<FS::cust_pkg_option> - Customer package option class
index 0ac269f..ca68c35 100644 (file)
@@ -2421,10 +2421,9 @@ sub ut_coordn {
 
 }
 
 
 }
 
-
 =item ut_domain COLUMN
 
 =item ut_domain COLUMN
 
-Check/untaint host and domain names.
+Check/untaint host and domain names.  May not be null.
 
 =cut
 
 
 =cut
 
@@ -2432,11 +2431,27 @@ sub ut_domain {
   my( $self, $field ) = @_;
   #$self->getfield($field) =~/^(\w+\.)*\w+$/
   $self->getfield($field) =~/^(([\w\-]+\.)*\w+)$/
   my( $self, $field ) = @_;
   #$self->getfield($field) =~/^(\w+\.)*\w+$/
   $self->getfield($field) =~/^(([\w\-]+\.)*\w+)$/
-    or return "Illegal (domain) $field: ". $self->getfield($field);
+    or return "Illegal (hostname) $field: ". $self->getfield($field);
   $self->setfield($field,$1);
   '';
 }
 
   $self->setfield($field,$1);
   '';
 }
 
+=item ut_domainn COLUMN
+
+Check/untaint host and domain names.  May be null.
+
+=cut
+
+sub ut_domainn {
+  my( $self, $field ) = @_;
+  if ( $self->getfield($field) =~ /^()$/ ) {
+    $self->setfield($field,'');
+    '';
+  } else {
+    $self->ut_domain($field);
+  }
+}
+
 =item ut_name COLUMN
 
 Check/untaint proper names; allows alphanumerics, spaces and the following
 =item ut_name COLUMN
 
 Check/untaint proper names; allows alphanumerics, spaces and the following
index 4ef2a63..6e3956a 100644 (file)
@@ -1890,6 +1890,29 @@ sub tables_hashref {
       'index'       => [ [ 'svcnum' ], [ 'optionname' ] ],
     },
 
       'index'       => [ [ 'svcnum' ], [ 'optionname' ] ],
     },
 
+    'svc_export_machine' => {
+      'columns' => [
+        'svcexportmachinenum', 'serial', '', '', '', '',
+        'svcnum',                 'int', '', '', '', '', 
+        'machinenum',             'int', '', '', '', '',
+      ],
+      'primary_key' => 'svcexportmachinenum',
+      'unique'      => [],
+      'index'       => [],
+    },
+
+    'part_export_machine' => {
+      'columns' => [
+        'machinenum', 'serial', '', '', '', '',
+        'exportnum',     'int', '', '', '', '',
+        'machine',    'varchar', 'NULL', $char_d, '', '', 
+        'disabled',      'char', 'NULL',       1, '', '',
+      ],
+      'primary_key' => 'machinenum',
+      'unique'      => [ [ 'exportnum', 'machine' ] ],
+      'index'       => [ [ 'exportnum' ] ],
+    },
+
    'part_pkg' => {
       'columns' => [
         'pkgpart',       'serial',    '',   '', '', '', 
    'part_pkg' => {
       'columns' => [
         'pkgpart',       'serial',    '',   '', '', '', 
@@ -2623,11 +2646,11 @@ sub tables_hashref {
 
     'part_export' => {
       'columns' => [
 
     'part_export' => {
       'columns' => [
-        'exportnum', 'serial', '', '', '', '', 
+        'exportnum',   'serial',     '',      '', '', '', 
         'exportname', 'varchar', 'NULL', $char_d, '', '',
         'exportname', 'varchar', 'NULL', $char_d, '', '',
-        'machine', 'varchar', '', $char_d, '', '', 
-        'exporttype', 'varchar', '', $char_d, '', '', 
-        'nodomain',     'char', 'NULL', 1, '', '', 
+        'machine',    'varchar', 'NULL', $char_d, '', '', 
+        'exporttype', 'varchar',     '', $char_d, '', '', 
+        'nodomain',      'char', 'NULL',       1, '', '', 
       ],
       'primary_key' => 'exportnum',
       'unique'      => [],
       ],
       'primary_key' => 'exportnum',
       'unique'      => [],
index 45773e0..97394af 100644 (file)
@@ -4,10 +4,11 @@ use strict;
 use vars qw( @ISA @EXPORT_OK $DEBUG %exports );
 use Exporter;
 use Tie::IxHash;
 use vars qw( @ISA @EXPORT_OK $DEBUG %exports );
 use Exporter;
 use Tie::IxHash;
-use base qw( FS::option_Common FS::m2m_Common ); # m2m for 'export_nas'
+use base qw( FS::option_Common FS::m2m_Common );
 use FS::Record qw( qsearch qsearchs dbh );
 use FS::part_svc;
 use FS::part_export_option;
 use FS::Record qw( qsearch qsearchs dbh );
 use FS::part_svc;
 use FS::part_export_option;
+use FS::part_export_machine;
 use FS::export_svc;
 
 #for export modules, though they should probably just use it themselves
 use FS::export_svc;
 
 #for export modules, though they should probably just use it themselves
@@ -108,6 +109,50 @@ otherwise returns false.
 If a hash reference of options is supplied, part_export_option records are
 created (see L<FS::part_export_option>).
 
 If a hash reference of options is supplied, part_export_option records are
 created (see L<FS::part_export_option>).
 
+=cut
+
+sub insert {
+  my $self = shift;
+
+  local $SIG{HUP} = 'IGNORE';
+  local $SIG{INT} = 'IGNORE';
+  local $SIG{QUIT} = 'IGNORE';
+  local $SIG{TERM} = 'IGNORE';
+  local $SIG{TSTP} = 'IGNORE';
+  local $SIG{PIPE} = 'IGNORE';
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  my $error = $self->SUPER::insert(@_);
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
+
+  #kinda false laziness with process_m2name
+  my @machines = map { $_ =~ s/^\s+//; $_ =~ s/\s+$//; $_ }
+                   grep /\S/,
+                     split /[\n\r]{1,2}/,
+                       $self->part_export_machine_textarea;
+
+  foreach my $machine ( @machines ) {
+
+    my $part_export_machine = new FS::part_export_machine {
+      'exportnum' => $self->exportnum,
+      'machine'   => $machine,
+    };
+    $error = $part_export_machine->insert;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+  '';
+}
+
 =item delete
 
 Delete this record from the database.
 =item delete
 
 Delete this record from the database.
@@ -117,13 +162,13 @@ Delete this record from the database.
 #foreign keys would make this much less tedious... grr dumb mysql
 sub delete {
   my $self = shift;
 #foreign keys would make this much less tedious... grr dumb mysql
 sub delete {
   my $self = shift;
+
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
   local $SIG{QUIT} = 'IGNORE';
   local $SIG{TERM} = 'IGNORE';
   local $SIG{TSTP} = 'IGNORE';
   local $SIG{PIPE} = 'IGNORE';
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
   local $SIG{QUIT} = 'IGNORE';
   local $SIG{TERM} = 'IGNORE';
   local $SIG{TSTP} = 'IGNORE';
   local $SIG{PIPE} = 'IGNORE';
-
   my $oldAutoCommit = $FS::UID::AutoCommit;
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
   my $oldAutoCommit = $FS::UID::AutoCommit;
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
@@ -147,10 +192,103 @@ sub delete {
     }
   }
 
     }
   }
 
-  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+  foreach my $part_export_machine ( $self->part_export_machine ) {
+    my $error = $part_export_machine->delete;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
 
 
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
   '';
   '';
+}
+
+=item replace [ OLD_RECORD ] [ HASHREF | OPTION => VALUE ... ]
+
+Replaces the OLD_RECORD with this one in the database.  If there is an error,
+returns the error, otherwise returns false.
+
+If a list or hash reference of options is supplied, option records are created
+or modified.
+
+=cut
 
 
+sub replace {
+  my $self = shift;
+
+  local $SIG{HUP} = 'IGNORE';
+  local $SIG{INT} = 'IGNORE';
+  local $SIG{QUIT} = 'IGNORE';
+  local $SIG{TERM} = 'IGNORE';
+  local $SIG{TSTP} = 'IGNORE';
+  local $SIG{PIPE} = 'IGNORE';
+
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  my $error = $self->SUPER::replace(@_);
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
+
+  if ( $self->part_export_machine_textarea ) {
+
+    my %part_export_machine = map { $_->machine => $_ }
+                                $self->part_export_machine;
+
+    my @machines = map { $_ =~ s/^\s+//; $_ =~ s/\s+$//; $_ }
+                     grep /\S/,
+                       split /[\n\r]{1,2}/,
+                         $self->part_export_machine_textarea;
+
+    foreach my $machine ( @machines ) {
+
+      if ( $part_export_machine{$machine} ) {
+
+        if ( $part_export_machine{$machine}->disabled eq 'Y' ) {
+          $part_export_machine{$machine}->disabled('');
+          $error = $part_export_machine{$machine}->replace;
+          if ( $error ) {
+            $dbh->rollback if $oldAutoCommit;
+            return $error;
+          }
+        }
+
+        delete $part_export_machine{$machine}; #so we don't disable it below
+
+      } else {
+
+        my $part_export_machine = new FS::part_export_machine {
+                                        'exportnum' => $self->exportnum,
+                                        'machine'   => $machine
+                                      };
+        $error = $part_export_machine->insert;
+        if ( $error ) {
+          $dbh->rollback if $oldAutoCommit;
+          return $error;
+        }
+  
+      }
+
+    }
+
+
+    foreach my $part_export_machine ( values %part_export_machine ) {
+      $part_export_machine->disabled('Y');
+      $error = $part_export_machine->replace;
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return $error;
+      }
+    }
+
+  }
+
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+  '';
 }
 
 =item check
 }
 
 =item check
@@ -166,7 +304,7 @@ sub check {
   my $error = 
     $self->ut_numbern('exportnum')
     || $self->ut_textn('exportname')
   my $error = 
     $self->ut_numbern('exportnum')
     || $self->ut_textn('exportname')
-    || $self->ut_domain('machine')
+    || $self->ut_domainn('machine')
     || $self->ut_alpha('exporttype')
   ;
   return $error if $error;
     || $self->ut_alpha('exporttype')
   ;
   return $error if $error;
@@ -233,6 +371,20 @@ sub cust_svc {
       $self->export_svc;
 }
 
       $self->export_svc;
 }
 
+=item part_export_machine
+
+Returns all machines as FS::part_export_machine objects (see
+L<FS::part_export_machine>).
+
+=cut
+
+sub part_export_machine {
+  my $self = shift;
+  map { $_ } #behavior of sort undefined in scalar context
+    sort { $a->machine cmp $b->machine }
+      qsearch('part_export_machine', { 'exportnum' => $self->exportnum } );
+}
+
 =item export_svc
 
 Returns a list of associated FS::export_svc records.
 =item export_svc
 
 Returns a list of associated FS::export_svc records.
index afc45db..d153728 100644 (file)
@@ -16,10 +16,12 @@ tie my %options, 'Tie::IxHash',
 # admin logins.
 
 %info = (
 # admin logins.
 
 %info = (
-  'svc'       => 'svc_acct',
-  'desc'      => 'Google hosted mail',
-  'options'   => \%options,
-  'nodomain'  => 'Y',
+  'svc'        => 'svc_acct',
+  'desc'       => 'Google hosted mail',
+  'options'    => \%options,
+  'nodomain'   => 'Y',
+  'no_machine' => 1,
+  'default_svc_class' => 'Email',
   'notes'    => <<'END'
 Export accounts to the Google Provisioning API.  Requires 
 REST::Google::Apps::Provisioning from CPAN.
   'notes'    => <<'END'
 Export accounts to the Google Provisioning API.  Requires 
 REST::Google::Apps::Provisioning from CPAN.
index b4c64ac..23df7b3 100644 (file)
@@ -51,6 +51,7 @@ tie %options, 'Tie::IxHash',
   'svc'     => 'svc_acct',
   'desc'    => 'Send an HTTP or HTTPS GET or POST request, for accounts.',
   'options' => \%options,
   'svc'     => 'svc_acct',
   'desc'    => 'Send an HTTP or HTTPS GET or POST request, for accounts.',
   'options' => \%options,
+  'no_machine' => 1,
   'notes'   => <<'END'
 Send an HTTP or HTTPS GET or POST to the specified URL on account addition,
 modification and deletion.  For HTTPS support,
   'notes'   => <<'END'
 Send an HTTP or HTTPS GET or POST to the specified URL on account addition,
 modification and deletion.  For HTTPS support,
index d8d70a3..50b6fae 100644 (file)
@@ -15,9 +15,11 @@ tie my %options, 'Tie::IxHash',
 ;
 
 %info = (
 ;
 
 %info = (
-  'svc'    => 'svc_acct',
-  'desc'   => 'Real-time export to Plesk managed mail service',
-  'options'=> \%options,
+  'svc'        => 'svc_acct',
+  'desc'       => 'Real-time export to Plesk managed mail service',
+  'options'    => \%options,
+  'no_machine' => 1,
+  'default_svc_class' => 'Email',
   'notes'  => <<'END'
 Real-time export to
 <a href="http://www.swsoft.com/">Plesk</a> managed server.
   'notes'  => <<'END'
 Real-time export to
 <a href="http://www.swsoft.com/">Plesk</a> managed server.
index ffe39ca..8163f20 100644 (file)
@@ -60,11 +60,13 @@ my $postfix_native_mailbox_map =
                  keys %postfix_native_mailbox_map      );
 
 %info = (
                  keys %postfix_native_mailbox_map      );
 
 %info = (
-  'svc'      => 'svc_acct',
-  'desc'     => 'Real-time export of accounts to SQL databases '.
-                '(vpopmail, Postfix+Courier IMAP, others?)',
-  'options'  => \%options,
-  'nodomain' => '',
+  'svc'        => 'svc_acct',
+  'desc'       => 'Real-time export of accounts to SQL databases '.
+                  '(vpopmail, Postfix+Courier IMAP, others?)',
+  'options'    => \%options,
+  'nodomain'   => '',
+  'no_machine' => 1,
+  'default_svc_class' => 'Email',
   'notes'    => <<END
 Export accounts (svc_acct records) to SQL databases.  Currently has default
 configurations for vpopmail and Postfix+Courier IMAP but intended to be
   'notes'    => <<END
 Export accounts (svc_acct records) to SQL databases.  Currently has default
 configurations for vpopmail and Postfix+Courier IMAP but intended to be
index e6aeb20..248105f 100644 (file)
@@ -14,6 +14,7 @@ delete $options{$_} for qw( table schema static primary_key );
   'desc'     => 'Mailbox status information from SQL',
   'options'  => \%options,
   'nodomain' => '',
   'desc'     => 'Mailbox status information from SQL',
   'options'  => \%options,
   'nodomain' => '',
+  'no_machine' => 1,
   'notes'    => <<END
 Read mailbox status information (vacation and spam settings) from an SQL
 database, tables "vacation" and "users" respectively.
   'notes'    => <<END
 Read mailbox status information (vacation and spam settings) from an SQL
 database, tables "vacation" and "users" respectively.
index 96ad1fa..3070f28 100644 (file)
@@ -34,6 +34,7 @@ tie my %options, 'Tie::IxHash',
   'svc'     => 'svc_acct',
   'desc'    => 'Configurable provisioning of accounts via the XML-RPC protocol',
   'options' => \%options,
   'svc'     => 'svc_acct',
   'desc'    => 'Configurable provisioning of accounts via the XML-RPC protocol',
   'options' => \%options,
+  'no_machine' => 1,
   'notes'   => <<'END',
 Configurable, real-time export of accounts via the XML-RPC protocol.<BR>
 <BR>
   'notes'   => <<'END',
 Configurable, real-time export of accounts via the XML-RPC protocol.<BR>
 <BR>
index 0e65ca0..06e2c23 100644 (file)
@@ -20,6 +20,7 @@ tie my %options, 'Tie::IxHash',
   'desc'     =>
     'Export to Amazon EC2',
   'options'  => \%options,
   'desc'     =>
     'Export to Amazon EC2',
   'options'  => \%options,
+  'no_machine' => 1,
   'notes'    => <<'END'
 Create instances in the Amazon EC2 (Elastic compute cloud).  Install
 Net::Amazon::EC2 perl module.  Advisable to set svc_external-skip_manual config
   'notes'    => <<'END'
 Create instances in the Amazon EC2 (Elastic compute cloud).  Install
 Net::Amazon::EC2 perl module.  Advisable to set svc_external-skip_manual config
index c006db9..e22bbf2 100644 (file)
@@ -37,6 +37,7 @@ tie my %options, 'Tie::IxHash',
     'Real-time export to Artera Turbo Reseller API',
   'options'  => \%options,
   #'nodomain' => 'Y',
     'Real-time export to Artera Turbo Reseller API',
   'options'  => \%options,
   #'nodomain' => 'Y',
+  'no_machine' => 1,
   'notes'    => <<'END'
 Real-time export to <a href="http://www.arteraturbo.com/">Artera Turbo</a>
 Reseller API.  Requires installation of
   'notes'    => <<'END'
 Real-time export to <a href="http://www.arteraturbo.com/">Artera Turbo</a>
 Reseller API.  Requires installation of
index 9edfee5..c1ed7fc 100644 (file)
@@ -45,6 +45,7 @@ tie %options, 'Tie::IxHash',
   'svc'     => 'svc_broadband',
   'desc'    => 'Send an HTTP or HTTPS GET or POST request, for accounts.',
   'options' => \%options,
   'svc'     => 'svc_broadband',
   'desc'    => 'Send an HTTP or HTTPS GET or POST request, for accounts.',
   'options' => \%options,
+  'no_machine' => 1,
   'notes'   => <<'END'
 <p>Send an HTTP or HTTPS GET or POST to the specified URL on account addition,
 modification and deletion.  For HTTPS support,
   'notes'   => <<'END'
 <p>Send an HTTP or HTTPS GET or POST to the specified URL on account addition,
 modification and deletion.  For HTTPS support,
index a160c99..5a8ffac 100644 (file)
@@ -43,6 +43,7 @@ FS::UID->install_callback(
   'svc'     => 'svc_broadband',
   'desc'    => 'Create a NAS entry in Freeside',
   'options' => \%options,
   'svc'     => 'svc_broadband',
   'desc'    => 'Create a NAS entry in Freeside',
   'options' => \%options,
+  'no_machine' => 1,
   'weight'  => 10,
   'notes'   => <<'END'
 <p>Create an entry in the NAS (RADIUS client) table, inheriting the IP 
   'weight'  => 10,
   'notes'   => <<'END'
 <p>Create an entry in the NAS (RADIUS client) table, inheriting the IP 
index c7f0fbb..cf9c36c 100644 (file)
@@ -107,3 +107,4 @@ sub ssh_cmd { #subroutine, not method
   '';
 }
 
   '';
 }
 
+1;
index cb1740e..44b4dba 100644 (file)
@@ -52,6 +52,7 @@ tie my %options, 'Tie::IxHash',
   'svc'     => 'svc_broadband',
   'desc'    => 'Send SNMP requests to the service IP address',
   'options' => \%options,
   'svc'     => 'svc_broadband',
   'desc'    => 'Send SNMP requests to the service IP address',
   'options' => \%options,
+  'no_machine' => 1,
   'weight'  => 10,
   'notes'   => <<'END'
 Send one or more SNMP SET requests to the IP address registered to the service.
   'weight'  => 10,
   'notes'   => <<'END'
 Send one or more SNMP SET requests to the IP address registered to the service.
index 697d3cd..4f526c8 100644 (file)
@@ -24,6 +24,7 @@ tie my %options, 'Tie::IxHash',
   'desc'     => 'Real-time export of broadband services to SQL databases ',
   'options'  => \%options,
   'nodomain' => '',
   'desc'     => 'Real-time export of broadband services to SQL databases ',
   'options'  => \%options,
   'nodomain' => '',
+  'no_machine' => 1,
   'notes'    => <<END
 END
 );
   'notes'    => <<END
 END
 );
index 5806362..b5d1a80 100644 (file)
@@ -55,6 +55,7 @@ tie %options, 'Tie::IxHash',
   'svc'      => 'svc_broadband',
   'desc'     => 'Real-time export to SQL-backed RADIUS (such as FreeRadius) for broadband services',
   'options'  => \%options,
   'svc'      => 'svc_broadband',
   'desc'     => 'Real-time export to SQL-backed RADIUS (such as FreeRadius) for broadband services',
   'options'  => \%options,
+  'no_machine' => 1,
   'nas'      => 'Y',
   'notes'    => <<END,
 Real-time export of <b>radcheck</b>, <b>radreply</b>, and <b>usergroup</b> 
   'nas'      => 'Y',
   'notes'    => <<END,
 Real-time export of <b>radcheck</b>, <b>radreply</b>, and <b>usergroup</b> 
index a3ec5e0..8b66225 100644 (file)
@@ -36,6 +36,7 @@ tie %options, 'Tie::IxHash',
   'svc'     => [qw( svc_acct svc_domain svc_forward svc_mailinglist )],
   'desc'    => 'Real-time export of accounts, domains, mail forwards and mailing lists to a CommuniGate Pro mail server',
   'options' => \%options,
   'svc'     => [qw( svc_acct svc_domain svc_forward svc_mailinglist )],
   'desc'    => 'Real-time export of accounts, domains, mail forwards and mailing lists to a CommuniGate Pro mail server',
   'options' => \%options,
+  'default_svc_class' => 'Email',
   'notes'   => <<'END'
 Real time export of accounts, domains, mail forwards and mailing lists to a
 <a href="http://www.stalker.com/CommuniGatePro/">CommuniGate Pro</a>
   'notes'   => <<'END'
 Real time export of accounts, domains, mail forwards and mailing lists to a
 <a href="http://www.stalker.com/CommuniGatePro/">CommuniGate Pro</a>
index e25043f..cecea28 100644 (file)
@@ -16,6 +16,7 @@ tie my %options, 'Tie::IxHash', %FS::part_export::communigate_pro::options,
     'Real-time export to a CommuniGate Pro mail server, one domain only',
   'options'  => \%options,
   'nodomain' => 'Y',
     'Real-time export to a CommuniGate Pro mail server, one domain only',
   'options'  => \%options,
   'nodomain' => 'Y',
+  'default_svc_class' => 'Email',
   'notes'    => <<'END'
 Real time export to a
 <a href="http://www.stalker.com/CommuniGatePro/">CommuniGate Pro</a>
   'notes'    => <<'END'
 Real time export to a
 <a href="http://www.stalker.com/CommuniGatePro/">CommuniGate Pro</a>
index 96fa437..2ae97e1 100644 (file)
@@ -18,6 +18,7 @@ tie my %options, 'Tie::IxHash',
   'svc'    => 'svc_acct',
   'desc'   => 'Real-time export to Critical Path Account Provisioning Protocol',
   'options'=> \%options,
   'svc'    => 'svc_acct',
   'desc'   => 'Real-time export to Critical Path Account Provisioning Protocol',
   'options'=> \%options,
+  'default_svc_class' => 'Email',
   'notes'  => <<'END'
 Real-time export to
 <a href="http://www.cp.net/">Critial Path Account Provisioning Protocol</a>.
   'notes'  => <<'END'
 Real-time export to
 <a href="http://www.cp.net/">Critial Path Account Provisioning Protocol</a>.
index 0ad00df..6c61e3d 100644 (file)
@@ -190,3 +190,5 @@ sub cpanel_connect {
 
   $whm;
 }
 
   $whm;
 }
+
+1;
index e8b677b..e834f93 100644 (file)
@@ -55,6 +55,7 @@ tie %options, 'Tie::IxHash',
   'svc'     => 'cust_main',
   'desc'    => 'Send an HTTP or HTTPS GET or POST request, for customers.',
   'options' => \%options,
   'svc'     => 'cust_main',
   'desc'    => 'Send an HTTP or HTTPS GET or POST request, for customers.',
   'options' => \%options,
+  'no_machine' => 1,
   'notes'   => <<'END'
 Send an HTTP or HTTPS GET or POST to the specified URL on customer addition,
 modification and deletion.  For HTTPS support,
   'notes'   => <<'END'
 Send an HTTP or HTTPS GET or POST to the specified URL on customer addition,
 modification and deletion.  For HTTPS support,
index 84c9e5a..246d5b3 100644 (file)
@@ -17,6 +17,8 @@ tie my %options, 'Tie::IxHash',
   'desc'     => 'Real-time export to Cyrus IMAP server',
   'options'  => \%options,
   'nodomain' => 'Y',
   'desc'     => 'Real-time export to Cyrus IMAP server',
   'options'  => \%options,
   'nodomain' => 'Y',
+  'no_machine' => 1, #de facto... but "server" option should move to it
+  'default_svc_class' => 'Email',
   'notes'    => <<'END'
 Integration with
 <a href="http://asg.web.cmu.edu/cyrus/imapd/">Cyrus IMAP Server</a>.
   'notes'    => <<'END'
 Integration with
 <a href="http://asg.web.cmu.edu/cyrus/imapd/">Cyrus IMAP Server</a>.
index 320d0a6..2717233 100644 (file)
@@ -20,6 +20,7 @@ tie my %options, 'Tie::IxHash',
   'svc'     => 'svc_phone',
   'desc'    => 'Provision e911 services via Dash Carrier Services',
   'notes'   => 'Provision e911 services via Dash Carrier Services',
   'svc'     => 'svc_phone',
   'desc'    => 'Provision e911 services via Dash Carrier Services',
   'notes'   => 'Provision e911 services via Dash Carrier Services',
+  'no_machine' => 1,
   'options' => \%options,
 );
 
   'options' => \%options,
 );
 
index 0749fec..ff0d949 100644 (file)
@@ -26,6 +26,7 @@ my $postfix_transport_static =
   'desc'    => 'Real time export of domains to SQL databases '.
                '(postfix, others?)',
   'options' => \%options,
   'desc'    => 'Real time export of domains to SQL databases '.
                '(postfix, others?)',
   'options' => \%options,
+  'no_machine' => 1,
   'notes'   => <<END
 Export domains (svc_domain records) to SQL databases.  Currently this is a
 simple export with a default for Postfix, but it can be extended for other
   'notes'   => <<END
 Export domains (svc_domain records) to SQL databases.  Currently this is a
 simple export with a default for Postfix, but it can be extended for other
index 0fd32fa..7386973 100644 (file)
@@ -18,6 +18,8 @@ tie my %options, 'Tie::IxHash',
   'svc'    => 'svc_acct',
   'desc'   => 'Real-time export to Everyone.net outsourced mail service',
   'options'=> \%options,
   'svc'    => 'svc_acct',
   'desc'   => 'Real-time export to Everyone.net outsourced mail service',
   'options'=> \%options,
+  'no_machine' => 1,
+  'default_svc_class' => 'Email',
   'notes'  => <<'END'
 Real-time export to
 <a href="http://www.everyone.net/">Everyone.net</a> via the XRC Remote API.
   'notes'  => <<'END'
 Real-time export to
 <a href="http://www.everyone.net/">Everyone.net</a> via the XRC Remote API.
index d171eb1..9f454df 100644 (file)
@@ -34,6 +34,7 @@ tie my %options, 'Tie::IxHash',
   'svc'     => 'svc_external',
   'desc'    => 'Purchase EZ-Prepaid PIN',
   'options' => \%options,
   'svc'     => 'svc_external',
   'desc'    => 'Purchase EZ-Prepaid PIN',
   'options' => \%options,
+  'no_machine' => 1,
   'notes'   => <<'END'
 <P>Export to the EZ-Prepaid PIN purchase service.  If the purchase is allowed,
 the PIN will be stored as svc_external.id.</P>
   'notes'   => <<'END'
 <P>Export to the EZ-Prepaid PIN purchase service.  If the purchase is allowed,
 the PIN will be stored as svc_external.id.</P>
index 563efcc..eb41378 100644 (file)
@@ -10,6 +10,7 @@ use FS::Record;
   'desc'     => 'Real-time export of forwards to SQL databases ',
                 #.' (vpopmail, Postfix+Courier IMAP, others?)',
   'options'  => __PACKAGE__->sql_options,
   'desc'     => 'Real-time export of forwards to SQL databases ',
                 #.' (vpopmail, Postfix+Courier IMAP, others?)',
   'options'  => __PACKAGE__->sql_options,
+  'no_machine' => 1,
   'notes'    => <<END
 Export mail forwards (svc_forward records) to SQL databases.
 
   'notes'    => <<END
 Export mail forwards (svc_forward records) to SQL databases.
 
index 6df21f4..9fe45ba 100644 (file)
@@ -19,6 +19,7 @@ tie my %options, 'Tie::IxHash',
   'svc'     => 'svc_phone',
   'desc'    => 'Provision phone numbers to VoIP Innovations (formerly GlobalPOPs VoIP)',
   'options' => \%options,
   'svc'     => 'svc_phone',
   'desc'    => 'Provision phone numbers to VoIP Innovations (formerly GlobalPOPs VoIP)',
   'options' => \%options,
+  'no_machine' => 1,
   'notes'   => <<'END'
 Requires installation of
 <a href="http://search.cpan.org/dist/Net-GlobalPOPs-MediaServicesAPI">Net::GlobalPOPs::MediaServicesAPI</a>
   'notes'   => <<'END'
 Requires installation of
 <a href="http://search.cpan.org/dist/Net-GlobalPOPs-MediaServicesAPI">Net::GlobalPOPs::MediaServicesAPI</a>
index 3749224..c35c89f 100644 (file)
@@ -43,6 +43,7 @@ tie %options, 'Tie::IxHash',
   'svc'     => 'svc_domain',
   'desc'    => 'Send an HTTP or HTTPS GET or POST request',
   'options' => \%options,
   'svc'     => 'svc_domain',
   'desc'    => 'Send an HTTP or HTTPS GET or POST request',
   'options' => \%options,
+  'no_machine' => 1,
   'notes'   => <<'END'
 Send an HTTP or HTTPS GET or POST to the specified URL.  For HTTPS support,
 <a href="http://search.cpan.org/dist/Crypt-SSLeay">Crypt::SSLeay</a>
   'notes'   => <<'END'
 Send an HTTP or HTTPS GET or POST to the specified URL.  For HTTPS support,
 <a href="http://search.cpan.org/dist/Crypt-SSLeay">Crypt::SSLeay</a>
index 5342106..6fbd3fb 100644 (file)
@@ -17,6 +17,7 @@ tie my %options, 'Tie::IxHash',
   'svc'     => 'svc_dsl',
   'desc'    => 'Retrieve status information via HTTP or HTTPS',
   'options' => \%options,
   'svc'     => 'svc_dsl',
   'desc'    => 'Retrieve status information via HTTP or HTTPS',
   'options' => \%options,
+  'no_machine' => 1,
   'notes'   => <<'END'
 Fields from the service can be substituted in the URL as $field.
 END
   'notes'   => <<'END'
 Fields from the service can be substituted in the URL as $field.
 END
index eedc9d0..23917bf 100644 (file)
@@ -31,6 +31,7 @@ tie my %options, 'Tie::IxHash',
   'svc'     => 'svc_dsl',
   'desc'    => 'Provision DSL to Ikano',
   'options' => \%options,
   'svc'     => 'svc_dsl',
   'desc'    => 'Provision DSL to Ikano',
   'options' => \%options,
+  'no_machine' => 1,
   'notes'   => <<'END'
 Requires installation of
 <a href="http://search.cpan.org/dist/Net-Ikano">Net::Ikano</a> from CPAN.
   'notes'   => <<'END'
 Requires installation of
 <a href="http://search.cpan.org/dist/Net-Ikano">Net::Ikano</a> from CPAN.
index b573401..02ae5ef 100644 (file)
@@ -17,6 +17,7 @@ tie my %options, 'Tie::IxHash',
   'desc'     =>
     'Export conferences to the Indosoft Conference Bridge',
   'options'  => \%options,
   'desc'     =>
     'Export conferences to the Indosoft Conference Bridge',
   'options'  => \%options,
+  'no_machine' => 1,
   'notes'    => <<'END'
 Export conferences to the Indosoft conference bridge.
 Net::Indosoft::Voicebridge is required.
   'notes'    => <<'END'
 Export conferences to the Indosoft conference bridge.
 Net::Indosoft::Voicebridge is required.
index ef16c7c..51f5760 100644 (file)
@@ -19,6 +19,7 @@ tie my %options, 'Tie::IxHash',
   'desc'     => 'Real-time export to InfoStreet streetSmartAPI',
   'options'  => \%options,
   'nodomain' => 'Y',
   'desc'     => 'Real-time export to InfoStreet streetSmartAPI',
   'options'  => \%options,
   'nodomain' => 'Y',
+  'no_machine' => 1,
   'notes'    => <<'END'
 Real-time export to
 <a href="http://www.infostreet.com/">InfoStreet</a> streetSmartAPI.
   'notes'    => <<'END'
 Real-time export to
 <a href="http://www.infostreet.com/">InfoStreet</a> streetSmartAPI.
index a94e43e..b51f631 100644 (file)
@@ -17,6 +17,7 @@ tie my %options, 'Tie::IxHash',
   'desc'    => 'Provision phone numbers from the internal DID database',
   'notes'   => 'After adding the export, DIDs may be imported under Tools -> Importing -> Import phone numbers (DIDs)',
   'options' => \%options,
   'desc'    => 'Provision phone numbers from the internal DID database',
   'notes'   => 'After adding the export, DIDs may be imported under Tools -> Importing -> Import phone numbers (DIDs)',
   'options' => \%options,
+  'no_machine' => 1,
 );
 
 sub rebless { shift; }
 );
 
 sub rebless { shift; }
index 8385320..fe634d2 100644 (file)
@@ -41,6 +41,7 @@ tie my %options, 'Tie::IxHash',
   'svc'     => 'svc_acct',
   'desc'    => 'Real-time export to LDAP',
   'options' => \%options,
   'svc'     => 'svc_acct',
   'desc'    => 'Real-time export to LDAP',
   'options' => \%options,
+  'default_svc_class' => 'Email',
   'notes'   => <<'END'
 Real-time export to arbitrary LDAP attributes.  Requires installation of
 <a href="http://search.cpan.org/dist/Net-LDAP">Net::LDAP</a> from CPAN.
   'notes'   => <<'END'
 Real-time export to arbitrary LDAP attributes.  Requires installation of
 <a href="http://search.cpan.org/dist/Net-LDAP">Net::LDAP</a> from CPAN.
index 6e2ee8a..2e37d04 100644 (file)
@@ -72,10 +72,11 @@ tie my %options, 'Tie::IxHash',
 ;
 
 %info = (
 ;
 
 %info = (
-  'svc'      => [ 'svc_phone', ], # 'part_device',
-  'desc'     => 'Provision phone numbers to NetSapiens',
-  'options'  => \%options,
-  'notes'    => <<'END'
+  'svc'        => [ 'svc_phone', ], # 'part_device',
+  'desc'       => 'Provision phone numbers to NetSapiens',
+  'options'    => \%options,
+  'no_machine' => 1,
+  'notes'      => <<'END'
 Requires installation of
 <a href="http://search.cpan.org/dist/REST-Client">REST::Client</a>
 from CPAN.
 Requires installation of
 <a href="http://search.cpan.org/dist/REST-Client">REST::Client</a>
 from CPAN.
index 0145af3..3a76488 100644 (file)
@@ -11,3 +11,4 @@ sub _export_insert {}
 sub _export_replace {}
 sub _export_delete {}
 
 sub _export_replace {}
 sub _export_delete {}
 
+1;
index 040af27..5c1ae01 100644 (file)
@@ -138,3 +138,4 @@ sub ssh_cmd { #subroutine, not method
   &Net::SSH::ssh_cmd( { @_ } );
 }
 
   &Net::SSH::ssh_cmd( { @_ } );
 }
 
+1;
index 3d01c16..7b07ecf 100644 (file)
@@ -21,10 +21,11 @@ tie %options, 'Tie::IxHash',
 ;
 
 %info = (
 ;
 
 %info = (
-  'svc'      => 'svc_phone',
-  'desc'     => 'Export DIDs to OpenSIPs dr_rules table',
-  'options'  => \%options,
-  'notes'    => 'Export DIDs to OpenSIPs dr_rules table',
+  'svc'        => 'svc_phone',
+  'desc'       => 'Export DIDs to OpenSIPs dr_rules table',
+  'options'    => \%options,
+  'no_machine' => 1,
+  'notes'      => 'Export DIDs to OpenSIPs dr_rules table',
 );
 
 sub rebless { shift; }
 );
 
 sub rebless { shift; }
@@ -93,3 +94,4 @@ sub dr_reload {
     '';
 }
 
     '';
 }
 
+1;
index 6b14bed..46c372c 100644 (file)
@@ -39,10 +39,11 @@ tie %options, 'Tie::IxHash',
 ;
 
 %info = (
 ;
 
 %info = (
-  'svc'      => 'svc_phone',
-  'desc'     => 'Real-time export to SQL-backed RADIUS (FreeRADIUS, ICRADIUS) for phone provisioning and rating',
-  'options'  => \%options,
-  'notes'    => <<END,
+  'svc'        => 'svc_phone',
+  'desc'       => 'Real-time export to SQL-backed RADIUS (FreeRADIUS, ICRADIUS) for phone provisioning and rating',
+  'options'    => \%options,
+  'no_machine' => 1,
+  'notes'      => <<END,
 Real-time export of <b>radcheck</b> table
 to any SQL database for <a href="http://www.freeradius.org/">FreeRADIUS</a>
 or <a href="http://radius.innercite.com/">ICRADIUS</a>.
 Real-time export of <b>radcheck</b> table
 to any SQL database for <a href="http://www.freeradius.org/">FreeRADIUS</a>
 or <a href="http://radius.innercite.com/">ICRADIUS</a>.
index 4fd19ee..9a8d617 100644 (file)
@@ -22,6 +22,7 @@ tie my %options, 'Tie::IxHash',
   'svc'     => 'svc_forward',
   'desc'    => 'Postfix text files',
   'options' => \%options,
   'svc'     => 'svc_forward',
   'desc'    => 'Postfix text files',
   'options' => \%options,
+  'default_svc_class' => 'Email',
   'notes'   => <<'END'
 Batch export of Postfix aliases and virtual files.
 <a href="http://search.cpan.org/dist/File-Rsync">File::Rsync</a>
   'notes'   => <<'END'
 Batch export of Postfix aliases and virtual files.
 <a href="http://search.cpan.org/dist/File-Rsync">File::Rsync</a>
index 02e89c6..9964489 100644 (file)
@@ -79,11 +79,12 @@ possibly harmful.
 EOT
 
 %info = (
 EOT
 
 %info = (
-  'svc'      => 'svc_broadband',
-  'desc'     => 'Real-time export to Northbound Interface',
-  'options'  => \%options,
-  'nodomain' => 'Y',
-  'notes'    => $notes,
+  'svc'        => 'svc_broadband',
+  'desc'       => 'Real-time export to Northbound Interface',
+  'options'    => \%options,
+  'nodomain'   => 'Y',
+  'no_machine' => 1,
+  'notes'      => $notes,
 );
 
 sub prizm_command {
 );
 
 sub prizm_command {
index 2ac3edb..f09d36a 100644 (file)
@@ -11,6 +11,8 @@ tie my %options, 'Tie::IxHash', %FS::part_export::sqlradius::options;
   'desc'     => 'Real-time export to RADIATOR',
   'options'  => \%options,
   'nodomain' => '',
   'desc'     => 'Real-time export to RADIATOR',
   'options'  => \%options,
   'nodomain' => '',
+  'no_machine' => 1,
+  'default_svc_class' => 'Internet',
   'notes' => <<'END',
 Real-time export of the <b>radusers</b> table to any SQL database in
 <a href="http://www.open.com.au/radiator/">Radiator</a>-native format.
   'notes' => <<'END',
 Real-time export of the <b>radusers</b> table to any SQL database in
 <a href="http://www.open.com.au/radiator/">Radiator</a>-native format.
index 6a1d676..3071ece 100644 (file)
@@ -87,6 +87,7 @@ tie my %options, 'Tie::IxHash',
   'svc'     => 'svc_broadband',
   'desc'    => 'Send a command to a router.',
   'options' => \%options,
   'svc'     => 'svc_broadband',
   'desc'    => 'Send a command to a router.',
   'options' => \%options,
+  'no_machine' => 1,
   'notes'   => 'Installation of Net::Telnet from CPAN is required for telnet connections.  This export will execute if the following virtual fields are set on the router: admin_user, admin_password, admin_address, admin_timeout, admin_prompt.  Option virtual fields are: admin_cmd_insert, admin_cmd_replace, admin_cmd_delete, admin_cmd_suspend, admin_cmd_unsuspend.  See the module documentation for a full list of required/supported router virtual fields.',
 );
 
   'notes'   => 'Installation of Net::Telnet from CPAN is required for telnet connections.  This export will execute if the following virtual fields are set on the router: admin_user, admin_password, admin_address, admin_timeout, admin_prompt.  Option virtual fields are: admin_cmd_insert, admin_cmd_replace, admin_cmd_delete, admin_cmd_suspend, admin_cmd_unsuspend.  See the module documentation for a full list of required/supported router virtual fields.',
 );
 
index b53b7da..7ae6105 100644 (file)
@@ -127,6 +127,7 @@ tie my %options, 'Tie::IxHash', (
   'Create an RT ticket',
   'options'  => \%options,
   'nodomain' => '',
   'Create an RT ticket',
   'options'  => \%options,
   'nodomain' => '',
+  'no_machine' => 1,
   'notes'    => ' 
   Create a ticket in RT.  The subject and body of the ticket 
   will be generated from a message template.'
   'notes'    => ' 
   Create a ticket in RT.  The subject and body of the ticket 
   will be generated from a message template.'
index 05f6236..6ba131f 100644 (file)
@@ -85,6 +85,7 @@ tie my %options, 'Tie::IxHash', (
   'Send an email message',
   'options'  => \%options,
   'nodomain' => '',
   'Send an email message',
   'options'  => \%options,
   'nodomain' => '',
+  'no_machine' => 1,
   'notes'    => ' 
   Send an email message.  The subject and body of the message
   will be generated from a message template.'
   'notes'    => ' 
   Send an email message.  The subject and body of the message
   will be generated from a message template.'
index 20e9091..b9d6551 100644 (file)
@@ -97,12 +97,13 @@ tie my %options, 'Tie::IxHash',
 ;
 
 %info = (
 ;
 
 %info = (
-  'svc'      => 'svc_acct',
-  'desc'     =>
+  'svc'         => 'svc_acct',
+  'desc'        =>
     'Real-time export via remote SSH (i.e. useradd, userdel, etc.)',
     'Real-time export via remote SSH (i.e. useradd, userdel, etc.)',
-  'options'  => \%options,
-  'nodomain' => 'Y',
-  'notes' => <<'END'
+  'options'     => \%options,
+  'nodomain'    => 'Y',
+  'svc_machine' => 1,
+  'notes'       => <<'END'
 Run remote commands via SSH.  Usernames are considered unique (also see
 shellcommands_withdomain).  You probably want this if the commands you are
 running will not accept a domain as a parameter.  You will need to
 Run remote commands via SSH.  Usernames are considered unique (also see
 shellcommands_withdomain).  You probably want this if the commands you are
 running will not accept a domain as a parameter.  You will need to
@@ -124,24 +125,7 @@ running will not accept a domain as a parameter.  You will need to
       this.form.unsuspend_stdin.value="";
     '>
   <LI>
       this.form.unsuspend_stdin.value="";
     '>
   <LI>
-    <INPUT TYPE="button" VALUE="FreeBSD before 4.10 / 5.3" onClick='
-      this.form.useradd.value = "lockf /etc/passwd.lock pw useradd $username -d $dir -m -s $shell -u $uid -c $finger -h 0";
-      this.form.useradd_stdin.value = "$_password\n";
-      this.form.userdel.value = "lockf /etc/passwd.lock pw userdel $username -r"; this.form.userdel_stdin.value="";
-      this.form.usermod.value = "lockf /etc/passwd.lock pw usermod $old_username -d $new_dir -m -l $new_username -s $new_shell -u $new_uid -g $new_gid -c $new_finger -h 0";
-      this.form.usermod_stdin.value = "$new__password\n"; this.form.suspend.value = "lockf /etc/passwd.lock pw lock $username";
-      this.form.suspend_stdin.value="";
-      this.form.unsuspend.value = "lockf /etc/passwd.lock pw unlock $username"; this.form.unsuspend_stdin.value="";
-    '>
-    Note: On FreeBSD versions before 5.3 and 4.10 (4.10 is after 4.9, not
-    4.1!), due to deficient locking in pw(1), you must disable the chpass(1),
-    chsh(1), chfn(1), passwd(1), and vipw(1) commands, or replace them with
-    wrappers that prepend "lockf /etc/passwd.lock".  Alternatively, apply the
-    patch in
-    <A HREF="http://www.freebsd.org/cgi/query-pr.cgi?pr=23501">FreeBSD PR#23501</A>
-    and use the "FreeBSD 4.10 / 5.3 or later" button below.
-  <LI>
-    <INPUT TYPE="button" VALUE="FreeBSD 4.10 / 5.3 or later" onClick='
+    <INPUT TYPE="button" VALUE="FreeBSD" onClick='
       this.form.useradd.value = "pw useradd $username -d $dir -m -s $shell -u $uid -g $gid -c $finger -h 0";
       this.form.useradd_stdin.value = "$_password\n";
       this.form.userdel.value = "pw userdel $username -r";
       this.form.useradd.value = "pw useradd $username -d $dir -m -s $shell -u $uid -g $gid -c $finger -h 0";
       this.form.useradd_stdin.value = "$_password\n";
       this.form.userdel.value = "pw userdel $username -r";
index cbdaf7f..19505b4 100644 (file)
@@ -37,6 +37,7 @@ tie my %options, 'Tie::IxHash',
   'desc'     => 'Real-time export to SQL-backed mail server',
   'options'  => \%options,
   'nodomain' => '',
   'desc'     => 'Real-time export to SQL-backed mail server',
   'options'  => \%options,
   'nodomain' => '',
+  'default_svc_class' => 'Email',
   'notes'    => <<'END'
 Database schema can be made to work with Courier IMAP, Exim and Dovecot.
 Others could work but are untested.  (more detailed description from
   'notes'    => <<'END'
 Database schema can be made to work with Courier IMAP, Exim and Dovecot.
 Others could work but are untested.  (more detailed description from
index 7213966..6760d09 100644 (file)
@@ -110,6 +110,7 @@ END
   'desc'     => 'Real-time export to SQL-backed RADIUS (FreeRADIUS, ICRADIUS)',
   'options'  => \%options,
   'nodomain' => 'Y',
   'desc'     => 'Real-time export to SQL-backed RADIUS (FreeRADIUS, ICRADIUS)',
   'options'  => \%options,
   'nodomain' => 'Y',
+  'no_machine' => 1,
   'nas'      => 'Y', # show export_nas selection in UI
   'default_svc_class' => 'Internet',
   'notes'    => $notes1.
   'nas'      => 'Y', # show export_nas selection in UI
   'default_svc_class' => 'Internet',
   'notes'    => $notes1.
index 869c7c7..07de875 100644 (file)
@@ -18,6 +18,7 @@ tie my %options, 'Tie::IxHash',
   'desc'    =>
     'Real-time export to a text /etc/raddb/users file (Livingston, Cistron)',
   'options' => \%options,
   'desc'    =>
     'Real-time export to a text /etc/raddb/users file (Livingston, Cistron)',
   'options' => \%options,
+  'default_svc_class' => 'Internet',
   'notes'   => <<'END'
 This will edit a text RADIUS users file in place on a remote server.
 Requires installation of
   'notes'   => <<'END'
 This will edit a text RADIUS users file in place on a remote server.
 Requires installation of
index e7f1126..64d2cc4 100644 (file)
@@ -68,6 +68,7 @@ tie my %options, 'Tie::IxHash', (
   'svc'     => 'svc_broadband',
   'desc'    => 'Sends SNMP SETs to a Trango AP.',
   'options' => \%options,
   'svc'     => 'svc_broadband',
   'desc'    => 'Sends SNMP SETs to a Trango AP.',
   'options' => \%options,
+  'no_machine' => 1,
   'notes'   => 'Requires Net::SNMP.  See the documentation for FS::part_export::trango for required virtual fields and usage information.',
 );
 
   'notes'   => 'Requires Net::SNMP.  See the documentation for FS::part_export::trango for required virtual fields and usage information.',
 );
 
index 12c3a7f..350a5ad 100644 (file)
@@ -26,6 +26,7 @@ tie my %options, 'Tie::IxHash',
   'svc'     => 'svc_phone',
   'desc'    => 'Provision phone numbers to Vitelity',
   'options' => \%options,
   'svc'     => 'svc_phone',
   'desc'    => 'Provision phone numbers to Vitelity',
   'options' => \%options,
+  'no_machine' => 1,
   'notes'   => <<'END'
 Requires installation of
 <a href="http://search.cpan.org/dist/Net-Vitelity">Net::Vitelity</a>
   'notes'   => <<'END'
 Requires installation of
 <a href="http://search.cpan.org/dist/Net-Vitelity">Net::Vitelity</a>
index 799a8e1..5fca170 100644 (file)
@@ -23,6 +23,7 @@ tie my %options, 'Tie::IxHash',
   'svc'     => 'svc_acct',
   'desc'    => 'Real-time export to vpopmail text files',
   'options' => \%options,
   'svc'     => 'svc_acct',
   'desc'    => 'Real-time export to vpopmail text files',
   'options' => \%options,
+  'default_svc_class' => 'Email',
   'notes'   => <<'END'
 This export is currently unmaintained.  See shellcommands_withdomain for an
 export that uses vpopmail CLI commands instead.<BR>
   'notes'   => <<'END'
 This export is currently unmaintained.  See shellcommands_withdomain for an
 export that uses vpopmail CLI commands instead.<BR>
index ccf9b3e..a247f05 100644 (file)
@@ -18,10 +18,11 @@ tie my %options, 'Tie::IxHash',
 ;
 
 %info = (
 ;
 
 %info = (
-  'svc'    => 'svc_www',
-  'desc'   => 'Real-time export to Plesk managed hosting service',
-  'options'=> \%options,
-  'notes'  => <<'END'
+  'svc'        => 'svc_www',
+  'desc'       => 'Real-time export to Plesk managed hosting service',
+  'options'    => \%options,
+  'no_machine' => 1,
+  'notes'      => <<'END'
 Real-time export to
 <a href="http://www.swsoft.com/">Plesk</a> managed server.
 Requires installation of
 Real-time export to
 <a href="http://www.swsoft.com/">Plesk</a> managed server.
 Requires installation of
index d6116ab..bef2e94 100644 (file)
@@ -188,3 +188,4 @@ sub ssh_cmd { #subroutine, not method
   '';
 }
 
   '';
 }
 
+1;
diff --git a/FS/FS/part_export_machine.pm b/FS/FS/part_export_machine.pm
new file mode 100644 (file)
index 0000000..1598e03
--- /dev/null
@@ -0,0 +1,155 @@
+package FS::part_export_machine;
+
+use strict;
+use base qw( FS::Record );
+use FS::Record qw( dbh qsearch ); #qsearchs );
+use FS::part_export;
+use FS::svc_export_machine;
+
+=head1 NAME
+
+FS::part_export_machine - Object methods for part_export_machine records
+
+=head1 SYNOPSIS
+
+  use FS::part_export_machine;
+
+  $record = new FS::part_export_machine \%hash;
+  $record = new FS::part_export_machine { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::part_export_machine object represents an export hostname choice.
+FS::part_export_machine inherits from FS::Record.  The following fields are
+currently supported:
+
+=over 4
+
+=item machinenum
+
+primary key
+
+=item exportnum
+
+Export, see L<FS::part_export>
+
+=item machine
+
+Hostname or IP address
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new record.  To add the record to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to.  You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+sub table { 'part_export_machine'; }
+
+=item insert
+
+Adds this record to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+sub delete {
+  my $self = shift;
+
+  local $SIG{HUP} = 'IGNORE';
+  local $SIG{INT} = 'IGNORE';
+  local $SIG{QUIT} = 'IGNORE';
+  local $SIG{TERM} = 'IGNORE';
+  local $SIG{TSTP} = 'IGNORE';
+  local $SIG{PIPE} = 'IGNORE';
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  my $error = $self->SUPER::delete;
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
+
+  foreach my $svc_export_machine ( $self->svc_export_machine ) {
+    my $error = $svc_export_machine->delete;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+  '';
+
+}
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database.  If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid record.  If there is
+an error, returns the error, otherwise returns false.  Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+  my $self = shift;
+
+  my $error = 
+    $self->ut_numbern('machinenum')
+    || $self->ut_foreign_key('exportnum', 'part_export', 'exportnum')
+    || $self->ut_domain('machine')
+    || $self->ut_enum('disabled', [ '', 'Y' ])
+  ;
+  return $error if $error;
+
+  $self->SUPER::check;
+}
+
+=item svc_export_machine
+
+=cut
+
+sub svc_export_machine {
+  my $self = shift;
+  qsearch( 'svc_export_machine', { 'machinenum' => $self->machinenum } );
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::part_export>, L<FS::Record>
+
+=cut
+
+1;
+
index dd18e87..7f22411 100644 (file)
@@ -591,7 +591,7 @@ sub _svc_defs {
       };
       my $mod = $1;
 
       };
       my $mod = $1;
 
-      if ( $mod =~ /^svc_[A-Z]/ or $mod =~ /^svc_acct_pop$/ ) {
+      if ( $mod =~ /^svc_[A-Z]/ or $mod =~ /^(svc_acct_pop|svc_export_machine)$/ ) {
         warn "skipping FS::$mod" if $DEBUG;
        next;
       }
         warn "skipping FS::$mod" if $DEBUG;
        next;
       }
diff --git a/FS/FS/svc_export_machine.pm b/FS/FS/svc_export_machine.pm
new file mode 100644 (file)
index 0000000..39629d8
--- /dev/null
@@ -0,0 +1,111 @@
+package FS::svc_export_machine;
+
+use strict;
+use base qw( FS::Record );
+use FS::Record; # qw( qsearch qsearchs );
+use FS::cust_svc;
+use FS::part_export_machine;
+
+=head1 NAME
+
+FS::svc_export_machine - Object methods for svc_export_machine records
+
+=head1 SYNOPSIS
+
+  use FS::svc_export_machine;
+
+  $record = new FS::svc_export_machine \%hash;
+  $record = new FS::svc_export_machine { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::svc_export_machine object represents a customer service export
+hostname.  FS::svc_export_machine inherits from FS::Record.  The following
+fields are currently supported:
+
+=over 4
+
+=item svcexportmachinenum
+
+primary key
+
+=item svcnum
+
+Customer service, see L<FS::cust_svc>
+
+=item machinenum
+
+Export hostname, see L<FS::part_export_machine>
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new record.  To add the record to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to.  You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+sub table { 'svc_export_machine'; }
+
+=item insert
+
+Adds this record to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=item delete
+
+Delete this record from the database.
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database.  If there is an error,
+returns the error, otherwise returns false.
+
+=item check
+
+Checks all fields to make sure this is a valid record.  If there is
+an error, returns the error, otherwise returns false.  Called by the insert
+and replace methods.
+
+=cut
+
+sub check {
+  my $self = shift;
+
+  my $error = 
+    $self->ut_numbern('svcexportmachinenum')
+    || $self->ut_foreign_key('svcnum', 'cust_svc', 'svcnum')
+    || $self->ut_foreign_key('machinenum', 'part_export_machine', 'machinenum' )
+  ;
+  return $error if $error;
+
+  $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::cust_svc>, L<FS::part_export_machine>, L<FS::Record>
+
+=cut
+
+1;
+
index bb10fb7..479dcad 100644 (file)
@@ -668,3 +668,7 @@ t/cust_bill_pkg_discount_void.t
 FS/Trace.pm
 FS/agent_pkg_class.pm
 t/agent_pkg_class.t
 FS/Trace.pm
 FS/agent_pkg_class.pm
 t/agent_pkg_class.t
+FS/part_export_machine.pm
+t/part_export_machine.t
+FS/svc_export_machine.pm
+t/svc_export_machine.t
diff --git a/FS/t/part_export_machine.t b/FS/t/part_export_machine.t
new file mode 100644 (file)
index 0000000..792bb50
--- /dev/null
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::part_export_machine;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/svc_export_machine.t b/FS/t/svc_export_machine.t
new file mode 100644 (file)
index 0000000..5279be2
--- /dev/null
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::svc_export_machine;
+$loaded=1;
+print "ok 1\n";
index 8e28f4f..beed708 100755 (executable)
@@ -36,10 +36,19 @@ function part_export_areyousure(href) {
       <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><A HREF="<% $p %>edit/part_export.cgi?<% $part_export->exportnum %>"><% $part_export->exportnum %></A></TD>
 
       <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
       <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><A HREF="<% $p %>edit/part_export.cgi?<% $part_export->exportnum %>"><% $part_export->exportnum %></A></TD>
 
       <TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
-% if( $part_export->exportname ) {
-  <B><% $part_export->exportname %>:</B><BR>
-% }
-<% $part_export->exporttype %> to <% $part_export->machine %> (<A HREF="<% $p %>edit/part_export.cgi?<% $part_export->exportnum %>">edit</A>&nbsp;|&nbsp;<A HREF="javascript:part_export_areyousure('<% $p %>misc/delete-part_export.cgi?<% $part_export->exportnum %>')">delete</A>)</TD>
+%       if( $part_export->exportname ) {
+          <B><% $part_export->exportname %>:</B><BR>
+%       }
+        <% $part_export->exporttype %>
+        <% $part_export->machine
+             ? 'to '. ( $part_export->machine eq '_SVC_MACHINE'
+                          ? 'per-service hostname'
+                          : $part_export->machine
+                      )
+             : ''
+        %>
+        (<A HREF="<% $p %>edit/part_export.cgi?<% $part_export->exportnum %>">edit</A>&nbsp;|&nbsp;<A HREF="javascript:part_export_areyousure('<% $p %>misc/delete-part_export.cgi?<% $part_export->exportnum %>')">delete</A>)
+      </TD>
 
       <TD CLASS="inv" BGCOLOR="<% $bgcolor %>">
         <% itable() %>
 
       <TD CLASS="inv" BGCOLOR="<% $bgcolor %>">
         <% itable() %>
index d7219b7..0407ee7 100644 (file)
   </TD>
 </TR>
 <TR>
   </TD>
 </TR>
 <TR>
-  <TD ALIGN="right">Export host</TD>
-  <TD>
-    <INPUT TYPE="text" NAME="machine" VALUE="<% $part_export->machine %>">
-  </TD>
-</TR>
-<TR>
   <TD ALIGN="right">Export</TD>
   <TD><% $widget->html %>
 
   <TD ALIGN="right">Export</TD>
   <TD><% $widget->html %>
 
@@ -63,7 +57,7 @@ my $widget = new HTML::Widgets::SelectLayers(
   'options'        => \%layers,
   'form_name'      => 'dummy',
   'form_action'    => 'process/part_export.cgi',
   'options'        => \%layers,
   'form_name'      => 'dummy',
   'form_action'    => 'process/part_export.cgi',
-  'form_text'      => [qw( exportnum exportname machine )],
+  'form_text'      => [qw( exportnum exportname )],
 #  'form_checkbox'  => [qw()],
   'html_between'    => "</TD></TR></TABLE>\n",
   'layer_callback'  => sub {
 #  'form_checkbox'  => [qw()],
   'html_between'    => "</TD></TR></TABLE>\n",
   'layer_callback'  => sub {
@@ -71,9 +65,69 @@ my $widget = new HTML::Widgets::SelectLayers(
     my $html = qq!<INPUT TYPE="hidden" NAME="exporttype" VALUE="$layer">!.
                ntable("#cccccc",2);
 
     my $html = qq!<INPUT TYPE="hidden" NAME="exporttype" VALUE="$layer">!.
                ntable("#cccccc",2);
 
-    $html .= '<TR><TD ALIGN="right">Description</TD><TD BGCOLOR=#ffffff>'.
-             $exports->{$layer}{notes}. '</TD></TR>'
-      if $layer;
+    if ( $layer ) {
+      $html .= '<TR><TD ALIGN="right">Description</TD><TD BGCOLOR=#ffffff>'.
+               $exports->{$layer}{notes}. '</TD></TR>';
+
+      if ( $exports->{$layer}{no_machine} ) {
+        $html .= '<INPUT TYPE="hidden" NAME="machine" VALUE="">'.
+                 '<INPUT TYPE="hidden" NAME="svc_machine" VALUE=N">';
+      } else {
+        $html .= '<TR><TD ALIGN="right">Hostname or IP</TD><TD>';
+        my $machine = $part_export->machine;
+        if ( $exports->{$layer}{svc_machine} ) {
+          my( $N_CHK, $Y_CHK) = ( 'CHECKED', '' );
+          my( $machine_DISABLED, $pem_DISABLED) = ( '', 'DISABLED' );
+          my $part_export_machine = '';
+          if ( $cgi->param('svc_machine') eq 'Y'
+                 || $machine eq '_SVC_MACHINE'
+             )
+          {
+            $Y_CHK = 'CHECKED';
+            $N_CHK = 'CHECKED';
+            $machine_DISABLED = 'DISABLED';
+            $pem_DISABLED = '';
+            $machine = '';
+            $part_export_machine =
+              $cgi->param('part_export_machine')
+              || join "\n",
+                   map $_->machine,
+                     grep ! $_->disabled,
+                       $part_export->part_export_machine;
+          }
+          my $oc = qq(onChange="${layer}_svc_machine_changed(this)");
+          $html .= qq[
+            <INPUT TYPE="radio" NAME="svc_machine" VALUE="N" $N_CHK $oc>
+            <INPUT TYPE="text" NAME="machine" ID="${layer}_machine" VALUE="$machine" $machine_DISABLED>
+            <BR>
+            <INPUT TYPE="radio" NAME="svc_machine" VALUE="Y" $Y_CHK $oc>
+            Selected in each customer service from these choices
+            <TEXTAREA NAME="part_export_machine" ID="${layer}_part_export_machine" $pem_DISABLED>$part_export_machine</TEXTAREA>
+
+            <SCRIPT TYPE="text/javascript">
+              function ${layer}_svc_machine_changed (what) {
+                if ( what.checked ) {
+                  var machine = document.getElementById("${layer}_machine");
+                  var part_export_machine = document.getElementById("${layer}_part_export_machine");
+                  if ( what.value == 'Y' ) {
+                    machine.disabled = true;
+                    part_export_machine.disabled = false;
+                  } else if ( what.value == 'N' ) {
+                    machine.disabled = false;
+                    part_export_machine.disabled = true;
+                  }
+                }
+              }
+            </SCRIPT>
+          ];
+        } else {
+          $html .= qq(<INPUT TYPE="text" NAME="machine" VALUE="$machine">).
+                     '<INPUT TYPE="hidden" NAME="svc_machine" VALUE=N">';
+        }
+        $html .= "</TD></TR>";
+      }
+
+    }
 
     foreach my $option ( keys %{$exports->{$layer}{options}} ) {
       my $optinfo = $exports->{$layer}{options}{$option};
 
     foreach my $option ( keys %{$exports->{$layer}{options}} ) {
       my $optinfo = $exports->{$layer}{options}{$option};
index 21150ef..6432d6b 100644 (file)
@@ -28,6 +28,11 @@ my $new = new FS::part_export ( {
   } fields('part_export')
 } );
 
   } fields('part_export')
 } );
 
+if ( $cgi->param('svc_machine') eq 'Y' ) {
+  $new->machine('_SVC_MACHINE');
+  $new->part_export_machine_textarea( $cgi->param('part_export_machine') );
+}
+
 my $error;
 if ( $exportnum ) {
   #warn $old;
 my $error;
 if ( $exportnum ) {
   #warn $old;