From e07b80f91c00fcf5013fe2c7066008470d203d30 Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Sun, 24 May 2009 17:02:36 +0300 Subject: Importing Asterisk::config 0.96 from tarball --- Changes | 60 +++ MANIFEST | 18 + META.yml | 13 + Makefile.PL | 12 + README | 33 ++ examples/exten.conf | 8 + examples/new.conf | 20 + examples/new_exten.conf | 7 + examples/sip.conf | 25 ++ examples/test1.pl | 10 + examples/test2.pl | 30 ++ examples/test3.pl | 16 + examples/test4.pl | 14 + examples/test5.pl | 26 ++ examples/test6.pl | 12 + lib/Asterisk/config.pm | 944 ++++++++++++++++++++++++++++++++++++++++++++++++ t/read.t | 12 + t/test.conf | 25 ++ 18 files changed, 1285 insertions(+) create mode 100755 Changes create mode 100755 MANIFEST create mode 100755 META.yml create mode 100755 Makefile.PL create mode 100755 README create mode 100755 examples/exten.conf create mode 100755 examples/new.conf create mode 100755 examples/new_exten.conf create mode 100755 examples/sip.conf create mode 100755 examples/test1.pl create mode 100755 examples/test2.pl create mode 100755 examples/test3.pl create mode 100755 examples/test4.pl create mode 100755 examples/test5.pl create mode 100755 examples/test6.pl create mode 100755 lib/Asterisk/config.pm create mode 100755 t/read.t create mode 100755 t/test.conf diff --git a/Changes b/Changes new file mode 100755 index 0000000..4d223fb --- /dev/null +++ b/Changes @@ -0,0 +1,60 @@ +0.96 2008-4-29 + - error name _format_convert in _do_append + - add return when not commit list on save_file +0.95 2008-3-19 + - add variable $object->{parsed_section_chunk} +0.94 2008-3-11 + - enable reload_when_save function +0.93 2008-2-1 + - add value_regexp to assign_delkey +0.92 2008-1-28 + - add make test +0.91 2008-1-25 + - fix some warnnings syntax. + +0.9 2008-1-23 + - changed object syntax. + - add function get_objvar + - add function fetch_sections_list + - add function fetch_sections_hashref + - add function fetch_keys_list + - add function fetch_keys_hashref + - add function fetch_values_arrayref + - add function reload + - add function set_objvar + - add object variable file + - add object variable keep_resource_array + - add object variable reload_when_save + - add object variable clean_when_reload + - add object variable commit_list + - add object variable parsed_conf + - changed readme + +0.8 2006-6-2 + - new parameter point=>'foot' in assign_append(). + - fix dejected \n in do_append() and/or do_delsection(). + +0.7 2006-4-18 + - add addsection. + - fix regexp in sub clean_string. + - fixed the bug of @commit_list dirty-write resulted by more than one instance of Asterisk::config + +0.6 2006-2-19 + - change load_config parameters to hash struct. + - fix split (.+) to (.*) in sub clean_keyvalue. + - fix split (.+) to (.*) in sub load_config. + - add use Fcntl ':flock' for disable flock warnings. + - more POD docs. + - fix VERSION variable. + - fix $stream_data warnings in load_config using strict. + - fix # warnings in load_config using strict. +0.5 2006-1-6 + - support stream in load_config. + - my $VERSION + +0.4 2005-12-23 + - add assign_matchreplace. + +0.1 2005-11-29 + - start.... + diff --git a/MANIFEST b/MANIFEST new file mode 100755 index 0000000..a95a1fc --- /dev/null +++ b/MANIFEST @@ -0,0 +1,18 @@ +Changes +examples/exten.conf +examples/new.conf +examples/new_exten.conf +examples/sip.conf +examples/test1.pl +examples/test2.pl +examples/test3.pl +examples/test4.pl +examples/test5.pl +examples/test6.pl +lib/Asterisk/config.pm +Makefile.PL +MANIFEST This list of files +README +t/read.t +t/test.conf +META.yml Module meta-data (added by MakeMaker) diff --git a/META.yml b/META.yml new file mode 100755 index 0000000..08720bc --- /dev/null +++ b/META.yml @@ -0,0 +1,13 @@ +--- #YAML:1.0 +name: Asterisk-config +version: 0.95 +abstract: The Asterisk config read and write module. +license: gpl +author: + - Sun Bing (hoowa.sun@gmail.com) +generated_by: ExtUtils::MakeMaker version 6.42_01 +distribution_type: module +requires: +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.3.html + version: 1.3 diff --git a/Makefile.PL b/Makefile.PL new file mode 100755 index 0000000..58fa955 --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,12 @@ +use ExtUtils::MakeMaker; + +WriteMakefile( + AUTHOR => 'Sun Bing (hoowa.sun@gmail.com)', + NAME => 'Asterisk::config', + ABSTRACT => 'The Asterisk config read and write module.', + VERSION_FROM => 'lib/Asterisk/config.pm', + ($ExtUtils::MakeMaker::VERSION >= 6.31 + ? ( LICENSE => 'gpl' ) + : () + ), +); diff --git a/README b/README new file mode 100755 index 0000000..97a8cc4 --- /dev/null +++ b/README @@ -0,0 +1,33 @@ +This is the README file for Asterisk::config, a module to +read/write Asterisk config. + +Asterisk is most popular Opensource PBX in PBX World! + +Access www.asterisk.org for more details. + +* Installation + +Asterisk::config uses the standard perl module install process: + +perl Makefile.PL +make +make install + +* Copyright + +See COPYRIGHT section in pod text below for usage and +distribution rights. + +by Sun bing + +* Introduction + +Asterisk::config can parse and saving data with Asterisk config +files. this module support asterisk 1.0 1.2 1.4 1.6, and it also +support Zaptel config files. + +The Asterisk::config be Part of FreeIris opensource Telephony Project +Access http://www.freeiris.org for more details. + +Please refer to the POD text for synopsis and usage details. + diff --git a/examples/exten.conf b/examples/exten.conf new file mode 100755 index 0000000..96a92f6 --- /dev/null +++ b/examples/exten.conf @@ -0,0 +1,8 @@ + +[mytest] +exten => 200,1,Dial(SIP/200) +exten => 201,1,NoOp('No response') +exten => 201,2,Hangup() + +[demo] +exten => s,1,NoOp('hello') diff --git a/examples/new.conf b/examples/new.conf new file mode 100755 index 0000000..7369ddf --- /dev/null +++ b/examples/new.conf @@ -0,0 +1,20 @@ +type=friend +secret=123456 +[general] +useragent=hoowa +disallow=all +#include classsip.conf + +[usera] +type=friend;saying +secret=thisone +host=192.168.0.1;dynamic + +[trunka] +type=peer +host=192.168.0.1 + +#include branchsip.conf + +[gan] +allow=h263 diff --git a/examples/new_exten.conf b/examples/new_exten.conf new file mode 100755 index 0000000..b3ba1f9 --- /dev/null +++ b/examples/new_exten.conf @@ -0,0 +1,7 @@ + +[mytest] +exten => 200,1,Dial(SIP/200) +exten => 201,1,NoOp('No response') + +[demo] +exten => s,1,NoOp('hello') diff --git a/examples/sip.conf b/examples/sip.conf new file mode 100755 index 0000000..1cfbf94 --- /dev/null +++ b/examples/sip.conf @@ -0,0 +1,25 @@ +key=value + +thisis=>unsection + +[general] +useragent=hoowa +disallow=all +allow=g729 +allow=>g723 #comment +allow=ulaw +#include classsip.conf + +[usera] +type=friend;saying +secret=thisone +host=>dynamic + +[trunka] +type=friend +host=192.168.0.1 + +#include branchsip.conf + +[tempsection] +delete=me diff --git a/examples/test1.pl b/examples/test1.pl new file mode 100755 index 0000000..d8ec230 --- /dev/null +++ b/examples/test1.pl @@ -0,0 +1,10 @@ +#!/usr/bin/perl +use Data::Dumper; +use lib '../lib'; +use Asterisk::config; + +my $rc = new Asterisk::config(file=>'sip.conf',keep_resource_array=>0); +if ($rc) { + print "true"; +} +print Dumper $rc; diff --git a/examples/test2.pl b/examples/test2.pl new file mode 100755 index 0000000..1476e66 --- /dev/null +++ b/examples/test2.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl +use Data::Dumper; +use lib '../lib'; +use Asterisk::config; + +my $rc = new Asterisk::config(file=>'sip.conf'); + +$myfile = $rc->get_objvar('file'); +print $myfile; +print "\n\n"; + +$parsed = $rc->fetch_sections_hashref(); +print Dumper $parsed; +print "\n\n"; + +$section_list = $rc->fetch_sections_list(); +print Dumper $section_list; +print "\n\n"; + +$key_ref = $rc->fetch_keys_hashref(section=>'[unsection]'); +print Dumper $key_ref; +print "\n\n"; + +$key_list = $rc->fetch_keys_list(section=>'general'); +print Dumper $key_list; +print "\n\n"; + +$value_list = $rc->fetch_values_arrayref(section=>'general',key=>'useragent'); +print Dumper $value_list; +print "\n\n"; diff --git a/examples/test3.pl b/examples/test3.pl new file mode 100755 index 0000000..9c8169f --- /dev/null +++ b/examples/test3.pl @@ -0,0 +1,16 @@ +#!/usr/bin/perl +use Data::Dumper; +use lib '../lib'; +use Asterisk::config; + +my $rc = new Asterisk::config(file=>'sip.conf'); + +print $rc->fetch_sections_hashref(); +print "\n\n"; + +if ($rc->reload()) { + print "true reload\n\n"; +} + +print $rc->fetch_sections_hashref(); +print "\n\n"; diff --git a/examples/test4.pl b/examples/test4.pl new file mode 100755 index 0000000..bb6b1f3 --- /dev/null +++ b/examples/test4.pl @@ -0,0 +1,14 @@ +#!/usr/bin/perl +use Data::Dumper; +use lib '../lib'; +use Asterisk::config; + +my $rc = new Asterisk::config(file=>'sip.conf'); + +if (!$rc->set_objvar(mytest=>'test')) { + print "not found\n"; +} + +$rc->set_objvar(reload_when_save=>123467); + +print $rc->get_objvar('reload_when_save'); diff --git a/examples/test5.pl b/examples/test5.pl new file mode 100755 index 0000000..6de3eb7 --- /dev/null +++ b/examples/test5.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl -w +use Data::Dumper; +use lib '../lib'; +use Asterisk::config; + +my $rc = new Asterisk::config(file=>'sip.conf',keep_resource_array=>0); + +$rc->assign_matchreplace(match=>'host=>dynamic',replace=>'host=192.168.0.1;dynamic'); + +$rc->assign_replacesection(section=>'[unsection]',data=>['type=friend','secret=123456']); + +$rc->assign_delsection(section=>'tempsection'); + +$rc->assign_addsection(section=>'gan'); + +$rc->assign_append(point=>'down',section=>'gan',data=>'allow=h263'); + +$rc->assign_editkey(section=>'trunka',key=>'type',new_value=>'peer'); + +$rc->assign_delkey(section=>'general',key=>'allow'); + +#$rc->assign_cleanfile(); + +# new_file can save data to newfile +$rc->save_file(new_file=>'new.conf'); + diff --git a/examples/test6.pl b/examples/test6.pl new file mode 100755 index 0000000..c14d0ab --- /dev/null +++ b/examples/test6.pl @@ -0,0 +1,12 @@ +#!/usr/bin/perl -w +use Data::Dumper; +use lib '../lib'; +use Asterisk::config; + +my $rc = new Asterisk::config(file=>'exten.conf',keep_resource_array=>0); + +$rc->assign_delkey(section=>'mytest',key=>'exten',value_regexp=>'201',value=>'201,2,Hangup()'); + +# new_file can save data to newfile +$rc->save_file(new_file=>'new_exten.conf'); + diff --git a/lib/Asterisk/config.pm b/lib/Asterisk/config.pm new file mode 100755 index 0000000..dc88ebf --- /dev/null +++ b/lib/Asterisk/config.pm @@ -0,0 +1,944 @@ +package Asterisk::config; +#-------------------------------------------------------------- +# +# Asterisk::config - asterisk config files read and write +# +# Copyright (C) 2005 - 2008, Sun bing. +# +# Sun bing +# +# +# LICENSE +# The Asterisk::config is licensed under the GNU 2.0 GPL. +# Asterisk::config carries no restrictions on re-branding +# and people are free to commercially re-distribute it. +# +# +#-------------------------------------------------------------- +$Asterisk::config::VERSION='0.96'; + +use strict; +use Fcntl ':flock'; + +############################## +# CLASS METHOD +sub new { +my $class = shift; +my %args = @_; +my (@resource_list,$resource_list,$parsed_conf,$parsed_section_chunk,$comment_flag); + + #try read + return(0) if (!defined $args{file}); + return(0) if (!-e $args{file}); + if (defined $args{'stream_data'}) { + @resource_list = split(/\n/,$args{'stream_data'}); + } else { + open(DATA,"<$args{'file'}") or die "Asterisk-config Can't Open file : $!"; + @resource_list = ; + close(DATA); + } + chomp(@resource_list); + #try parse + $comment_flag = '\;|\#'; + ($parsed_conf,$parsed_section_chunk) = &_parse(\@resource_list,$comment_flag,$args{'section_chunk'}); + + #try define default variable + $args{'keep_resource_array'} = 1 if (!defined $args{'keep_resource_array'}); + if (defined $args{'keep_resource_array'} && $args{'keep_resource_array'}) { + $resource_list = \@resource_list; + } + if (!defined $args{'clean_when_reload'}) { + $args{'clean_when_reload'} = 1; + } + if (!defined $args{'reload_when_save'}) { + $args{'reload_when_save'} = 1; + } + +my $self = { + #user input + file=> $args{'file'}, + keep_resource_array=> $args{'keep_resource_array'}, + clean_when_reload=> $args{'clean_when_reload'}, + reload_when_save=> $args{'reload_when_save'}, + + #internal + commit_list => [], + parsed_conf=> $parsed_conf, + parsed_section_chunk=> $parsed_section_chunk, + resource_list=> $resource_list, + comment_flag=> $comment_flag, + }; + bless $self,$class; + return $self; +} + +############################## +# INTERNAL SUBROUTE _parse +# parse conf +sub _parse { +my $resource_list = $_[0]; +my $comment_flag = $_[1]; +my $section_chunk = $_[2]; + +my (%DATA,$last_section_name,%DATA_CHUNK); + $DATA{'[unsection]'}={}; $DATA_CHUNK{'[unsection]'}={} if ($section_chunk); + foreach my $one_line (@$resource_list) { + my $line_sp=&_clean_string($one_line,$comment_flag); + + #format : Find New Section ??? + if ($line_sp =~ /^\[(.+)\]/) { + $DATA{$1}={}; $last_section_name = $1; + $DATA_CHUNK{$1}=[] if ($section_chunk); + next; + + #save source chunk to data_chunk + } elsif ($section_chunk) { + next if ($one_line eq ''); + my $section_name = $last_section_name; + $section_name = '[unsection]' if (!$section_name); + #copying source chunk to data_chunk + push(@{$DATA_CHUNK{$section_name}},$one_line); + } + + next if ($line_sp eq '');#next if just comment + + #fromat : Include "#" ??? + if ($line_sp =~ /^\#/) { + my $section_name = $last_section_name; + $section_name = '[unsection]' if (!$section_name); + $DATA{$section_name}{$line_sp}=[] if (!$DATA{$section_name}{$line_sp}); + push(@{$DATA{$section_name}{$line_sp}},$line_sp); + next; + } + + #format : Key=Value ??? + if ($line_sp =~ /\=/) { + #split data and key + my ($key,$value)=&_clean_keyvalue($line_sp); + + my $section_name = $last_section_name; + $section_name = '[unsection]' if (!$section_name); + $DATA{$section_name}{$key}=[] if (!$DATA{$section_name}{$key}); + push(@{$DATA{$section_name}{$key}},$value); + next; + } + } + +return(\%DATA,\%DATA_CHUNK); +} + +############################## +# INTERNAL SUBROUTE _clean_string +# clean strings +sub _clean_string { +my $string = shift; +my $comment_flag = shift; + return '' unless $string; + if ($string !~ /^\#/) { + ($string,undef)=split(/$comment_flag/,$string); + } + $string =~ s/^\s+//; + $string =~ s/\s+$//; +return($string); +} + +############################## +# INTERNAL SUBROUTE _clean_string +# split key value of data +sub _clean_keyvalue { +my $string = shift; +my ($key,$value)=split(/\=(.*)/,$string); + $key =~ s/^(\s+)//; $key =~ s/(\s+)$//; + if ($value) { + $value=~ s/^\>//g; $value =~ s/^(\s+)//; $value =~ s/(\s+)$//; + } + +return($key,$value); +} + +############################## +# READ METHOD +sub get_objvar +{ +my $self = shift; +my $varname = shift; + if (defined $self->{$varname}) { + return($self->{$varname}); + } else { + return(0); + } +} + +sub fetch_sections_list +{ +my $self = shift; +my @sections_list = grep(!/^\[unsection\]/, keys %{$self->{parsed_conf}}); +return(\@sections_list); +} + +sub fetch_sections_hashref +{ +my $self = shift; +return($self->{parsed_conf}); +} + +sub fetch_keys_list +{ +my $self = shift; +my %args = @_; + return(0) if (!defined $args{section}); + return(0) if (!defined $self->{parsed_conf}{$args{section}}); + +my @keys_list = grep(!/^\[unsection\]/, keys %{$self->{parsed_conf}{$args{section}}}); +return(\@keys_list); +} + +sub fetch_keys_hashref +{ +my $self = shift; +my %args = @_; + return(0) if (!defined $args{section}); + return(0) if (!defined $self->{parsed_conf}{$args{section}}); + +return($self->{parsed_conf}{$args{section}}); +} + +sub fetch_values_arrayref +{ +my $self = shift; +my %args = @_; + return(0) if (!defined $args{section}); + return(0) if (!defined $self->{parsed_conf}{$args{section}}); + return(0) if (!defined $args{key}); + return(0) if (!defined $self->{parsed_conf}{$args{section}}{$args{key}}); + +return($self->{parsed_conf}{$args{section}}{$args{key}}); +} + +sub reload +{ +my $self = shift; + + #try read + return(0) if (!defined $self->{file}); + return(0) if (!-e $self->{file}); + open(DATA,"<$self->{'file'}") or die "Asterisk-config Can't Open file : $!"; +my @resource_list = ; + close(DATA); + chomp(@resource_list); + + # save to parsed_conf +my $parsed_conf = &_parse(\@resource_list,$self->{comment_flag}); + $self->{parsed_conf} = $parsed_conf; + + # save to resource_list +my $resource_list; + if (defined $self->{'keep_resource_array'} && $self->{'keep_resource_array'}) { + $resource_list = \@resource_list; + } + $self->{resource_list} = $resource_list; + + # save to commit_list / do clean_when_reload ? + if (defined $self->{'clean_when_reload'} && $self->{'clean_when_reload'}) { + &clean_assign($self); + } + + +return(1); +} + +############################## +# WRITE METHOD + +sub clean_assign +{ +my $self = shift; +# undef($self->{commit_list}); + $self->{commit_list}=[]; +return(1); +} + +sub set_objvar +{ +my $self = shift; +my $key = shift; +my $value = shift; + + return(0) if (!defined $value); + return(0) if (!exists $self->{$key}); + $self->{$key} = $value; + +return(1); +} + +#----------------------------------------------------------- +# assign method to commit_list +sub assign_cleanfile +{ +my $self = shift; +my %hash = @_; + $hash{'action'}='cleanfile'; + push(@{$self->{commit_list}},\%hash); +} + +sub assign_matchreplace +{ +my $self = shift; +my %hash = @_; + $hash{'action'}='matchreplace'; + push(@{$self->{commit_list}},\%hash); +} + +sub assign_append +{ +my $self = shift; +my %hash = @_; + $hash{'action'}='append'; + push(@{$self->{commit_list}},\%hash); +} + +sub assign_replacesection +{ +my $self = shift; +my %hash = @_; + $hash{'action'}='replacesection'; + push(@{$self->{commit_list}},\%hash); +} + +sub assign_delsection +{ +my $self = shift; +my %hash = @_; + $hash{'action'}='delsection'; + push(@{$self->{commit_list}},\%hash); +} + +sub assign_addsection +{ +my $self = shift; +my %hash = @_; + $hash{action} = 'addsection'; + push(@{$self->{commit_list}}, \%hash); +} + +sub assign_editkey +{ +my $self = shift; +my %hash = @_; + $hash{'action'}='editkey'; + push(@{$self->{commit_list}},\%hash); +} + +sub assign_delkey +{ +my $self = shift; +my %hash = @_; + $hash{'action'}='delkey'; + push(@{$self->{commit_list}},\%hash); +} + +#----------------------------------------------------------- +# save method and save internal method +# filename: run assign rules and save to file +# save_file(); +sub save_file +{ +my $self = shift; +my %opts = @_; + + return if ($#{$self->{commit_list}} < 0); + +my $used_resource; + #check to use resource_list? + if (defined $self->{'keep_resource_array'} && $self->{'keep_resource_array'}) { +# $used_resource = $self->{resource_list}; + $used_resource = [ @{ $self->{resource_list} } ]; + } + + if (!defined $used_resource) { + open(DATA,"<$self->{'file'}") or die "Asterisk-config can't read from $self->{file} : $!"; + my @DATA = ; + close(DATA); + chomp(@DATA); + $used_resource = \@DATA; + } + + foreach my $one_case (@{$self->{commit_list}}) { + $used_resource = &_do_editkey($one_case,$used_resource,$self) if ($one_case->{'action'} eq 'editkey' || $one_case->{'action'} eq 'delkey'); + $used_resource = &_do_delsection($one_case,$used_resource,$self) if ($one_case->{'action'} eq 'delsection' || $one_case->{'action'} eq 'replacesection'); + $used_resource = &_do_addsection($one_case,$used_resource,$self) if ($one_case->{'action'} eq 'addsection'); + $used_resource = &_do_append($one_case,$used_resource,$self) if ($one_case->{'action'} eq 'append'); + $used_resource = &_do_matchreplace($one_case,$used_resource,$self) if ($one_case->{'action'} eq 'matchreplace'); + if ($one_case->{'action'} eq 'cleanfile') { + undef($used_resource); + last; + } + } + + + #save file and check new_file + if (defined $opts{'new_file'} && $opts{'new_file'} ne '') { + open(SAVE,">$opts{'new_file'}") or die "Asterisk-config Save_file can't write : $!"; + } else { + open(SAVE,">$self->{'file'}") or die "Asterisk-config Save_file can't write : $!"; + } + flock(SAVE,LOCK_EX); + print SAVE grep{$_.="\n"} @{$used_resource}; + flock(SAVE,LOCK_UN); + close(SAVE); + + #reload when save + if (defined $self->{'reload_when_save'} && $self->{'reload_when_save'}) { + &reload($self); + } + +return(); +} + +sub _do_editkey +{ +my $one_case = shift; +my $data = shift; +my $class_self = shift; + +my @NEW; +my $last_section_name='[unsection]'; +my $auto_save=0; + + foreach my $one_line (@$data) { + + #tune on auto save + if ($auto_save) { push(@NEW,$one_line); next; } + + my $line_sp=&_clean_string($one_line,$class_self->{comment_flag}); + + #income new section + if ($line_sp =~ /^\[(.+)\]/) { + $last_section_name = $1; + } elsif ($last_section_name eq $one_case->{section} && $line_sp =~ /\=/) { + + #split data and key + my ($key,$value)=&_clean_keyvalue($line_sp); + + if ($key eq $one_case->{'key'} && $one_case->{'value_regexp'} && !$one_case->{'value'}) { + $value =~ /(.+?)\,/; + if ($one_case->{'action'} eq 'delkey' && $1 eq $one_case->{'value_regexp'}){ undef($one_line); } + + } elsif ($key eq $one_case->{'key'} && !$one_case->{'value'}) { #处理全部匹配的key的value值 + if ($one_case->{'action'} eq 'delkey') { undef($one_line); } + else { $one_line = "$key=".$one_case->{'new_value'}; } +# $one_line = "$key=".$one_case->{'new_value'}; +# undef($one_line) if ($one_case->{'action'} eq 'delkey'); + } elsif ($key eq $one_case->{'key'} && $one_case->{'value'} eq $value) { #处理唯一匹配的key的value值 + if ($one_case->{'action'} eq 'delkey') { undef($one_line); } + else { $one_line = "$key=".$one_case->{'new_value'}; } +# $one_line = "$key=".$one_case->{'new_value'}; +# undef($one_line) if ($one_case->{'action'} eq 'delkey'); + $auto_save = 1; + } + } + + push(@NEW,$one_line) if (defined $one_line); + } + +return(\@NEW); +} + +sub _do_delsection +{ +my $one_case = shift; +my $data = shift; +my $class_self = shift; + +my @NEW; +my $last_section_name='[unsection]'; +my $auto_save=0; + + push(@NEW,&_format_convert($one_case->{'data'})) + if ($one_case->{'section'} eq '[unsection]' and $one_case->{'action'} eq 'replacesection'); + + foreach my $one_line (@$data) { + + #tune on auto save + if ($auto_save) { push(@NEW,$one_line); next; } + + my $line_sp=&_clean_string($one_line,$class_self->{comment_flag}); + + if ($last_section_name eq $one_case->{'section'} && $line_sp =~ /^\[(.+)\]/) { + #when end of compared section and come new different section + $auto_save = 1; + } elsif ($last_section_name eq $one_case->{'section'}) { + next; + } elsif ($line_sp =~ /^\[(.+)\]/) { + #is this new section? + if ($one_case->{'section'} eq $1) { + $last_section_name = $1; + next if ($one_case->{'action'} eq 'delsection'); + push(@NEW,$one_line); + $one_line=&_format_convert($one_case->{'data'}); + } + } + + push(@NEW,$one_line); + } + +return(\@NEW); +} + +sub _do_addsection +{ +my $one_case = shift; +my $data = shift; +my $class_self = shift; + +my $exists = 0; +my $section = '[' . $one_case->{section} . ']'; + + foreach my $one_line(@$data) { + + my $line_sp=&_clean_string($one_line,$class_self->{comment_flag}); + if($line_sp =~ /^\[.+\]/) { + + if ($section eq $line_sp) { + $exists = 1; + last; + } + } + } + unless($exists) { + + push(@$data, $section); + } + +return $data; +} + +sub _do_append +{ +my $one_case = shift; +my $data = shift; +my $class_self = shift; +my @NEW; + + if ($one_case->{'section'} eq '') { + #Append data head of source data/foot of source data + if ($one_case->{'point'} eq 'up') { + push(@NEW,&_format_convert($one_case->{'data'}),@$data); + } else { + push(@NEW,@$data,&_format_convert($one_case->{'data'})); + } + + } elsif (!defined $one_case->{'comkey'} || $one_case->{'comkey'} eq '') { + #Append data head/foot of section_name + my $auto_save=0; + my $save_tmpmem=0; + my $offset=0; + foreach my $one_line (@$data) { + #tune on auto save + if ($auto_save) { push(@NEW,$one_line); $offset++; next; } + #check section + my $line_sp=&_clean_string($one_line,$class_self->{comment_flag}); + my ($section_name) = $line_sp =~ /^\[(.+)\]/; + + # for up / down + if (defined $section_name && $one_case->{'section'} eq $section_name && $one_case->{'point'} eq 'up') { + push(@NEW,&_format_convert($one_case->{'data'})); $auto_save=1; + } elsif (defined $section_name && $one_case->{'section'} eq $section_name && $one_case->{'point'} eq 'down') { + push(@NEW,$one_line); $one_line=&_format_convert($one_case->{'data'}); $auto_save=1; + # for foot matched section + } elsif (defined $section_name && $one_case->{'section'} eq $section_name && $one_case->{'point'} eq 'foot') { + $save_tmpmem=1; + # for foot 发现要从匹配的section换成新section + } elsif ($save_tmpmem == 1 && $section_name && $one_case->{'section'} ne $section_name) { + push(@NEW,&_format_convert($one_case->{'data'})); $auto_save=1; $save_tmpmem=0; + # for foot 发现匹配的section已经到达整个结尾 + } + if ($save_tmpmem == 1 && $offset==$#{$data}) { + push(@NEW,$one_line); $one_line=&_format_convert($one_case->{'data'}); + $auto_save=1; $save_tmpmem=0; + } + + push(@NEW,$one_line); + $offset++; + } + + } else { + + my $last_section_name='[unsection]'; + my $auto_save=0; + foreach my $one_line (@$data) { + + #tune on auto save + if ($auto_save) { push(@NEW,$one_line); next; } + + my $line_sp=&_clean_string($one_line,$class_self->{comment_flag}); + #income new section + if ($line_sp =~ /^\[(.+)\]/) { + $last_section_name = $1; + } elsif ($last_section_name eq $one_case->{'section'} && $line_sp =~ /\=/) { + #split data and key + my ($key,$value)=&_clean_keyvalue($line_sp); + if ($key eq $one_case->{comkey}[0] && $value eq $one_case->{comkey}[1] && $one_case->{'point'} eq 'up') { + push(@NEW,&_format_convert($one_case->{'data'})); $auto_save=1; + } elsif ($key eq $one_case->{comkey}[0] && $value eq $one_case->{comkey}[1] && $one_case->{'point'} eq 'down') { + push(@NEW,$one_line); $one_line=&_format_convert($one_case->{'data'}); + $auto_save=1; + } elsif ($key eq $one_case->{comkey}[0] && $value eq $one_case->{comkey}[1] && $one_case->{'point'} eq 'over') { + $one_line=&_format_convert($one_case->{'data'}); $auto_save=1; + } + } + push(@NEW,$one_line); + } + + } + +return(\@NEW); +} + +# income scalar,array ref,hash ref output array data +sub _format_convert +{ +my $string = shift; + if (ref($string) eq 'ARRAY') { + return(@$string); + } elsif (ref($string) eq 'HASH') { + my @tmp; + foreach (keys(%$string)) { + push(@tmp,"$_=".$string->{$_}); + } + return(@tmp); + } else { + return($string); + } +} + +sub _do_matchreplace +{ +my $one_case = shift; +my $data = shift; +my $class_self = shift; +my @NEW; + + foreach my $one_line (@$data) { + if ($one_line =~ /$one_case->{'match'}/) { + $one_line = $one_case->{'replace'}; + } + push(@NEW,$one_line); + } + +return(\@NEW); +} + +=head1 NAME + +Asterisk::config - the Asterisk config read and write module. + +=head1 SYNOPSIS + + use Asterisk::config; + + my $sip_conf = new Asterisk::config(file=>'/etc/asterisk/sip.conf'); + my $conference = new Asterisk::config(file=>'/etc/asterisk/meetme.conf', + keep_resource_array=>0); + + $allow = $sip_conf->fetch_values_arrayref(section=>'general',key=>'allow'); + print $allow->[0]; + + $sip_conf->assign_append(point=>'down',data=>"[userb]\ntype=friend\n"); + + $sip_conf->save(); + + +=head1 DESCRIPTION + +Asterisk::config can parse and saving data with Asterisk config +files. this module support asterisk 1.0 1.2 1.4 1.6, and it also +support Zaptel config files. + +=head1 Note + +Version 0.9 syntax incompitable with 0.8. + +=head1 CLASS METHOD + +=head2 new + + $sip_conf = new Asterisk::config(file=>'file name', + [stream_data=>$string], + [object variable]); + +Instantiates a new object of file. read data from stream_data or +file. + + +=head1 OBJECT VARIABLE + +=head2 file + +config file name and path. +if file no exists (exp. data from stream_data ) you can't +saving by C. + +=head2 keep_resource_array + +use resource array when save make fast than open file, but need +more memory, default enabled. use set_objvar to change it. + +=head2 reload_when_save + +when save done, auto call . + +default enable. use set_variable to change it. + +=head2 clean_when_reload + +when reload done, auto clean_assign with current object. +default enable. use set_objvar to change it. + +=head2 commit_list + +internal variable listed all command. +i suggest don't modify and change this variable. + +=head2 parsed_conf + +internal variable of parsed. +i suggest don't modify and change this variable. + + +=head1 OBJECT READ METHOD + +=head2 get_objvar + + $sip_conf->get_objvar(var_name); + +return defined object variables. + +=head2 fetch_sections_list + + $sip_conf->fetch_sections_list(); + +only return sections name list. does not include 'unsection'. + +=head2 fetch_sections_hashref + + $sip_conf->fetch_sections_hashref(); + +this function return parsed config files data. + +=head2 fetch_keys_list + + $sip_conf->fetch_keys_list(section=>[section name|unsection]); + +return keys list of section name or unsection. + +=head2 fetch_keys_hashref + + $sip_conf->fetch_keys_hashref(section=>[section name|unsection]); + +return referenced key list (and keys value), section value 'unsection' +return all unsection keys, if section name unreachable return failed. + +=head2 fetch_values_arrayref + + $sip_conf->fetch_values_arrayref(section=>[section name|unsection], + key=>key name); + +return referenced value list, if section name unreachable return +failed. if key name unreachable return failed. + +=head2 reload + + $sip_conf->reload(); + +reload and parse config file. +if clean_when_reload true will do clean_assign. + +=head1 OBJECT WRITE METHOD + +=head2 set_objvar + + $sip_conf->set_objvar('var_name'=>'value'); + +set the object variables to new value. + +=head2 assign_cleanfile + + $sip_conf->assign_cleanfile(); + +assign clean all to file. + +=head2 assign_matchreplace + + $sip_conf->assign_matchreplace(match=>[string],replace=>[string]); + +replace new data when matched. + +=over 2 + +=item * match -> string of matched data. + +=item * replace -> new data string. + +=back + +=head2 assign_append + + $sip_conf->assign_append(point=>['up'|'down'|'foot'], + section=>[section name], + data=>'key=value'|['key=value','key=value']|{key=>'value',key=>'value'}); + +append data around with section name. + +=over 3 + +=item * point -> append data C / C / C with section. + +=item * section -> matched section name, expect 'unsection'. + +=item * data -> new replace data in string/array/hash. + +=back + + $sip_conf->assign_append(point=>['up'|'down'|'over'], + section=>[section name], + comkey=>[key,value], + data=>'key=value'|['key=value','key=value']|{key=>'value',key=>'value'}; + +append data around with section name and key/value in same section. + +=over 2 + +=item * point -> C will overwrite with key/value matched. + +=item * comkey -> match key and value. + +=back + + $sip_conf->assign_append(point=>'up'|'down', + data=>'key=value'|['key=value','key=value']|{key=>'value',key=>'value'}); + +simple append data without any section. + +=head2 assign_replacesection + + $sip_conf->assign_replacesection(section=>[section name|unsection], + data=>'key=value'|['key=value','key=value']|{key=>'value',key=>'value'}); + +replace the section body data. + +=over 1 + +=item * section -> all section name and 'unsection'. + +=back + +=head2 assign_delsection + + $sip_conf->assign_delsection(section=>[section name|unsection]); + +erase section name and section data. + +=over 1 + +=item * section -> all section and 'unsection'. + +=back + +=head2 assign_addsection + + $sip_conf->assign_addsection(section=>[section]); + +add section with name. + +=over 1 + +=item * section -> name of new section. + +=back + +=head2 assign_editkey + + $sip_conf->assign_editkey(section=>[section name|unsection],key=>[keyname],value=>[value],new_value=>[new_value]); + +modify value with matched section.if don't assign value=> will replace all matched key. + +warnning example script: + + $sip_conf->assign_editkey(section=>'990001',key=>'all',new_value=>'gsm'); + +data: + + all=g711 + all=ilbc + +will convert to: + + all=gsm + all=gsm + + +=head2 assign_delkey + + $sip_conf->assign_delkey(section=>[section name|unsection],key=>[keyname],value=>[value]); + +erase all matched C in section or in 'unsection'. + + $sip_conf->assign_delkey(section=>[section name|unsection],key=>[keyname],value_regexp=>[exten_number]); + +erase when matched exten number. + + exten => 100,n,... + exten => 102,n,... + +=head2 save_file + + $sip_conf->save_file([new_file=>'filename']); + +process commit list and save to file. +if reload_when_save true will do reload. +if no object variable file or file not exists or can't be +save return failed. +if defined new_file will save to new file, default overwrite +objvar 'file'. + +=head2 clean_assign + + $sip_conf->clean_assign(); + +clean all assign rules. + +=head1 EXAMPLES + +see example in source tree. + +=head1 AUTHORS + +Asterisk::config by Sun bing + +Version 0.7 patch by Liu Hailong. + +=head1 COPYRIGHT + +The Asterisk::config module is Copyright (c) Sun bing +All rights reserved. + +You may distribute under the terms of either the GNU General Public +License or the Artistic License, as specified in the Perl README file. + +=head1 WARRANTY + +The Asterisk::config is free Open Source software. + +IT COMES WITHOUT WARRANTY OF ANY KIND. + +=head1 SUPPORT + +Sun bing + +The Asterisk::config be Part of FreeIris opensource Telephony Project +Access http://www.freeiris.org for more details. + +=cut + +1; diff --git a/t/read.t b/t/read.t new file mode 100755 index 0000000..b267b9a --- /dev/null +++ b/t/read.t @@ -0,0 +1,12 @@ +#make sample read test +use strict; +use Test; + +use lib '../lib'; + +BEGIN { plan tests => 1 } + +use Asterisk::config; + +my $sip_conf = new Asterisk::config(file=>'t/test.conf'); +ok($sip_conf); diff --git a/t/test.conf b/t/test.conf new file mode 100755 index 0000000..1cfbf94 --- /dev/null +++ b/t/test.conf @@ -0,0 +1,25 @@ +key=value + +thisis=>unsection + +[general] +useragent=hoowa +disallow=all +allow=g729 +allow=>g723 #comment +allow=ulaw +#include classsip.conf + +[usera] +type=friend;saying +secret=thisone +host=>dynamic + +[trunka] +type=friend +host=192.168.0.1 + +#include branchsip.conf + +[tempsection] +delete=me -- cgit v1.2.3