package Dahdi::Config::Gen; # # Written by Oron Peled # Copyright (C) 2009, Xorcom # This program is free software; you can redistribute and/or # modify it under the same terms as Perl itself. # # $Id$ # =head1 NAME Dahdi::Config::Gen -- Wrapper class for configuration generators. =head1 SYNOPSIS use Dahdi::Config::Gen qw(is_true); my $params = Dahdi::Config::Params->new('the-config-file'); my $gconfig = Dahdi::Config::Gen->new($params); my $num = $gconfig->{'base_exten'}; my $overlap = is_true($gconfig->{'brint_overlap'}); $gconfig->dump; # For debugging $gconfig->run_generator('system', {}, @spans); =head1 DESCRIPTION The constructor must be given an C object. The returned object contains all data required for generation in the form of a hash. The constructor maps the Cs from the parameter object into semantic configuration keys. E.g: the C item is mapped to C and C keys. The actual generation is done by delegation to one of the generators. This is done via the C method which receive the generator name, a generator specific options hash and a list of span objects (from C) for which to generate configuration. This module contains few helper functions. E.g: C, C. =cut require Exporter; @ISA = qw(Exporter); @EXPORT_OK = qw(is_true); use strict; # Parse values as true/false sub is_true($) { my $val = shift; return undef unless defined $val; return $val =~ /^(1|y|yes)$/i; } sub range_string($$) { my ($start, $end) = @_; if($start == $end) { sprintf "%d", $start; } else { sprintf "%d-%d", $start, $end; } } # Generate channel range strings from arrays of chan numbers # E.g: "63-77,79-93" sub channo_range(@) { my @channos = sort { $a <=> $b } @_; my $first_num = $channos[0]; my $range_start = $first_num; my @range; my $prev = undef; foreach my $c (@channos) { my $curr = $c; if(!defined($prev)) { # First iteration $prev = $curr; } elsif($curr != $prev + 1) { # New range push(@range, range_string($range_start, $prev)); $range_start = $curr; } $prev = $curr; } if($prev >= $first_num) { # Last range push(@range, range_string($range_start, $prev)); } return join(',', @range); } # Generate channel range strings from chan objects # E.g: "63-77,79-93" sub chan_range(@) { my @chans = sort { $a->num <=> $b->num } @_; my @channos = map { $_->num } @chans; channo_range(@channos); } # Generate channel range strings from digital span objects # E.g: "63-77,79-93" sub bchan_range($) { my $span = shift || die; die unless $span->is_digital(); my $first_chan = ($span->chans())[0]; my $first_num = $first_chan->num(); my $bchan_ref = $span->bchan_list(); my @channos = map { $_ + $first_num } @{$bchan_ref}; channo_range(@channos); } # Returns a channel numbers array from a channel range string sub parse_chan_range($) { my $rangestr = shift; $rangestr =~ s/\s*//g; # Squeeze die "Bad characters in '$rangestr'" if $rangestr =~ /[^\d\s,-]/; my @ranges = split(/,/, $rangestr); my @channos; my $last_end; foreach my $range (@ranges) { my ($start, $end) = split(/-/, $range, 2); $end = $start unless defined $end; die "Bad characters in '$start'" if $start =~ /\D/; die "Bad characters in '$end'" if $end =~ /\D/; die "Reversed range $end < $start" if $end < $start; die "Channel number < 1" if $start < 1; die "New range begins below previous $start <= $last_end" if defined($last_end) && $last_end >= $start; for(my $i = $start + 0; $i <= $end; $i++) { push(@channos, $i); } $last_end = $end; } return sort { $a <=> $b } @channos; } sub new($) { my $pack = shift || die "$0: Missing package argument"; my $p = shift || die "$0: Missing parameters argument"; # Set defaults my $fxs_default_start = $p->item('fxs_default_start'); my $fxo_default_start = $p->item('fxo_default_start'); my %default_context = ( FXO => $p->item('context_lines'), FXS => $p->item('context_phones'), IN => $p->item('context_input'), OUT => $p->item('context_output'), BRI_TE => $p->item('context_lines'), BRI_NT => $p->item('context_lines'), E1_TE => $p->item('context_lines'), T1_TE => $p->item('context_lines'), J1_TE => $p->item('context_lines'), E1_NT => $p->item('context_lines'), T1_NT => $p->item('context_lines'), J1_NT => $p->item('context_lines'), ); my %default_group = ( FXO => $p->item('group_lines'), FXS => $p->item('group_phones'), IN => '', OUT => '', BRI_TE => $p->item('group_lines'), BRI_NT => $p->item('group_lines'), E1_TE => $p->item('group_lines'), T1_TE => $p->item('group_lines'), J1_TE => $p->item('group_lines'), E1_NT => $p->item('group_lines'), T1_NT => $p->item('group_lines'), J1_NT => $p->item('group_lines'), ); my %default_dahdi_signalling = ( FXO => "fxs$fxo_default_start", FXS => "fxo$fxs_default_start", IN => "fxo$fxs_default_start", OUT => "fxo$fxs_default_start", ); my %default_chan_dahdi_signalling = ( FXO => "fxs_$fxo_default_start", FXS => "fxo_$fxs_default_start", IN => "fxo_$fxs_default_start", OUT => "fxo_$fxs_default_start", ); # First complex mapping my $gconfig = { PARAMETERS => $p, 'loadzone' => $p->item('lc_country'), 'defaultzone' => $p->item('lc_country'), 'context' => \%default_context, 'group' => \%default_group, 'dahdi_signalling' => \%default_dahdi_signalling, 'chan_dahdi_signalling' => \%default_chan_dahdi_signalling, }; # Now add trivial mappings my @trivial = qw( base_exten freepbx fxs_immediate bri_hardhdlc bri_sig_style r2_idle_bits tdm_framing echo_can brint_overlap pri_termtype pri_connection_type em_signalling ); foreach my $k (@trivial) { $gconfig->{$k} = $p->item($k); } bless $gconfig,$pack; return $gconfig; } sub run_generator($$@) { my $gconfig = shift || die; my $name = shift || die "$0: Missing generator name argument"; my $genopts = shift || die "$0: Missing genopts argument"; ref($genopts) eq 'HASH' or die "$0: Bad genopts argument"; my @spans = @_; my $module = "Dahdi::Config::Gen::$name"; #print STDERR "DEBUG: $module\n"; eval "use $module"; if($@) { die "Failed to load configuration generator for '$name'\n"; } my $cfg = $module->new($gconfig, $genopts); $cfg->generate(@spans); } sub dump($) { my $self = shift || die; printf STDERR "%s dump:\n", ref $self; my $width = 30; foreach my $k (sort keys %$self) { my $val = $self->{$k}; my $ref = ref $val; #print STDERR "DEBUG: '$k', '$ref', '$val'\n"; if($ref eq '') { printf STDERR "%-${width}s %s\n", $k, $val; } elsif($ref eq 'SCALAR') { printf STDERR "%-${width}s %s\n", $k, ${$val}; } elsif($ref eq 'ARRAY') { #printf STDERR "%s:\n", $k; my $i = 0; foreach my $v (@{$val}) { printf STDERR "%-${width}s %s\n", "$k\->[$i]", $v; $i++; } } elsif($ref eq 'HASH') { #printf STDERR "%s:\n", $k; foreach my $k1 (keys %{$val}) { printf STDERR "%-${width}s %s\n", "$k\->\{$k1\}", ${$val}{$k1}; } } else { printf STDERR "%-${width}s (-> %s)\n", $k, $ref; } } } 1;