package NGCP::Panel::Controller::Pbx; use NGCP::Panel::Utils::Generic qw(:all); use Sipwise::Base; use parent 'Catalyst::Controller'; use NGCP::Panel::Utils::Message; use NGCP::Panel::Utils::DateTime; use NGCP::Panel::Utils::Contract; use NGCP::Panel::Utils::Phonebook; sub auto :Private { my ($self, $c) = @_; $c->log->debug(__PACKAGE__ . '::auto'); NGCP::Panel::Utils::Navigation::check_redirect_chain(c => $c); return 1; } sub base :Chained('/') :PathPart('') :CaptureArgs(0) :Does(License) :RequiresLicense('device_provisioning') :RequiresLicense('pbx') :RequiresLicense('phonebook') :LicenseDetachTo('/denied_page') { my ($self, $c) = @_; $c->stash->{schema} = $c->config->{deviceprovisioning}->{secure} ? 'https' : 'http'; $c->stash->{host} = $c->config->{deviceprovisioning}->{host} // $c->req->uri->host; $c->stash->{port} = $c->config->{deviceprovisioning}->{port} // 1444; $c->stash->{cisco_port} = $c->config->{deviceprovisioning}->{cisco_port} // 1447; $c->log->debug("SSL_CLIENT_M_DN: " . ($c->request->env->{SSL_CLIENT_M_DN} // "")); unless( ($c->user_exists && ($c->user->roles eq "admin" || $c->user->roles eq "reseller")) || defined $c->request->env->{SSL_CLIENT_M_DN} ) { $c->response->content_type('text/plain'); if($c->config->{features}->{debug}) { $c->response->body("403 - unauthenticated pbx access"); } else { $c->response->body("403 - forbidden"); } $c->response->status(403); return; } } sub spa_directory_getsearch :Chained('base') :PathPart('pbx/directory/spasearch') :Args(1) { my ($self, $c, $id) = @_; my $schema = $c->stash->{schema}; my $host = $c->stash->{host}; my $port = $c->stash->{cisco_port}; my $baseuri = "$schema://$host:$port/pbx/directory/spa/$id"; my $data = ''; $data = <<EOF; <CiscoIPPhoneInput> <Title>Search User</Title> <Prompt>Enter (part of) Name</Prompt> <URL>$baseuri</URL> <InputItem> <QueryStringParam>q</QueryStringParam> <InputFlags>A</InputFlags> </InputItem> </CiscoIPPhoneInput> EOF $c->log->debug("providing config to $id"); $c->log->debug($data); $c->response->content_type('text/xml'); $c->response->body($data); return; } sub spa_directory_list :Chained('base') :PathPart('pbx/directory/spa') :Args(1) { my ($self, $c, $id) = @_; unless($id) { $c->response->content_type('text/plain'); if($c->config->{features}->{debug}) { $c->response->body("404 - device id not given"); } else { $c->response->body("404 - device not found"); } $c->response->status(404); return; } $id =~ s/^([^\=]+)\=0$/$1/; $id = lc $id; my $dev = $c->model('DB')->resultset('autoprov_field_devices')->find({ identifier => $id }); unless($dev) { $c->response->content_type('text/plain'); if($c->config->{features}->{debug}) { $c->response->body("404 - device id '" . $id . "' not found"); } else { $c->response->body("404 - device not found"); } $c->response->status(404); return; } my $schema = $c->stash->{schema}; my $host = $c->stash->{host}; my $port = $c->stash->{cisco_port}; my $baseuri = "$schema://$host:$port/pbx/directory/spa/$id"; my $data = ''; my $delim = '?'; my $q; my $dirsuffix = ''; if(exists $c->req->params->{q} && length($c->req->params->{q})) { $q = $c->req->params->{q}; $baseuri .= "?q=$q"; $delim = '&'; $dirsuffix = ' (Search Results)'; } my $customer = $dev->contract; my $page = $c->req->params->{page} // 1; my $rows = 10; my $rs = $self->_get_dirsearch_rs($customer, $q); my $total = $rs->count; my ($nextpage, $prevpage); if(($total / $rows) > $page ) { $nextpage = $page + 1; } if($page > 1) { $prevpage = $page - 1; } my @entries = (); my %entries = (); foreach my $sub($rs->search(undef,{page => $page, rows => $rows})->all) { my $prov_sub = $sub->provisioning_voip_subscriber; next unless($prov_sub && $prov_sub->pbx_extension); my $display_name = $sub->get_column('display_name'); push @entries, { name => $display_name, ext => $prov_sub->pbx_extension }; $entries{$prov_sub->pbx_extension} = 1; } $self->add_phonebook_entries($c, $dev, \@entries, \%entries); my $nexturi = $baseuri . $delim . 'page='.($nextpage//0); my $prevuri = $baseuri . $delim . 'page='.($prevpage//0); my $searchuri = "$schema://$host:$port/pbx/directory/spasearch/$id"; $data = "<CiscoIPPhoneDirectory><Title>PBX Address Book$dirsuffix</Title><Prompt>Select the User</Prompt>"; $data .= join '', map {"<DirectoryEntry><Name>$$_{name}</Name><Telephone>$$_{ext}</Telephone></DirectoryEntry>"} @entries; $data .= "<SoftKeyItem><Name>Dial</Name><URL>SoftKey:Dial</URL><Position>1</Position></SoftKeyItem>"; if($prevpage) { $data .= "<SoftKeyItem><Name>Prev</Name><URL>$prevuri</URL><Position>2</Position></SoftKeyItem>"; } else { $data .= "<SoftKeyItem><Name>Search</Name><URL>$searchuri</URL><Position>2</Position></SoftKeyItem>"; } $data .= "<SoftKeyItem><Name>Next</Name><URL>$nexturi</URL><Position>3</Position></SoftKeyItem>" if($nextpage); $data .= "<SoftKeyItem><Name>Cancel</Name><URL>Init:Services</URL><Position>4</Position></SoftKeyItem>"; $data .= '</CiscoIPPhoneDirectory>'; $c->log->debug("providing config to $id"); $c->log->debug($data); $c->response->content_type('text/xml'); $c->response->body($data); } sub panasonic_directory_list :Chained('base') :PathPart('pbx/directory/panasonic') :Args() { my ($self, $c) = @_; my $id = $c->req->params->{userid}; my $q = $c->req->params->{name}; unless($id) { $c->response->content_type('text/plain'); if($c->config->{features}->{debug}) { $c->response->body("404 - device id not given"); } else { $c->response->body("404 - device not found"); } $c->response->status(404); return; } $id =~ s/^([^\=]+)\=0$/$1/; $id = lc $id; my $dev = $c->model('DB')->resultset('autoprov_field_devices')->find({ identifier => $id }); unless($dev) { $c->response->content_type('text/plain'); if($c->config->{features}->{debug}) { $c->response->body("404 - device id '" . $id . "' not found"); } else { $c->response->body("404 - device not found"); } $c->response->status(404); return; } my $schema = $c->stash->{schema}; my $host = $c->stash->{host}; my $port = $c->stash->{port}; my $customer = $dev->contract; my $rs = $self->_get_dirsearch_rs($customer, $q); my @entries = (); my %entries = (); foreach my $sub($rs->all) { my $prov_sub = $sub->provisioning_voip_subscriber; next unless($prov_sub && $prov_sub->pbx_extension); my $display_name = $sub->get_column('display_name'); push @entries, { name => $display_name, ext => $prov_sub->pbx_extension }; $entries{$prov_sub->pbx_extension} = 1; } $self->add_phonebook_entries($c, $dev, \@entries, \%entries); my $data = <<'EOS_XML'; <?xml version="1.0" encoding="utf-8"?> <ppxml xmlns="http://panasonic/sip_phone" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://panasonic/sip_phone sip_phone.xsd"> <Screen version="2.0"> <PhoneBook version="2.0"> EOS_XML my $person_id = 0; $data .= join '', map { $person_id++; <<EOS_XMLLOOP; <Personnel id="$person_id"> <Name>$$_{name}</Name> <PhoneNums> <PhoneNum type="ext">$$_{ext}</PhoneNum> </PhoneNums> </Personnel> EOS_XMLLOOP } @entries; $data .= <<EOS_XML; </PhoneBook> </Screen> </ppxml> EOS_XML $c->log->debug("providing config to $id"); $c->log->debug($data); $c->response->content_type('text/xml'); $c->response->body($data); } sub yealink_directory_list :Chained('base') :PathPart('pbx/directory/yealink') :Args() { my ($self, $c) = @_; my $id = $c->req->params->{userid}; my $q = $c->req->params->{name}; unless($id) { $c->response->content_type('text/plain'); if($c->config->{features}->{debug}) { $c->response->body("404 - device id not given"); } else { $c->response->body("404 - device not found"); } $c->response->status(404); return; } $id =~ s/^([^\=]+)\=0$/$1/; $id = lc $id; my $dev = $c->model('DB')->resultset('autoprov_field_devices')->find({ identifier => $id }); unless($dev) { $c->response->content_type('text/plain'); if($c->config->{features}->{debug}) { $c->response->body("404 - device id '" . $id . "' not found"); } else { $c->response->body("404 - device not found"); } $c->response->status(404); return; } my $schema = $c->stash->{schema}; my $host = $c->stash->{host}; my $port = $c->stash->{port}; my $customer = $dev->contract; my $rs = $self->_get_dirsearch_rs($customer, $q); my @entries = (); my %entries = (); foreach my $sub($rs->all) { my $prov_sub = $sub->provisioning_voip_subscriber; next unless($prov_sub && $prov_sub->pbx_extension); my $display_name = $sub->get_column('display_name'); push @entries, { name => $display_name, ext => $prov_sub->pbx_extension }; $entries{$prov_sub->pbx_extension} = 1; } $self->add_phonebook_entries($c, $dev, \@entries, \%entries); my $req_uri = $c->req->uri; my $data = <<EOS_XML; <?xml version="1.0" encoding="utf-8"?> <SipwiseIPPhoneDirectory> <SoftKeyItem> <Name>0</Name> <URL>$req_uri</URL> </SoftKeyItem> EOS_XML $data .= join '', map { <<EOS_XMLLOOP; <DirectoryEntry> <Name>$$_{name}</Name> <Telephone>$$_{ext}</Telephone> </DirectoryEntry> EOS_XMLLOOP } @entries; $data .= '</SipwiseIPPhoneDirectory>'; $c->log->debug("providing config to $id"); $c->log->debug($data); $c->response->content_type('text/xml'); $c->response->body($data); } sub polycom_directory_list :Chained('base') :PathPart('pbx/directory/polycom') :Args(1) { my ($self, $c, $id) = @_; $id =~ s/\-directory\.xml$//; my $q; unless($id) { $c->response->content_type('text/plain'); if($c->config->{features}->{debug}) { $c->response->body("404 - device id not given"); } else { $c->response->body("404 - device not found"); } $c->response->status(404); return; } $id = lc $id; my $dev = $c->model('DB')->resultset('autoprov_field_devices')->find({ identifier => $id }); unless($dev) { $c->response->content_type('text/plain'); if($c->config->{features}->{debug}) { $c->response->body("404 - device id '" . $id . "' not found"); } else { $c->response->body("404 - device not found"); } $c->response->status(404); return; } my $schema = $c->stash->{schema}; my $host = $c->stash->{host}; my $port = $c->stash->{port}; my $customer = $dev->contract; my $rs = $self->_get_dirsearch_rs($customer, $q); my @entries = (); my %entries = (); foreach my $sub($rs->all) { my $prov_sub = $sub->provisioning_voip_subscriber; next unless($prov_sub && $prov_sub->pbx_extension); my $display_name = $sub->get_column('display_name'); push @entries, { name => $display_name, ext => $prov_sub->pbx_extension }; $entries{$prov_sub->pbx_extension} = 1; } $self->add_phonebook_entries($c, $dev, \@entries, \%entries); foreach my $entry (@entries) { my ($fname, @rest) = split / +/, $entry->{name}; my $lname = join ' ', @rest; $entry->{fname} = $fname; $entry->{lname} = $lname; } my $data = <<EOS_XML; <?xml version="1.0" encoding="utf-8"?> <directory> <item_list> EOS_XML # ln last name # fn first name # ct contact # sd speed-dial index # rt ring type # dc divert contact for auto divert # ad auto divert # ar auto reject # bw buddy watching # bb buddy block $data .= join '', map { <<EOS_XMLLOOP; <item> <ln>$$_{lname}</ln> <fn>$$_{fname}</fn> <ct>$$_{ext}</ct> <sd/> <rt/> <dc/> <ad>0</ad> <ar>0</ar> <bw>0</bw> <bb>0</bb> </item> EOS_XMLLOOP } @entries; $data .= '</item_list></directory>'; $c->log->debug("providing config to $id"); $c->log->debug($data); $c->response->content_type('text/xml'); $c->response->body($data); } sub _get_dirsearch_rs :Private { my ($self, $customer, $q) = @_; my $rs = $customer->voip_subscribers->search({ 'status' => 'active', 'provisioning_voip_subscriber.pbx_extension' => { '!=' => undef }, 'voip_usr_preferences.value' => { '!=' => undef }, 'attribute.attribute' => 'display_name', defined $q ? ( -or => [ 'voip_usr_preferences.value' => { like => "%$q%" }, 'provisioning_voip_subscriber.pbx_extension' => { like => "$q%" } ] ) : (), },{ join => { provisioning_voip_subscriber => { voip_usr_preferences => 'attribute' } }, '+select' => [qw/voip_usr_preferences.value/], '+as' => [qw/display_name/], order_by => { '-asc' => 'voip_usr_preferences.value' }, }); return $rs; } sub add_phonebook_entries { my ($self, $c, $dev, $entries, $entries_existent) = @_; my %phonebook = (); foreach my $private_line ($dev->autoprov_field_device_lines->search_rs({ line_type => 'private' })->all) { my $private_line_subscriber_id = $private_line->provisioning_voip_subscriber->voip_subscriber->id; $phonebook{$private_line_subscriber_id} //= NGCP::Panel::Utils::Phonebook::get_subscriber_phonebook($c, $private_line_subscriber_id); foreach my $entry (@{$phonebook{$private_line_subscriber_id}}) { push @$entries, { name => $entry->{name}, ext => $entry->{number} } unless $entries_existent->{$entry->{number}}; $entries_existent->{$entry->{number}} = 1; } } } 1; __END__ =head1 NAME NGCP::Panel::Controller::Pbx =head1 DESCRIPTION A controller to manipulate the PBX data =head1 AUTHOR Sipwise Development Team =head1 LICENSE This library is free software. You can redistribute it and/or modify it under the same terms as Perl itself. =cut # vim: set tabstop=4 expandtab: