X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fdomain_record.pm;h=ea0c48d4f07d29c19199cd159929f8e4499e810d;hb=c65b166b6e2ebdac5c2eb2e8336ebd1a4087f77c;hp=9f0035689dc0353fc586df5baa257cf2114571a6;hpb=0da1c2b1d5dbe10b304d131f6807b18a237b5d45;p=freeside.git diff --git a/FS/FS/domain_record.pm b/FS/FS/domain_record.pm index 9f0035689..ea0c48d4f 100644 --- a/FS/FS/domain_record.pm +++ b/FS/FS/domain_record.pm @@ -1,10 +1,11 @@ package FS::domain_record; use strict; -use vars qw( @ISA ); +use vars qw( @ISA $noserial_hack ); #use FS::Record qw( qsearch qsearchs ); -use FS::Record qw( qsearchs ); +use FS::Record qw( qsearchs dbh ); use FS::svc_domain; +use FS::svc_www; @ISA = qw(FS::Record); @@ -71,12 +72,93 @@ otherwise returns false. =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; + + if ( $self->rectype eq '_mstr' ) { #delete all other records + foreach my $domain_record ( reverse $self->svc_domain->domain_record ) { + my $error = $domain_record->delete; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + } + + my $error = $self->SUPER::insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + + unless ( $self->rectype =~ /^(SOA|_mstr)$/ ) { + my $error = $self->increment_serial; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + + ''; + +} + =item delete Delete this record from the database. =cut +sub delete { + my $self = shift; + + return "Can't delete a domain record which has a website!" + if qsearchs( 'svc_www', { 'recnum' => $self->recnum } ); + + 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; + } + + unless ( $self->rectype =~ /^(SOA|_mstr)$/ ) { + my $error = $self->increment_serial; + 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, @@ -84,6 +166,40 @@ returns the error, otherwise returns false. =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; + } + + unless ( $self->rectype eq 'SOA' ) { + my $error = $self->increment_serial; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + + ''; + +} + =item check Checks all fields to make sure this is a valid example. If there is @@ -107,30 +223,33 @@ sub check { return "Unknown svcnum (in svc_domain)" unless qsearchs('svc_domain', { 'svcnum' => $self->svcnum } ); - $self->reczone =~ /^(@|[a-zA-Z0-9\.\-]+)$/ + $self->reczone =~ /^(@|[a-z0-9\.\-\*]+)$/i or return "Illegal reczone: ". $self->reczone; $self->reczone($1); $self->recaf =~ /^(IN)$/ or return "Illegal recaf: ". $self->recaf; $self->recaf($1); - $self->rectype =~ /^(SOA|NS|MX|A|PTR|CNAME)$/ + $self->rectype =~ /^(SOA|NS|MX|A|PTR|CNAME|_mstr)$/ or return "Illegal rectype (only SOA NS MX A PTR CNAME recognized): ". $self->rectype; $self->rectype($1); + return "Illegal reczone for ". $self->rectype. ": ". $self->reczone + if $self->rectype !~ /^MX$/i && $self->reczone =~ /\*/; + if ( $self->rectype eq 'SOA' ) { my $recdata = $self->recdata; $recdata =~ s/\s+/ /g; - $recdata =~ /^([a-z0-9\.\-]+ [\w\-\+]+\.[a-z0-9\.\-]+ \( (\d+ ){5}\))$/ + $recdata =~ /^([a-z0-9\.\-]+ [\w\-\+]+\.[a-z0-9\.\-]+ \( ((\d+|((\d+[WDHMS])+)) ){5}\))$/i or return "Illegal data for SOA record: $recdata"; $self->recdata($1); } elsif ( $self->rectype eq 'NS' ) { - $self->recdata =~ /^([a-z0-9\.\-]+)$/ + $self->recdata =~ /^([a-z0-9\.\-]+)$/i or return "Illegal data for NS record: ". $self->recdata; $self->recdata($1); } elsif ( $self->rectype eq 'MX' ) { - $self->recdata =~ /^(\d+)\s+([a-z0-9\.\-]+)$/ + $self->recdata =~ /^(\d+)\s+([a-z0-9\.\-]+)$/i or return "Illegal data for MX record: ". $self->recdata; $self->recdata("$1 $2"); } elsif ( $self->rectype eq 'A' ) { @@ -138,25 +257,82 @@ sub check { or return "Illegal data for A record: ". $self->recdata; $self->recdata($1); } elsif ( $self->rectype eq 'PTR' ) { - $self->recdata =~ /^([a-z0-9\.\-]+)$/ + $self->recdata =~ /^([a-z0-9\.\-]+)$/i or return "Illegal data for PTR record: ". $self->recdata; $self->recdata($1); } elsif ( $self->rectype eq 'CNAME' ) { - $self->recdata =~ /^([a-z0-9\.\-]+)$/ + $self->recdata =~ /^([a-z0-9\.\-]+|\@)$/i or return "Illegal data for CNAME record: ". $self->recdata; $self->recdata($1); + } elsif ( $self->rectype eq '_mstr' ) { + $self->recdata =~ /^((\d{1,3}\.){3}\d{1,3})$/ + or return "Illegal data for _master pseudo-record: ". $self->recdata; } else { die "ack!"; } - ''; #no error + $self->SUPER::check; +} + +=item increment_serial + +=cut + +sub increment_serial { + return '' if $noserial_hack; + my $self = shift; + + my $soa = qsearchs('domain_record', { + svcnum => $self->svcnum, + reczone => '@', #or full domain ? + recaf => 'IN', + rectype => 'SOA', + } ) or return "soa record not found; can't increment serial"; + + my $data = $soa->recdata; + $data =~ s/(\(\D*)(\d+)/$1.($2+1)/e; #well, it works. + + my %hash = $soa->hash; + $hash{recdata} = $data; + my $new = new FS::domain_record \%hash; + $new->replace($soa); +} + +=item svc_domain + +Returns the domain (see L) for this record. + +=cut + +sub svc_domain { + my $self = shift; + qsearchs('svc_domain', { svcnum => $self->svcnum } ); +} + +=item zone + +Returns the canonical zone name. + +=cut + +sub zone { + my $self = shift; + my $zone = $self->reczone; # or die ? + if ( $zone =~ /\.$/ ) { + $zone =~ s/\.$//; + } else { + my $svc_domain = $self->svc_domain; # or die ? + $zone .= '.'. $svc_domain->domain; + $zone =~ s/^\@\.//; + } + $zone; } =back =head1 VERSION -$Id: domain_record.pm,v 1.4 2002-04-20 10:09:42 ivan Exp $ +$Id: domain_record.pm,v 1.16 2003-08-05 00:20:43 khoff Exp $ =head1 BUGS