X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2Fpart_export.pm;h=072074b96e7102fb4b2f4da4c08bc53e00ae1fbe;hp=41dfe77a1ea2947585018991a399d5ae665e6ad4;hb=7308f9eeb141bab0f550cce772a42f18a5cc7319;hpb=c6da895a2fb2c233716381b7e45ebbeb1c2f6aaa diff --git a/FS/FS/part_export.pm b/FS/FS/part_export.pm index 41dfe77a1..072074b96 100644 --- a/FS/FS/part_export.pm +++ b/FS/FS/part_export.pm @@ -1,12 +1,16 @@ package FS::part_export; use strict; -use vars qw( @ISA ); +use vars qw( @ISA @EXPORT_OK %exports ); +use Exporter; +use Tie::IxHash; use FS::Record qw( qsearch qsearchs dbh ); use FS::part_svc; use FS::part_export_option; +use FS::export_svc; @ISA = qw(FS::Record); +@EXPORT_OK = qw(export_info); =head1 NAME @@ -19,7 +23,7 @@ FS::part_export - Object methods for part_export records $record = new FS::part_export \%hash; $record = new FS::part_export { 'column' => 'value' }; - ($new_record, $options) = $template_recored->clone( $svcpart ); + #($new_record, $options) = $template_recored->clone( $svcpart ); $error = $record->insert( { 'option' => 'value' } ); $error = $record->insert( \%options ); @@ -40,8 +44,6 @@ fields are currently supported: =item exportnum - primary key -=item svcpart - Service definition (see L) to which this export applies - =item machine - Machine name =item exporttype - Export type @@ -67,27 +69,29 @@ points to. You can ask the object for a copy with the I method. sub table { 'part_export'; } -=item clone SVCPART - -An alternate constructor. Creates a new export by duplicating an existing -export. The given svcpart is assigned to the new export. - -Returns a list consisting of the new export object and a hashref of options. - =cut -sub clone { - my $self = shift; - my $class = ref($self); - my %hash = $self->hash; - $hash{'exportnum'} = ''; - $hash{'svcpart'} = shift; - ( $class->new( \%hash ), - { map { $_->optionname => $_->optionvalue } - qsearch('part_export_option', { 'exportnum' => $self->exportnum } ) - } - ); -} +#=item clone SVCPART +# +#An alternate constructor. Creates a new export by duplicating an existing +#export. The given svcpart is assigned to the new export. +# +#Returns a list consisting of the new export object and a hashref of options. +# +#=cut +# +#sub clone { +# my $self = shift; +# my $class = ref($self); +# my %hash = $self->hash; +# $hash{'exportnum'} = ''; +# $hash{'svcpart'} = shift; +# ( $class->new( \%hash ), +# { map { $_->optionname => $_->optionvalue } +# qsearch('part_export_option', { 'exportnum' => $self->exportnum } ) +# } +# ); +#} =item insert HASHREF @@ -137,7 +141,7 @@ sub insert { ''; -}; +} =item delete @@ -173,6 +177,14 @@ sub delete { } } + foreach my $export_svc ( $self->export_svc ) { + my $error = $export_svc->delete; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; @@ -258,13 +270,11 @@ sub check { my $error = $self->ut_numbern('exportnum') || $self->ut_domain('machine') - || $self->ut_number('svcpart') || $self->ut_alpha('exporttype') ; return $error if $error; - return "Unknown svcpart: ". $self->svcpart - unless qsearchs( 'part_svc', { 'svcpart' => $self->svcpart } ); + warn $self->machine. "!!!\n"; $self->machine =~ /^([\w\-\.]*)$/ or return "Illegal machine: ". $self->machine; @@ -273,20 +283,39 @@ sub check { $self->nodomain =~ /^(Y?)$/ or return "Illegal nodomain: ". $self->nodomain; $self->nodomain($1); + $self->deprecated(1); #BLAH + #check exporttype? ''; #no error } -=item part_svc +#=item part_svc +# +#Returns the service definition (see L) for this export. +# +#=cut +# +#sub part_svc { +# my $self = shift; +# qsearchs('part_svc', { svcpart => $self->svcpart } ); +#} + +sub part_svc { + use Carp; + croak "FS::part_export::part_svc deprecated"; + #confess "FS::part_export::part_svc deprecated"; +} -Returns the service definition (see L) for this export. +=item export_svc + +Returns a list of associated FS::export_svc records. =cut -sub part_svc { +sub export_svc { my $self = shift; - qsearchs('part_svc', { svcpart => $self->svcpart } ); + qsearch('export_svc', { 'exportnum' => $self->exportnum } ); } =item part_export_option @@ -340,8 +369,10 @@ autoloaded-on-demand), but until then, see L. sub rebless { my $self = shift; my $exporttype = $self->exporttype; - my $class = ref($self); - bless($self, $class."::$exporttype"); + my $class = ref($self). "::$exporttype"; + eval "use $class;"; + die $@ if $@; + bless($self, $class); } =item export_insert SVC_OBJECT @@ -383,363 +414,384 @@ sub export_delete { $self->_export_delete(@_); } -#fallbacks providing useful error messages intead of infinite loops -sub _export_insert { - my $self = shift; - return "_export_insert: unknown export type ". $self->exporttype; -} +=item export_suspend -sub _export_replace { - my $self = shift; - return "_export_replace: unknown export type ". $self->exporttype; -} +=cut -sub _export_delete { +sub export_suspend { my $self = shift; - return "_export_delete: unknown export type ". $self->exporttype; + $self->rebless; + $self->_export_suspend(@_); } -=back +=item export_unsuspend =cut -#infostreet - -package FS::part_export::infostreet; -use vars qw(@ISA); -@ISA = qw(FS::part_export); - -sub rebless { shift; } +sub export_unsuspend { + my $self = shift; + $self->rebless; + $self->_export_unsuspend(@_); +} +#fallbacks providing useful error messages intead of infinite loops sub _export_insert { - my( $self, $svc_acct ) = (shift, shift); - $self->infostreet_queue( $svc_acct->svcnum, - 'createUser', $svc_acct->username, $svc_acct->password ); + my $self = shift; + return "_export_insert: unknown export type ". $self->exporttype; } sub _export_replace { - my( $self, $new, $old ) = (shift, shift, shift); - return "can't change username with InfoStreet" - if $old->username ne $new->username; - return '' unless $old->_password ne $new->_password; - $self->infostreet_queue( $new->svcnum, - 'passwd', $new->username, $new->password ); + my $self = shift; + return "_export_replace: unknown export type ". $self->exporttype; } sub _export_delete { - my( $self, $svc_acct ) = (shift, shift); - $self->infostreet_queue( $svc_acct->svcnum, - 'purgeAccount,releaseUsername', $svc_acct->username ); -} - -sub infostreet_queue { - my( $self, $svcnum, $method ) = (shift, shift, shift); - my $queue = new FS::queue { - 'svcnum' => $svcnum, - 'job' => 'FS::part_export::infostreet::infostreet_command', - }; - $queue->insert( - $self->option('url'), - $self->option('login'), - $self->option('password'), - $self->option('groupID'), - $method, - @_, - ); -} - -sub infostreet_command { #subroutine, not method - my($url, $username, $password, $groupID, $method, @args) = @_; - - #quelle hack - if ( $method =~ /,/ ) { - foreach my $part ( split(/,\s*/, $method) ) { - infostreet_command($url, $username, $password, $groupID, $part, @args); - } - return; - } - - eval "use Frontier::Client;"; - - my $conn = Frontier::Client->new( url => $url ); - my $key_result = $conn->call( 'authenticate', $username, $password, $groupID); - my %key_result = _infostreet_parse($key_result); - die $key_result{error} unless $key_result{success}; - my $key = $key_result{data}; - - my $result = $conn->call($method, $key, @args); - my %result = _infostreet_parse($result); - die $result{error} unless $result{success}; - -} - -sub _infostreet_parse { #subroutine, not method - my $arg = shift; - map { - my $value = $arg->{$_}; - #warn ref($value); - $value = $value->value() - if ref($value) && $value->isa('Frontier::RPC2::DataType'); - $_=>$value; - } keys %$arg; + my $self = shift; + return "_export_delete: unknown export type ". $self->exporttype; } -#sqlradius - -package FS::part_export::sqlradius; -use vars qw(@ISA); -@ISA = qw(FS::part_export); +#fallbacks providing null operations -sub rebless { shift; } - -sub _export_insert { - my($self, $svc_acct) = (shift, shift); - - foreach my $table (qw(reply check)) { - my $method = "radius_$table"; - my %attrib = $svc_acct->$method; - next unless keys %attrib; - my $error = $self->sqlradius_queue( $svc_acct->svcnum, 'insert', - $table, $svc_acct->username, %attrib ); - return $error if $error; - } - my @groups = $svc_acct->radius_groups; - if ( @groups ) { - my $error = $self->sqlradius_queue( $svc_acct->svcnum, 'usergroup_insert', - $svc_acct->username, @groups ); - return $error if $error; - } +sub _export_suspend { + my $self = shift; + #warn "warning: _export_suspened unimplemented for". ref($self); ''; } -sub _export_replace { - my( $self, $new, $old ) = (shift, shift, shift); - - #return "can't (yet) change username with sqlradius" - # if $old->username ne $new->username; - if ( $old->username ne $new->username ) { - my $error = $self->sqlradius_queue( $new->svcnum, 'rename', - $new->username, $old->username ); - return $error if $error; - } - - foreach my $table (qw(reply check)) { - my $method = "radius_$table"; - my %new = $new->$method; - my %old = $old->$method; - if ( grep { !exists $old{$_} #new attributes - || $new{$_} ne $old{$_} #changed - } keys %new - ) { - my $error = $self->sqlradius_queue( $new->svcnum, 'insert', - $table, $new->username, %new ); - return $error if $error; - } - - my @del = grep { !exists $new{$_} } keys %old; - if ( @del ) { - my $error = $self->sqlradius_queue( $new->svcnum, 'attrib_delete', - $table, $new->username, @del ); - return $error if $error; - } - } - - # (sorta) false laziness with FS::svc_acct::replace - my @oldgroups = @{$old->usergroup}; #uuuh - my @newgroups = $new->radius_groups; - my @delgroups = (); - foreach my $oldgroup ( @oldgroups ) { - if ( grep { $oldgroup eq $_ } @newgroups ) { - @newgroups = grep { $oldgroup ne $_ } @newgroups; - next; - } - push @delgroups, $oldgroup; - } - - if ( @delgroups ) { - my $error = $self->sqlradius_queue( $new->svcnum, 'usergroup_delete', - $new->username, @delgroups ); - return $error if $error; - } - - if ( @newgroups ) { - my $error = $self->sqlradius_queue( $new->svcnum, 'usergroup_insert', - $new->username, @newgroups ); - return $error if $error; - } - +sub _export_unsuspend { + my $self = shift; + #warn "warning: _export_unsuspend unimplemented for ". ref($self); ''; } -sub _export_delete { - my( $self, $svc_acct ) = (shift, shift); - $self->sqlradius_queue( $svc_acct->svcnum, 'delete', - $svc_acct->username ); -} - -sub sqlradius_queue { - my( $self, $svcnum, $method ) = (shift, shift, shift); - my $queue = new FS::queue { - 'svcnum' => $svcnum, - 'job' => "FS::part_export::sqlradius::sqlradius_$method", - }; - $queue->insert( - $self->option('datasrc'), - $self->option('username'), - $self->option('password'), - @_, - ); -} +=back -sub sqlradius_insert { #subroutine, not method - my $dbh = sqlradius_connect(shift, shift, shift); - my( $replycheck, $username, %attributes ) = @_; - - foreach my $attribute ( keys %attributes ) { - my $u_sth = $dbh->prepare( - "UPDATE rad$replycheck SET Value = ? WHERE UserName = ? AND Attribute = ?" ) or die $dbh->errstr; - my $i_sth = $dbh->prepare( - "INSERT INTO rad$replycheck ( id, UserName, Attribute, Value ) ". - "VALUES ( ?, ?, ?, ? )" - ) or die $dbh->errstr; - $u_sth->execute($attributes{$attribute}, $username, $attribute) > 0 - or $i_sth->execute( '', $username, $attribute, $attributes{$attribute} ) - or die "can't insert into rad$replycheck table: ". $i_sth->errstr; - } - $dbh->disconnect; -} +=head1 SUBROUTINES -sub sqlradius_usergroup_insert { #subroutine, not method - my $dbh = sqlradius_connect(shift, shift, shift); - my( $username, @groups ) = @_; +=over 4 - my $sth = $dbh->prepare( - "INSERT INTO usergroup ( id, UserName, GroupName ) VALUES ( ?, ?, ? )" - ) or die $dbh->errstr; - foreach my $group ( @groups ) { - $sth->execute( '', $username, $group ) - or die "can't insert into groupname table: ". $sth->errstr; - } - $dbh->disconnect; -} +=item export_info [ SVCDB ] -sub sqlradius_usergroup_delete { #subroutine, not method - my $dbh = sqlradius_connect(shift, shift, shift); - my( $username, @groups ) = @_; +Returns a hash reference of the exports for the given I, or if no +I is specified, for all exports. The keys of the hash are +Is and the values are again hash references containing information +on the export: - my $sth = $dbh->prepare( - "DELETE FROM usergroup ( id, UserName, GroupName ) VALUES ( ?, ?, ? )" - ) or die $dbh->errstr; - foreach my $group ( @groups ) { - $sth->execute( '', $username, $group ) - or die "can't delete from groupname table: ". $sth->errstr; - } - $dbh->disconnect; -} - -sub sqlradius_rename { #subroutine, not method - my $dbh = sqlradius_connect(shift, shift, shift); - my($new_username, $old_username) = @_; - foreach my $table (qw(radreply radcheck usergroup )) { - my $sth = $dbh->prepare("UPDATE $table SET Username = ? WHERE UserName = ?") - or die $dbh->errstr; - $sth->execute($new_username, $old_username) - or die "can't update $table: ". $sth->errstr; - } - $dbh->disconnect; -} + 'desc' => 'Description', + 'options' => { + 'option' => { label=>'Option Label' }, + 'option2' => { label=>'Another label' }, + }, + 'nodomain' => 'Y', #or '' + 'notes' => 'Additional notes', -sub sqlradius_attrib_delete { #subroutine, not method - my $dbh = sqlradius_connect(shift, shift, shift); - my( $replycheck, $username, @attrib ) = @_; +=cut - foreach my $attribute ( @attrib ) { - my $sth = $dbh->prepare( - "DELETE FROM rad$replycheck WHERE UserName = ? AND Attribute = ?" ) - or die $dbh->errstr; - $sth->execute($username,$attribute) - or die "can't delete from rad$replycheck table: ". $sth->errstr; - } - $dbh->disconnect; +sub export_info { + #warn $_[0]; + return $exports{$_[0]} if @_; + #{ map { %{$exports{$_}} } keys %exports }; + my $r = { map { %{$exports{$_}} } keys %exports }; } -sub sqlradius_delete { #subroutine, not method - my $dbh = sqlradius_connect(shift, shift, shift); - my $username = shift; +#=item exporttype2svcdb EXPORTTYPE +# +#Returns the applicable I for an I. +# +#=cut +# +#sub exporttype2svcdb { +# my $exporttype = $_[0]; +# foreach my $svcdb ( keys %exports ) { +# return $svcdb if grep { $exporttype eq $_ } keys %{$exports{$svcdb}}; +# } +# ''; +#} - foreach my $table (qw( radcheck radreply usergroup )) { - my $sth = $dbh->prepare( "DELETE FROM $table WHERE UserName = ?" ); - $sth->execute($username) - or die "can't delete from $table table: ". $sth->errstr; - } - $dbh->disconnect; -} +tie my %sysvshell_options, 'Tie::IxHash', + 'crypt' => { label=>'Password encryption', + type=>'select', options=>[qw(crypt md5)], + default=>'crypt', + }, +; + +tie my %bsdshell_options, 'Tie::IxHash', + 'crypt' => { label=>'Password encryption', + type=>'select', options=>[qw(crypt md5)], + default=>'crypt', + }, +; + +tie my %shellcommands_options, 'Tie::IxHash', + #'machine' => { label=>'Remote machine' }, + 'user' => { label=>'Remote username', default=>'root' }, + 'useradd' => { label=>'Insert command', + default=>'useradd -d $dir -m -s $shell -u $uid $username; passwd $username' + #default=>'cp -pr /etc/skel $dir; chown -R $uid.$gid $dir' + }, + 'useradd_stdin' => { label=>'Insert command STDIN', + type =>'textarea', + default=>"\$_password\n\$_password\n", + }, + 'userdel' => { label=>'Delete command', + default=>'userdel $username', + #default=>'rm -rf $dir', + }, + 'userdel_stdin' => { label=>'Delete command STDIN', + type =>'textarea', + default=>'', + }, + 'usermod' => { label=>'Modify command', + default=>'usermod -d $new_dir -l $new_username -s $new_shell -u $new_uid $old_username; passwd $new_username', + #default=>'[ -d $old_dir ] && mv $old_dir $new_dir || ( '. + # 'chmod u+t $old_dir; mkdir $new_dir; cd $old_dir; '. + # 'find . -depth -print | cpio -pdm $new_dir; '. + # 'chmod u-t $new_dir; chown -R $uid.$gid $new_dir; '. + # 'rm -rf $old_dir'. + #')' + }, + 'usermod_stdin' => { label=>'Modify command STDIN', + type =>'textarea', + default=>"\$_password\n\$_password\n", + }, +; + +tie my %shellcommands_withdomain_options, 'Tie::IxHash', + 'user' => { label=>'Remote username', default=>'root' }, + 'useradd' => { label=>'Insert command', + #default=>'' + }, + 'useradd_stdin' => { label=>'Insert command STDIN', + type =>'textarea', + #default=>"$_password\n$_password\n", + }, + 'userdel' => { label=>'Delete command', + #default=>'', + }, + 'userdel_stdin' => { label=>'Delete command STDIN', + type =>'textarea', + #default=>'', + }, + 'usermod' => { label=>'Modify command', + default=>'', + }, + 'usermod_stdin' => { label=>'Modify command STDIN', + type =>'textarea', + #default=>"$_password\n$_password\n", + }, +; + +tie my %textradius_options, 'Tie::IxHash', + 'user' => { label=>'Remote username', default=>'root' }, + 'users' => { label=>'users file location', default=>'/etc/raddb/users' }, +; + +tie my %sqlradius_options, 'Tie::IxHash', + 'datasrc' => { label=>'DBI data source ' }, + 'username' => { label=>'Database username' }, + 'password' => { label=>'Database password' }, +; + +tie my %cyrus_options, 'Tie::IxHash', + 'server' => { label=>'IMAP server' }, + 'username' => { label=>'Admin username' }, + 'password' => { label=>'Admin password' }, +; + +tie my %cp_options, 'Tie::IxHash', + 'host' => { label=>'Hostname' }, + 'port' => { label=>'Port number' }, + 'username' => { label=>'Username' }, + 'password' => { label=>'Password' }, + 'domain' => { label=>'Domain' }, + 'workgroup' => { label=>'Default Workgroup' }, +; + +tie my %infostreet_options, 'Tie::IxHash', + 'url' => { label=>'XML-RPC Access URL', }, + 'login' => { label=>'InfoStreet login', }, + 'password' => { label=>'InfoStreet password', }, + 'groupID' => { label=>'InfoStreet groupID', }, +; + +tie my %vpopmail_options, 'Tie::IxHash', + 'machine' => { label=>'vpopmail machine', }, + 'dir' => { label=>'directory', }, # ?more info? default? + 'uid' => { label=>'vpopmail uid' }, + 'gid' => { label=>'vpopmail gid' }, +; + +tie my %bind_options, 'Tie::IxHash', + #'machine' => { label=>'named machine' }, + 'named_conf' => { label => 'named.conf location', + default=> '/etc/bind/named.conf' }, + 'zonepath' => { label => 'path to zone files', + default=> '/etc/bind/', }, +; + +tie my %bind_slave_options, 'Tie::IxHash', + #'machine' => { label=> 'Slave machine' }, + 'master' => { label=> 'Master IP address(s) (semicolon-separated)' }, + 'named_conf' => { label => 'named.conf location', + default => '/etc/bind/named.conf' }, +; + +tie my %sqlmail_options, 'Tie::IxHash', + 'datasrc' => { label=>'DBI data source' }, + 'username' => { label=>'Database username' }, + 'password' => { label=>'Database password' }, +; + + +#export names cannot have dashes... +%exports = ( + 'svc_acct' => { + 'sysvshell' => { + 'desc' => + 'Batch export of /etc/passwd and /etc/shadow files (Linux/SysV).', + 'options' => \%sysvshell_options, + 'nodomain' => 'Y', + 'notes' => 'MD5 crypt requires installation of Crypt::PasswdMD5 from CPAN. Run bin/sysvshell.export to export the files.', + }, + 'bsdshell' => { + 'desc' => + 'Batch export of /etc/passwd and /etc/master.passwd files (BSD).', + 'options' => \%bsdshell_options, + 'nodomain' => 'Y', + 'notes' => 'MD5 crypt requires installation of Crypt::PasswdMD5 from CPAN. Run bin/bsdshell.export to export the files.', + }, +# 'nis' => { +# 'desc' => +# 'Batch export of /etc/global/passwd and /etc/global/shadow for NIS ', +# 'options' => {}, +# }, + 'textradius' => { + 'desc' => 'Real-time export to a text /etc/raddb/users file (Livingston, Cistron)', + 'options' => \%textradius_options, + 'notes' => 'This will edit a text RADIUS users file in place on a remote server. Requires installation of RADIUS::UserFile from CPAN. If using RADIUS::UserFile 1.01, make sure to apply this patch. Also make sure rsync is installed on the remote machine, and SSH is setup for unattended operation.', + }, + + 'shellcommands' => { + 'desc' => 'Real-time export via remote SSH (i.e. useradd, userdel, etc.)', + 'options' => \%shellcommands_options, + 'nodomain' => 'Y', + 'notes' => '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 setup SSH for unattended operation.

Use these buttons for some useful presets:
', + }, + + 'shellcommands_withdomain' => { + 'desc' => 'Real-time export via remote SSH.', + 'options' => \%shellcommands_withdomain_options, + 'notes' => 'Run remote commands via SSH. username@domain (rather than just usernames) are considered unique (also see shellcommands). You probably want this if the commands you are running will accept a domain as a parameter, and will allow the same username with different domains. You will need to setup SSH for unattended operation.', + }, + + 'sqlradius' => { + 'desc' => 'Real-time export to SQL-backed RADIUS (ICRADIUS, FreeRADIUS)', + 'options' => \%sqlradius_options, + 'nodomain' => 'Y', + 'notes' => 'Real-time export of radcheck, radreply and usergroup tables to any SQL database for FreeRADIUS or ICRADIUS. An existing RADIUS database will be updated in realtime, but you can use freeside-sqlradius-reset to delete the entire RADIUS database and repopulate the tables from the Freeside database. See the DBI documentation and the documentation for your DBD for the exact syntax of a DBI data source. If using FreeRADIUS 0.5 or above, make sure your op fields are set to allow NULL values.', + }, + + 'sqlmail' => { + 'desc' => 'Real-time export to SQL-backed mail server', + 'options' => \%sqlmail_options, + 'nodomain' => 'Y', + 'notes' => 'Database schema can be made to work with Courier IMAP and Exim. Others could work but are untested. (...extended description from pc-intouch?...)', + }, + + 'cyrus' => { + 'desc' => 'Real-time export to Cyrus IMAP server', + 'options' => \%cyrus_options, + 'nodomain' => 'Y', + 'notes' => 'Integration with Cyrus IMAP Server. Cyrus::IMAP::Admin should be installed locally and the connection to the server secured. svc_acct.quota, if available, is used to set the Cyrus quota. ' + }, + + 'cp' => { + 'desc' => 'Real-time export to Critical Path Account Provisioning Protocol', + 'options' => \%cp_options, + 'notes' => 'Real-time export to Critial Path Account Provisioning Protocol. Requires installation of Net::APP from CPAN.', + }, + + 'infostreet' => { + 'desc' => 'Real-time export to InfoStreet streetSmartAPI', + 'options' => \%infostreet_options, + 'nodomain' => 'Y', + 'notes' => 'Real-time export to InfoStreet streetSmartAPI. Requires installation of Frontier::Client from CPAN.', + }, + + 'vpopmail' => { + 'desc' => 'Real-time export to vpopmail text files', + 'options' => \%vpopmail_options, + 'notes' => 'Real time export to vpopmail text files (...extended description from jeff?...)', + }, + + }, + + 'svc_domain' => { + + 'bind' => { + 'desc' =>'Batch export to BIND named', + 'options' => \%bind_options, + 'notes' => 'Batch export of BIND zone and configuration files to primary nameserver. File::Rsync must be installed. Run bin/bind.export to export the files.', + }, + + 'bind_slave' => { + 'desc' =>'Batch export to slave BIND named', + 'options' => \%bind_slave_options, + 'notes' => 'Batch export of BIND configuration file to a secondary nameserver. Zones are slaved from the listed masters. File::Rsync must be installed. Run bin/bind.export to export the files.', + }, + + 'sqlmail' => { + 'desc' => 'Real-time export to SQL-backed mail server', + 'options' => \%sqlmail_options, + #'nodomain' => 'Y', + 'notes' => 'Database schema can be made to work with Courier IMAP and Exim. Others could work but are untested. (...extended description from pc-intouch?...)', + }, + + + }, + + 'svc_acct_sm' => {}, + + 'svc_forward' => { + 'sqlmail' => { + 'desc' => 'Real-time export to SQL-backed mail server', + 'options' => \%sqlmail_options, + #'nodomain' => 'Y', + 'notes' => 'Database schema can be made to work with Courier IMAP and Exim. Others could work but are untested. (...extended description from pc-intouch?...)', + }, + }, + + 'svc_www' => { + 'www_shellcommands' => { + 'desc' => 'www_shellcommands', + 'options' => {}, # \%www_shellcommands_options, + 'notes' => 'unfinished...', + }, + + }, + +); -sub sqlradius_connect { - #my($datasrc, $username, $password) = @_; - #DBI->connect($datasrc, $username, $password) or die $DBI::errstr; - DBI->connect(@_) or die $DBI::errstr; -} +=back =head1 NEW EXPORT CLASSES - #myexport - - package FS::part_export::myexport; - use vars qw(@ISA); - @ISA = qw(FS::part_export); - - sub rebless { shift; } - - sub _export_insert { - my($self, $svc_something) = (shift, shift); - $self->myexport_queue( $svc_acct->svcnum, 'insert', - $svc_something->username, $svc_something->password ); - } - - sub _export_replace { - my( $self, $new, $old ) = (shift, shift, shift); - #return "can't change username with myexport" - # if $old->username ne $new->username; - #return '' unless $old->_password ne $new->_password; - $self->myexport_queue( $new->svcnum, - 'replace', $new->username, $new->password ); - } - - sub _export_delete { - my( $self, $svc_something ) = (shift, shift); - $self->myexport_queue( $svc_acct->svcnum, - 'delete', $svc_something->username ); - } - - #a good idea to queue anything that could fail or take any time - sub myexport_queue { - my( $self, $svcnum, $method ) = (shift, shift, shift); - my $queue = new FS::queue { - 'svcnum' => $svcnum, - 'job' => "FS::part_export::myexport::myexport_$method", - }; - $queue->insert( @_ ); - } - - sub myexport_insert { #subroutine, not method - } - sub myexport_replace { #subroutine, not method - } - sub myexport_delete { #subroutine, not method - } +Should be added to the %export hash here, and a module should be added in +FS/FS/part_export/ (an example may be found in eg/export_template.pm) =head1 BUGS -Probably. +All the stuff in the %exports hash should be generated from the specific +export modules. + +Hmm... cust_export class (not necessarily a database table...) ... ? -Hmm, export code has wound up in here. Move those sub-classes out into their -own files, at least. Also hmm... cust_export class (not necessarily a -database table...) ... ? +deprecated column... =head1 SEE ALSO -L, L, L, L, +L, L, L, +L, L, L, schema.html from the base documentation. =cut