#!/usr/bin/perl

# Source: @RPM_PACKAGE_VERSION@-@RPM_PACKAGE_RELEASE@

use utf8;
use strict;
use warnings;

BEGIN {
        unshift(@INC,($ENV{'POPHOME'}||'@POPHOME@').'/lib')
			unless $ENV{'KUNDE_NO_PERLPATH'};
      }

select(STDERR); $|=1; select(STDOUT);

print "*** Domains anlegen und bearbeiten\n\n" if -t STDIN;

use Dbase::Getopt qw(:DEFAULT getopt_descr);
use Dbase::Globals qw(
  aufzaehlung
  bignum
  def_or_minus
  find_descr
  flag_names
  get_descr
  get_kunde
  get_ipkunde
  get_ipkunde_byhost
);
use Dbase::Help qw(Do DoFn DoSelect DoTime DoTrans in_list qquote unixtime);
use Fehler qw(fehler);
use Loader qw(acct_domain_gebuehr add_kunde_domain add_zone log_update valid_ticket);

my ( $Ticket, $BitFlags, $ZoneTemplate, $DNSFlags, $DomNS, $SlaveNS, $NIC );

sub set_dns_flags {
    fehler("Nur eine der drei DNS Optionen angeben!\n")
      if defined $DNSFlags;

    if ($_[0] and $_[0] & 4) {
        $DNSFlags = 4;
    }
    else {
        $DNSFlags = 1 | 2;
        $DNSFlags |= $_ for @_;
    }
}

DoTrans {

    my @ARGV = GetOptions(
        'add-master-zones:s' => sub {
            ( undef, $ZoneTemplate ) = @_;
            set_dns_flags();
        },
        'add-default-zones:s' => sub {
            ( undef, $ZoneTemplate ) = @_;
            set_dns_flags(8);
        },
        'add-slave-zones=s' => sub {
            ( undef, $SlaveNS ) = @_;
            $DomNS = get_ipkunde_byhost($SlaveNS);
            set_dns_flags();
        },
        'add-nameserver=s' => sub {
            ( undef, $SlaveNS ) = @_;
            $DomNS = get_ipkunde_byhost($SlaveNS);
            set_dns_flags(4);
        },
        'a|art=s'   => \my $Art,
        'd|datum=s' => \my $Datum,
        'flags=s'   => sub {
            my ( undef, $Flags ) = @_;
            for ( split /,/, $Flags ) {
                my $flagdescr = find_descr domainflags => $_;
                fehler("Flag $_ gibt es nicht!\n") unless defined $flagdescr;
                $BitFlags |= bignum(1) << $flagdescr;
            }
        },
        'n|nic=s'    => sub { $NIC = getopt_descr( nic => @_ ) },
        's|status=s' => \my $CMDStatus,
        't|tarif=s'  => \my $Tarif,
        'ticket=s'   => sub {
            ( undef, $Ticket ) = @_;
            fehler("Ticket existiert nicht.\n") unless valid_ticket($Ticket);
        },
        'update!' => \my $Update,
    );

    fehler("Du solltest mindestens einen Kunden und eine Domain angeben!\n")
      if @ARGV < 2;

    my $kunde;
    {
        my $k = shift @ARGV;
        $kunde = get_kunde($k);
        fehler("Kunde '$k' nicht gefunden\n") unless $kunde;
    }

    my $datum;
    if ($Datum) {
        $datum = unixtime($Datum);
        fehler("Datum '$Datum' nicht erkannt.\n") unless $datum;
    }
    else {
        $datum = DoTime;
    }

    my $Status = $CMDStatus || 'beantragt';
    my $DomStatus = find_descr( domainstatus => $Status )
      or fehler("Status '$Status' nicht bekannt.\n");
    my $DomArt = find_descr( acctinfo => $Art )
      or fehler("Art '$Art' nicht bekannt.\n")
      if defined $Art;
    my $NICNAME = get_descr( nic => $NIC ) if $NIC;

    $ZoneTemplate = undef if defined $ZoneTemplate && !length $ZoneTemplate;

    # Falls -update nicht gesetzt ist,
    # überprüf vorher ob Domains schon vorhanden sind:
    if ( !$Update ) {
        my @domains;
        DoSelect {
            my ( $id, $domain ) = @_;
            push @domains, "#$id:$domain";
        }
        <<_;
SELECT id, domain
  FROM domainkunde
 WHERE ${\ in_list( 'domain', '', @ARGV ) }
   AND ( ende IS NULL OR ende > $datum )
ORDER BY domain, id
_
        fehler('Die Domain'
          . ( @domains != 1 && 's' ) . ' '
          . aufzaehlung(@domains)
          . " gibt es bereits.\n")
          if @domains;
    }

    foreach my $domain (@ARGV) {
        next unless $domain;
        my ( $dom, $domname, $nserver ) = DoFn(<<_);
            SELECT id, domain, nserver
              FROM domainkunde
             WHERE domain = '$domain'
               AND ( ende IS NULL OR ende > $datum )
_

        my $SetStatus = 0;
        if ($dom) {
            print "OK: Domain #$dom $domname: Gibt es bereits.\n" 
              if -t STDIN;
            $SetStatus = 1 if defined $Update && defined $CMDStatus;
        }
        else {
            $dom = add_kunde_domain( $kunde, ( defined $Tarif ) | 2, "Neu:$domain", $domain, $datum, $Tarif );
            print "OK: #$dom $domain angelegt.\n";
            $SetStatus = 1;
        }
        if ($Ticket) {
            my ($otk) = DoFn("SELECT ticket FROM domainkunde WHERE id = $dom");
            log_update( "domainkunde", "id", $dom, undef, "ticket", undef, $otk );
            Do("UPDATE domainkunde SET ticket = $Ticket WHERE id = $dom");
            print "  : #$dom $domain wurde mit Ticket $Ticket assoziiert.\n"
              if -t STDIN;
        }
        if ($BitFlags) {
            my $dflags = DoFn("SELECT flags FROM domainkunde WHERE id = $dom");
            unless ( $BitFlags == $dflags ) {
                my $flag_names = flag_names( $BitFlags, "domainflags", $dflags );
                log_update( "domainkunde", "id", $dom, undef, "flags", undef, $flag_names );
                Do("UPDATE domainkunde SET flags = $BitFlags WHERE id = $dom");
                print "  : #$dom $domain wurde mit Flags " . $flag_names . " verknüpft.\n"
                  if -t STDIN;
            }
        }
        if ($DomArt) {
            acct_domain_gebuehr( $dom, $kunde, 2, $DomArt );
            print "  : #$dom $domain wurde mit Accounting-Eintrag '$DomArt: $Art' versehen.\n"
              if -t STDIN;
        }
        if ($NIC) {
            my ($onic) = DoFn("SELECT nic FROM domainkunde WHERE id = $dom");
            if ( !$onic or $onic != $NIC ) {
                log_update( "domainkunde", "id", $dom, undef, "nic", undef, $onic );
                Do("UPDATE domainkunde SET nic = $NIC WHERE id = $dom");
                print "  : #$dom $domain NIC wurde auf '$NIC: $NICNAME' gesetzt.\n"
                  if -t STDIN;
            }
            else {
                print "  : #$dom $domain NIC ist schon auf '$NIC: $NICNAME' gesetzt.\n"
                  if -t STDIN;
            }
        }
        if ($SetStatus) {
            my ($ostat) = DoFn("SELECT status FROM domainkunde WHERE id = $dom");
            log_update( "domainkunde", "id", $dom, undef, "status", undef, $ostat );
            Do("UPDATE domainkunde SET status = $DomStatus WHERE id = $dom");
            print "  : #$dom $domain Status wurde auf '$DomStatus: $Status' gesetzt.\n"
              if -t STDIN;
        }

        # DNS-Zonen editieren
        if ( defined $DNSFlags ) {
            if ( qquote($nserver) ne qquote($DomNS) ) {
                print "  : #$dom $domain Nameserver wurde "
                  . (
                    defined $SlaveNS
                    ? "auf '$DomNS: $SlaveNS' gesetzt"
                    : 'gelöscht' )
                  . ".\n"
                  if -t STDIN;
                log_update( "domainkunde", "id", $dom, undef, "nserver", undef, def_or_minus($nserver) );
                Do('update domainkunde set nserver = ' . qquote($DomNS) . ' where id = ' . $dom );
            }
            add_zone( $dom, $DNSFlags, $ZoneTemplate );
            print "  : #$dom $domain Zone wurde aktualisiert.\n"
              if -t STDIN;
        }
    }
}

=head1 Name

makedomains -- legt Domains und Tarife an

=head1 Zusammenfassung

makedomains [-d Datum] Kunde Domain...
    -d Datum  als Startdatum verwenden (Default: jetzt)
    Kunde     für diesen Kunden Domains anlegen
    Domain... diese Domains anlegen

=head1 Beschreibung

Lege für einen Kunden einen haufen Domains und Tarife an.
Falls die Domains schon vorhanden sind, werden diese aktualisiert
je nachdem welche Optionen angegeben wurden.

Beantragt werden die Teile (noch) nicht!

=head2 Optionen

=over 4

=item C<-d Datum>

=item C<-datum Datum>

Verwendet dieses Datum als Startdatum

Default: Aktuelle Zeit.

=item C<-flags kommagetrennte Flags>

Assoziiert die Domain mit den angegebenen Flags. Falls ein Flag nicht gefunden
wird, dann gibt er eine Fehlermeldung aus,

Beispiel: C<-flags=noris_update,no_mx>

=item C<-s Indexeeintrag>

=item C<-s Status>

=item C<-status Status>

Béi neu angelegten Domains wird der Standardmäßig der Status 'beantragt'
gesetzt.
Bei Domains die aktualisiert werden wird der Status nicht verändert ausser
es wird einer explizit angegeben.

Default: beantragt (bei neuen Domains)

=item C<-t Tarif>

=item C<-tarif Tarif>

Verwendet diesen Tarif.

Default: Keiner => manuell bitte.

=item C<-ticket TicketNr>

Verknüpft die Domain mit dem angegebenen Ticket.

=item C<-a Art>

=item C<-art Art>

Art zu setzender Accountingeintrag.

Default: kein Accountingeintrag.

=item C<-n NIC>

=item C<-nic NIC>

Zu setzender NIC.

Default: kein NIC eintrag.

=item C<-update>

Falls diese Option angegeben wird, werden bestehende Domains aktualisiert.
Ansonsten bricht das Skript ab falls eine Domain existiert.

Default: kein Update bestehender Domains.

=item C<-h>

=item C<-help>

=item C<-?>

Kurzhilfe.

=back

=head2 Optionen zum Anlegen von DNS-Zonen

Die folgenden Optionen schließen sich gegenseitig aus;
es kann also pro Aufruf maximal eine davon verwendet werden:

=over 4

=item -add-master-zones [Template-Name]

Für die Domains werden Master-DNS-Zonen angelegt;
dabei wird versucht, die Daten bereits bestehender DNS-Zonen zu übernehmen,
bevor ggf. auf Default-Daten zurückgegriffen wird.

=item -add-default-zones [Template-Name]

Für die Domains werden Master-DNS-Zonen mit Default-Daten angelegt.

=item -add-slave-zones DNS-Master

Für die Domains werden Slave-DNS-Zonen mit dem (z. B. über seine
IP-Adresse oder seinen FQDN) angegebenen Master-DNS-Server angelegt.
Diese Option setzt voraus, dass der fragliche DNS-Master bereits in der
Datenbank registriert ist.

=item -add-nameserver DNS-Master

Keine DNS-Zone anlegen, nur kundeneigenen Master-DNS-Server eintragen

=back

=head2 Benötigte Optionen

=over 4

=item C<Kunde>

Der Besitzer dieser Domains.

=item C<Domain>

Die anzulegenden Domainnamen.

=back

=cut

