--- /dev/null
+blib*
+Makefile
+Makefile.old
+Build
+_build*
+pm_to_blib*
+*.tar.gz
+.lwpcookies
+Net-Indosoft-Voicebridge-*
+cover_db
--- /dev/null
+Revision history for Net-Indosoft-Voicebridge
+
+0.01 unreleased
+ First version, released on an unsuspecting world.
+
--- /dev/null
+Changes
+MANIFEST
+Makefile.PL
+README
+voicebridgeAPI.wsdl
+lib/Net/Indosoft/Voicebridge.pm
+t/00-load.t
+t/01-Account_Client_Conference.t
+t/pod-coverage.t
+t/pod.t
--- /dev/null
+use strict;
+use warnings;
+use ExtUtils::MakeMaker;
+
+WriteMakefile(
+ NAME => 'Net::Indosoft::Voicebridge',
+ AUTHOR => 'Ivan Kohler <ivan-voicebridge@freeside.biz>',
+ VERSION_FROM => 'lib/Net/Indosoft/Voicebridge.pm',
+ ABSTRACT_FROM => 'lib/Net/Indosoft/Voicebridge.pm',
+ PL_FILES => {},
+ PREREQ_PM => {
+ 'Test::More' => 0,
+ 'SOAP::Lite' => 0,
+ },
+ dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
+ clean => { FILES => 'Net-Indosoft-Voicebridge-*' },
+);
--- /dev/null
+Net-Indosoft-Voicebridge
+
+This is an interface to the Indosoft Voicebridge API. It is only useful if you
+have an account with Indosoft to resell confernce bridge service.
+
+INSTALLATION
+
+To install this module, run the following commands:
+
+ perl Makefile.PL
+ make
+ make test
+ make install
+
+SUPPORT AND DOCUMENTATION
+
+After installing, you can find documentation for this module with the
+perldoc command.
+
+ perldoc Net::Indosoft::Voicebridge
+
+You can also look for information at:
+
+ RT, CPAN's request tracker
+ http://rt.cpan.org/NoAuth/Bugs.html?Dist=Net-Indosoft-Voicebridge
+
+ AnnoCPAN, Annotated CPAN documentation
+ http://annocpan.org/dist/Net-Indosoft-Voicebridge
+
+ CPAN Ratings
+ http://cpanratings.perl.org/d/Net-Indosoft-Voicebridge
+
+ Search CPAN
+ http://search.cpan.org/dist/Net-Indosoft-Voicebridge
+
+
+COPYRIGHT AND LICENCE
+
+Copyright (C) 2009 Freeside Internet Services, Inc.
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl itself.
+
--- /dev/null
+package Net::Indosoft::Voicebridge;
+
+use warnings;
+use strict;
+use Data::Dumper;
+use SOAP::Lite;
+
+our $AUTOLOAD;
+our $DEBUG = 1;
+
+=head1 NAME
+
+Net::Indosoft::Voicebridge - Interface to Indosoft Voicebridge API
+
+=head1 VERSION
+
+Version 0.01
+
+=cut
+
+our $VERSION = '0.01';
+
+=head1 SYNOPSYS
+
+ use Net::Indosoft::Voicebridge;
+
+ my $handle = Net::GlobalPOPs::MediaServicesAPI->new(
+ 'url' => 'http://your_tag.kanobe.net:8080/vbsoap/voicebridgeAPI.php',
+ );
+
+=head1 METHODS
+
+=head2 new
+
+Creates a new Net::Indosoft::Voicebridge object.
+
+=cut
+
+sub new {
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+ my $self = ref($_[0]) ? shift : { @_ };
+
+# my $soap = new SOAP::Lite (
+# 'service' => $URL.'?wsdl',
+# );
+# $self->{soap} = $soap;
+
+ bless($self, $class);
+}
+
+#ideally this could be retreived from the WSDL, but hey
+# or at least derived from the method name?
+our %requestobj = (
+ 'addAccount' => 'Account',
+ 'modifyAccount' => 'Account',
+ 'addClient' => 'Client',
+ 'modifyClient' => 'Client',
+ 'addConference' => 'Conference',
+ 'modifyConference' => 'Conference',
+);
+
+#this is think they're just on crack. returnning a string to parse inside
+#a ton of XML? somehow that misses the point.
+our %returnparse = (
+ 'addAccount' => [ qw( account_id ) ],
+ 'modifyAccount' => [ qw( account_id ) ],
+ 'addClient' => [ qw( client_id ) ],
+ 'modifyClient' => [ qw( client_id ) ],
+ 'addConference' => [ qw( conference_id moderator_pin participant_pin ) ],
+ 'modifyConference' => [ qw( conference_id ) ],
+);
+
+sub AUTOLOAD {
+ my $self = shift;
+
+ $AUTOLOAD =~ /(^|::)(\w+)$/ or die "unparsable AUTOLOAD: $AUTOLOAD";
+ my $function = $2;
+ return if $function eq 'DESTROY';
+
+ my $uri = "voicebridgeAPI/$function";
+
+
+ my $soap = SOAP::Lite
+# -> readable(1)
+ -> proxy($self->{url})
+# -> on_action( sub { join '/', @_ } ) #according to the wsdl, right?
+# -> on_action( sub { "urn:voicebridgeAPI/$function" } )
+ -> autotype(0)
+# -> default_ns("urn:voicebridgeAPI")
+ ;
+
+ my $request;
+ my $obj = $requestobj{$function};
+ if ( $obj ) {
+
+ my $opts = ref($_[0]) ? shift : { @_ };
+ if ( $DEBUG > 1 ) {
+ warn "$_: ". $opts->{$_}. "\n" foreach keys %$opts;
+ }
+
+ $request = SOAP::Data->name( $obj =>
+ \SOAP::Data->value(
+ map SOAP::Data->name( $_ )->value( $opts->{$_} ), keys %$opts
+ )
+ );
+
+ } else {
+
+ $request = shift;
+
+ }
+
+ my $som = $soap->call( $function, $request );
+
+ die $som->faultstring if $som->fault;
+ return { 'error' => $som->faultdetail } if $som->fault;
+
+ warn Dumper($som->body) if $DEBUG > 1;
+
+ my $return = $som->valueof("//${function}Response/return");
+
+ if ( $return =~ /^<errors/i ) {
+ my $rsom = SOAP::Deserializer->deserialize($return);
+ my @errors = $rsom->valueof('//errors/error');
+ return { 'error' => join(' / ', @errors ) } if @errors;
+ }
+
+ if ( $function =~ /^delete/ && $return !~ /Deleted Success?fully/i ) {
+ return { 'error' => 'Deletion unsuccessful',
+ 'return' => $return,
+ };
+ }
+
+ my %return = ( 'return'=>$return );
+ foreach my $rp ( @{ $returnparse{$function} || [] } ) {
+ #are they always numeric?
+ $return =~ /\W$rp\s*=\s*(\d+)/ and $return{$rp} = $1;
+ }
+
+ return \%return;
+}
+
+=head2 addAccount
+
+Pass a list of key=>value pairs or a hash reference:
+
+i.account_name: Required Field: Alpha Numeric
+ii.account_desc: Alpha Numeric
+iii.account_addr: Alpha Numeric
+iv.account_city: Alpha Numeric
+v.account_state: Alpha Numeric
+vi.account_country: Alpha Numeric
+vii.account_zip: Alpha Numeric
+viii.account_phone: Required Field: Alpha Numeric Ex: 123-123-1234
+ix.account_fax: Alpha Numeric
+x.account_email: Required Field, have to be in valid email format
+xi.account_password: Required Field: Alpha Numeric
+
+Returns a hash reference with one element, either 'error' for error conditions,
+or 'account_id' if the account is created sucessfully.
+
+=head2 modifyAccount
+
+Pass a list of key=>value pairs or a hash reference:
+
+xiv.account_id: Required Field (Provided when the account was created)
+xv.account_name: Required Field
+xvi.account_desc
+xvii.account_addr
+xviii.account_city
+xix.account_state
+xx.account_country
+xxi.account_zip
+xxii.account_phone: Required Field
+xxiii.account_fax
+xxiv.account_email: Required Field
+xxv.account_password: Required Field
+
+Returns a hash reference with one element, either 'error' for error conditions,
+or 'account_id' if the account is modified sucessfully.
+
+=head2 addClient
+
+Pass a list of key=>value pairs or a hash reference:
+
+account_id: Required Field Alpha Numeric
+client_contact_name: Required Field Alpha Numeric
+client_contact_addr Alpha Numeric
+client_contact_city Alpha Numeric
+client_contact_state Alpha Numeric
+client_contact_country Alpha Numeric
+client_contact_zip Alpha Numeric
+client_contact_phone: Required Field Alpha Numeric
+client_contact_fax Alpha Numeric
+client_contact_email: Required Field Alpha Numeric
+client_contact_password: Required Field Alpha Numeric
+
+Returns a hash reference with one element, either 'error' for error conditions,
+or 'client_id' if the account is created sucessfully.
+
+=head2 modifyClient
+
+Pass a list of key=>value pairs or a hash reference:
+
+client_id: Required Field
+account_id: Required Field
+client_contact_name: Required Field
+client_contact_addr
+client_contact_city
+client_contact_state
+client_contact_country
+client_contact_zip
+client_contact_phone: Required Field
+client_contact_fax
+client_contact_email: Required Field
+client_contact_password: Required Field
+
+Returns a hash reference with one element, either 'error' for error conditions,
+or 'client_id' if the account is modified sucessfully.
+
+=head2 addConference
+
+Pass a list of key=>value pairs or a hash reference:
+
+client_id: Required Field Alpha Numeric (Required to associate conference to client, client ID provided when new client is added)
+conference_name: Required Field Alpha Numeric
+conference_desc Alpha Numeric
+start_time: Required Field Alpha Numeric
+moderated_flag:
+1 ¿ Presentation mode
+0 ¿ Conversation Mode
+entry_ann_flag: Integer
+0 ¿ None
+1 - Tone
+2 - Name
+record_flag: Integer
+0 ¿ Stop Recording
+1 ¿ Start Recording
+moh_flag: Integer
+0 ¿ Stop MOH
+1 ¿ Start MOH
+talk_detect_flag
+play_user_cnt_flag: Integer
+1- Announce number of conference members currently in conference
+0 ¿ no Announcement
+wait_for_admin_flag: Integer
+1 - Only start conference once admin enters
+0 ¿ all users without admin
+stop_on_admin_exit_flag: Integer
+1 - End conference when admin exits:
+0 - No
+second_pin_flag: Integer
+1 - Prompt conference members for a second pin/password when logging in?
+0 - No Extra conference PIN
+secondary_pin: Integer
+If second_pin_flag is 1 also pass the PIN
+allow_sub_conf: Integer
+1 ¿ Allow sub conference for this conference
+0 ¿ Donot Allow sub conference
+duration: Integer
+Duration in minutes e.g 30 for 30 minutes
+conference_type: reservationless/reserved
+
+On errors, returns a hash reference with one element, 'error', otherwise
+returns a hash reference with the following keys: conference_id, moderator_pin
+and participant_pin.
+
+=head2 modifyConference
+
+Pass a list of key=>value pairs or a hash reference:
+
+conference_id: Required Field
+client_id: Required Field
+conference_name: Required Field
+conference_desc
+start_time: Required Field
+moderated_flag:
+1 ¿ Presentation mode
+0 ¿ Conversation Mode
+entry_ann_flag: Integer
+0 ¿ None
+1 - Tone
+2 - Name
+record_flag: Integer
+0 ¿ Stop Recording
+1 ¿ Start Recording
+moh_flag: Integer
+0 ¿ Stop MOH
+1 ¿ Start MOH
+play_user_cnt_flag: Integer
+1- Announce number of conference members currently in conference
+0 ¿ no Announcement
+wait_for_admin_flag: Integer
+1 - Only start conference once admin enters
+0 ¿ all users without admin
+stop_on_admin_exit_flag: Integer
+1 - End conference when admin exits:
+0 - No
+second_pin_flag: Integer
+1 - Prompt conference members for a second pin/password when logging in?
+0 - No Extra conference PIN
+secondary_pin: Integer
+If second_pin_flag is 1 also pass the PIN
+allow_sub_conf: Integer
+1 ¿ Allow sub conference for this conference
+0 ¿ Donot Allow sub conference
+duration: Integer
+Duration in minutes e.g 30 for 30 minutes
+
+Returns a hash reference with one element, either 'error' for error conditions,
+or 'conference_id' if the conference is modified sucessfully.
+
+=head2 deleteAccount
+
+Pass a list of key=>value pairs or a hash reference:
+
+i.account_id: Required Field
+
+On errors, should returns a hash reference with one element, 'error'.
+
+=head2 deleteClient
+
+Pass a list of key=>value pairs or a hash reference:
+
+ii.client_id: Required Field
+
+On errors, should returns a hash reference with one element, 'error'.
+
+=head2 deleteConference
+
+Pass a list of key=>value pairs or a hash reference:
+
+iii.conference_id: Required Field
+
+On errors, should returns a hash reference with one element, 'error'.
+
+=head1 The services below are not yet documented/online
+
+=head2 addConferencePIN
+
+=head2 modifyConferencePIN
+
+=head2 deleteConferencePIN
+
+=head2 addDNIS
+
+=head2 modifyDNIS
+
+=head2 deleteDNIS
+
+=head1 AUTHOR
+
+Ivan Kohler, C<< <ivan-voicebridge at freeside.biz> >>
+
+=head1 BUGS
+
+Please report any bugs or feature requests to C<bug-net-indosoft-voicebridge at rt.cpan.org>, or through
+the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Net-Indosoft-Voicebridge>. I will be notified, and then you'll
+automatically be notified of progress on your bug as I make changes.
+
+=head1 SUPPORT
+
+You can find documentation for this module with the perldoc command.
+
+ perldoc Net::Indosoft::Voicebridge
+
+You can also look for information at:
+
+=over 4
+
+=item * RT: CPAN's request tracker
+
+L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Net-Indosoft-Voicebridge>
+
+=item * AnnoCPAN: Annotated CPAN documentation
+
+L<http://annocpan.org/dist/Net-Indosoft-Voicebridge>
+
+=item * CPAN Ratings
+
+L<http://cpanratings.perl.org/d/Net-Indosoft-Voicebridge>
+
+=item * Search CPAN
+
+L<http://search.cpan.org/dist/Net-Indosoft-Voicebridge>
+
+=back
+
+=head1 ACKNOWLEDGEMENTS
+
+This module was developed by Freeside Internet Services, Inc.
+If you need a complete, open-source web-based application to manage your
+customers, conferences, billing and trouble ticketing, please visit
+http://freeside.biz/
+
+Development sponsored by NxxTcom Conferencing. If you need a cost-effective
+voice, web or video conference, please visit http://www.nxxtcom.net/
+
+=head1 COPYRIGHT & LICENSE
+
+Copyright (c) 2009 Freeside Internet Services, Inc. <http://freeside.biz/>
+All rights reserved.
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl itself.
+
+=cut
+
+1;
+
--- /dev/null
+#!perl -T
+
+use Test::More tests => 1;
+
+BEGIN {
+ use_ok( 'Net::Indosoft::Voicebridge' );
+}
+
+diag( "Testing Net::Indosoft::Voicebridge $Net::Indosoft::Voicebridge::VERSION, Perl $], $^X" );
--- /dev/null
+#!perl
+
+use Test::More;
+
+open URL, "t/URL"
+ or do { plan 'skip_all' => 'Put your URL in the t/URL file to test'; exit };
+chomp( my $URL = scalar(<URL>) );
+
+plan tests => 6 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 2;
+
+use Net::Indosoft::Voicebridge;
+
+my $vb = new Net::Indosoft::Voicebridge( 'url' => $URL );
+
+my $return;
+
+# addAccount (6)
+
+$return = $vb->addAccount(
+ 'account_name' => 'aname', #i think this is more like a username
+ 'account_password' => 'test54',
+
+ 'account_desc' => 'A test account',
+
+ 'account_addr' => '1234 Test Lane',
+ 'account_city' => 'Testville',
+ 'account_state' => 'CA',
+ 'account_zip' => '54321',
+ 'account_country' => 'US',
+
+ 'account_phone' => '415-555-1212',
+# 'account_fax' => '415-555-1212',
+ 'account_email' => 'ivan-voicebridge-test@freeside.biz',
+);
+
+ok( ! $return->{error}, 'addAccount successful' ) or warn $return->{error};
+
+like($return->{account_id}, qr/^(\d+)$/, 'addAccount returned account_id');
+
+my $account_id = $return->{account_id};
+
+$return = $vb->addAccount(
+);
+
+ok( $return->{error}, 'addAccount empty error test', );
+
+like($return->{error}, qr/Please, fill in/, 'addAccount empty error test got expected error');
+
+$return = $vb->addAccount(
+ #'account_name' => 'A. Name',
+ 'account_desc' => 'A test account',
+ 'account_addr' => '1234 Test Lane',
+ 'account_city' => 'Testville',
+ 'account_state' => 'CA',
+ 'account_zip' => '54321',
+ #'account_phone' => '415-555-1212',
+ 'account_fax' => '415-555-1212',
+ #'account_email' => 'ivan-voicebridge-test@freeside.biz',
+ #'account_password' => 'testing',
+);
+
+ok( $return->{error}, 'addAccount bad data error test', );
+
+like($return->{error}, qr/Please, fill in/, 'addAccount bad data error test got expected error');
+
+# modifyAccount (2)
+
+$return = $vb->modifyAccount(
+ 'account_id' => $account_id,
+ 'account_name' => 'anewname', #i think this is more like a username
+ 'account_password' => 'test32',
+
+ 'account_desc' => 'A modified test account',
+
+ 'account_addr' => '5432 Test Lane',
+ 'account_city' => 'Test City',
+ 'account_state' => 'NY',
+ 'account_zip' => '12345',
+ 'account_country' => 'US',
+
+ 'account_phone' => '212-555-1212',
+ 'account_fax' => '212-555-1212',
+ 'account_email' => 'ivan-voicebridge-test2@freeside.biz',
+);
+
+ok( ! $return->{error}, 'modifyAccount successful' ) or warn $return->{error};
+
+is($return->{account_id}, $account_id, 'modifyAccount returned account_id');
+
+# addClient (2)
+
+$return = $vb->addClient(
+ 'account_id' => $account_id,
+
+ 'client_contact_name' => 'Tofu Beast',
+ 'client_contact_password' => 'word54',
+
+ 'client_contact_addr' => '5432 Test Lane Suite 11',
+ 'client_contact_city' => 'Test City',
+ 'client_contact_state' => 'NY',
+ 'client_contact_country' => 'US',
+ 'client_contact_zip' => '12345',
+
+ 'client_contact_phone' => '212-555-1234',
+ 'client_contact_fax' => '212-555-1234',
+ 'client_contact_email' => 'ivan-voicebridge-test3@freeside.biz',
+
+);
+
+ok( ! $return->{error}, 'addClient successful' ) or warn $return->{error};
+
+like($return->{client_id}, qr/^(\d+)$/, 'addClient returned client_id');
+
+my $client_id = $return->{client_id};
+
+# modifyClient (2)
+
+$return = $vb->modifyClient(
+ 'account_id' => $account_id,
+ 'client_id' => $client_id,
+
+ 'client_contact_name' => 'Secret Agent X',
+ 'client_contact_password' => 'word32',
+
+ 'client_contact_addr' => '1234 Test Lane Suite 55',
+ 'client_contact_city' => 'Testville',
+ 'client_contact_state' => 'CA',
+ 'client_contact_country' => 'US',
+ 'client_contact_zip' => '54321',
+
+ 'client_contact_phone' => '415-555-1234',
+ 'client_contact_fax' => '415-555-1234',
+ 'client_contact_email' => 'ivan-voicebridge-test4@freeside.biz',
+
+);
+
+ok( ! $return->{error}, 'modifyClient successful' ) or warn $return->{error};
+
+is($return->{client_id}, $client_id, 'modifyClient returned client_id');
+
+# addConference (2)
+
+$return = $vb->addConference(
+ 'client_id' => $client_id,
+ 'conference_name' => 'Test Conference',
+ 'conference_desc' => 'Net Indosoft Voicebridge test',
+ 'start_time' => '2010-20-04 16:20:00',
+ #'moderated_flag' => 0,
+ #'entry_ann_flag' => 0
+ #'record_flag' => 0
+ #'moh_flag' => 0
+ #'talk_detect_flag' => 0
+ #'play_user_cnt_flag' => 0
+ #'wait_for_admin' => 0
+ #'stop_on_admin_exit' => 0
+ #'second_pin' => 0
+ #'secondary_pin' => 0,
+ #'allow_sub-conf' => 0,
+ #'duration' => 0,
+ #'conference_type' => 'reservation', #'reservationless',
+
+);
+
+ok( ! $return->{error}, 'addConference successful' ) or warn $return->{error};
+
+like($return->{conference_id}, qr/^(\d+)$/, 'addConference returned conference_id');
+
+my $conference_id = $return->{conference_id};
+
+# modifyConference (2)
+
+$return = $vb->modifyConference(
+ 'conference_id' => $conference_id,
+ 'conference_name' => 'Modified Test Conference',
+ 'conference_desc' => 'Net Indosoft Voicebridge modify test',
+ 'start_time' => '2010-20-04 16:20:00',
+ 'moderated_flag' => 1,
+ #'entry_ann_flag' => 0
+ #'record_flag' => 0
+ #'moh_flag' => 0
+ #'talk_detect_flag' => 0
+ #'play_user_cnt_flag' => 0
+ 'wait_for_admin' => 1
+ #'stop_on_admin_exit' => 0
+ #'second_pin' => 0
+ #'secondary_pin' => 0,
+ #'allow_sub-conf' => 0,
+ #'duration' => 0,
+ #'conference_type' => 'reservation', #'reservationless',
+
+);
+
+ok( ! $return->{error}, 'modifyConference successful' ) or warn $return->{error};
+
+is($return->{conference_id}, $conference_id, 'modifyConference returned conference_id')
+ or warn $return->{'return'};
+
+# deleteConference (2)
+
+$return = $vb->deleteConference(
+ 'conference_id' => $conference_id,
+);
+
+ok( ! $return->{error}, 'deleteConference successful' )
+ or warn $return->{error}. "\n". $return->{return}. "\n";
+
+TODO: {
+
+ local $TODO = 'deleteConference always returns "Deleted successfully", even when nothing was';
+
+ $return = $vb->deleteConference(
+ 'conference_id' => '999999999',
+ );
+
+ ok( $return->{error}, 'deleteConference bad data error test' )
+ ;#or warn $return->{return};
+
+}
+
+# deleteClient (2)
+
+$return = $vb->deleteClient(
+ 'client_id' => $client_id,
+);
+
+ok( ! $return->{error}, 'deleteClient successful' )
+ or warn $return->{error}. "\n". $return->{return}. "\n";
+
+TODO: {
+
+ local $TODO = 'deleteClient always returns "Deleted successfully", even when nothing was';
+
+ $return = $vb->deleteClient(
+ 'client_id' => '999999999',
+ );
+
+ ok( $return->{error}, 'deleteClient bad data error test' )
+ ;#or warn $return->{return};
+
+}
+
+# deleteAccount (2)
+
+$return = $vb->deleteAccount(
+ 'account_id' => $account_id,
+);
+
+ok( ! $return->{error}, 'deleteAccount successful' )
+ or warn $return->{error}. "\n". $return->{return}. "\n";
+
+TODO: {
+
+ local $TODO = 'deleteAccount always returns "Deleted successfully", even when nothing was';
+
+ $return = $vb->deleteAccount(
+ 'account_id' => '999999999',
+ );
+
+ ok( $return->{error}, 'deleteAccount bad data error test' )
+ ;#or warn $return->{return};
+
+}
--- /dev/null
+use strict;
+use warnings;
+use Test::More;
+
+# Ensure a recent version of Test::Pod::Coverage
+my $min_tpc = 1.08;
+eval "use Test::Pod::Coverage $min_tpc";
+plan skip_all => "Test::Pod::Coverage $min_tpc required for testing POD coverage"
+ if $@;
+
+# Test::Pod::Coverage doesn't require a minimum Pod::Coverage version,
+# but older versions don't recognize some common documentation styles
+my $min_pc = 0.18;
+eval "use Pod::Coverage $min_pc";
+plan skip_all => "Pod::Coverage $min_pc required for testing POD coverage"
+ if $@;
+
+all_pod_coverage_ok();
--- /dev/null
+#!perl -T
+
+use strict;
+use warnings;
+use Test::More;
+
+# Ensure a recent version of Test::Pod
+my $min_tp = 1.22;
+eval "use Test::Pod $min_tp";
+plan skip_all => "Test::Pod $min_tp required for testing POD" if $@;
+
+all_pod_files_ok();
--- /dev/null
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<definitions xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="urn:voicebridgeAPI" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="urn:voicebridgeAPI">
+<types>
+<xsd:schema targetNamespace="urn:voicebridgeAPI"
+>
+ <xsd:import namespace="http://schemas.xmlsoap.org/soap/encoding/" />
+ <xsd:import namespace="http://schemas.xmlsoap.org/wsdl/" />
+ <xsd:complexType name="Account">
+ <xsd:all>
+ <xsd:element name="account_id" type="xsd:int"/>
+ <xsd:element name="account_name" type="xsd:string"/>
+ <xsd:element name="account_desc" type="xsd:string"/>
+ <xsd:element name="account_addr" type="xsd:string"/>
+ <xsd:element name="account_city" type="xsd:string"/>
+ <xsd:element name="account_state" type="xsd:string"/>
+ <xsd:element name="account_country" type="xsd:string"/>
+ <xsd:element name="account_zip" type="xsd:string"/>
+ <xsd:element name="account_phone" type="xsd:string"/>
+ <xsd:element name="account_fax" type="xsd:string"/>
+ <xsd:element name="account_email" type="xsd:string"/>
+ <xsd:element name="account_password" type="xsd:string"/>
+ </xsd:all>
+ </xsd:complexType>
+ <xsd:complexType name="Client">
+ <xsd:all>
+ <xsd:element name="client_id" type="xsd:int"/>
+ <xsd:element name="account_id" type="xsd:int"/>
+ <xsd:element name="client_contact_name" type="xsd:string"/>
+ <xsd:element name="client_contact_addr" type="xsd:string"/>
+ <xsd:element name="client_contact_city" type="xsd:string"/>
+ <xsd:element name="client_contact_state" type="xsd:string"/>
+ <xsd:element name="client_contact_country" type="xsd:string"/>
+ <xsd:element name="client_contact_zip" type="xsd:string"/>
+ <xsd:element name="client_contact_phone" type="xsd:string"/>
+ <xsd:element name="client_contact_fax" type="xsd:string"/>
+ <xsd:element name="client_contact_email" type="xsd:string"/>
+ <xsd:element name="client_contact_password" type="xsd:string"/>
+ </xsd:all>
+ </xsd:complexType>
+ <xsd:complexType name="Conference">
+ <xsd:all>
+ <xsd:element name="conference_id" type="xsd:int"/>
+ <xsd:element name="client_id" type="xsd:int"/>
+ <xsd:element name="conference_name" type="xsd:string"/>
+ <xsd:element name="conference_desc" type="xsd:string"/>
+ <xsd:element name="start_time" type="xsd:string"/>
+ <xsd:element name="moderated_flag" type="xsd:int"/>
+ <xsd:element name="entry_ann_flag" type="xsd:int"/>
+ <xsd:element name="record_flag" type="xsd:int"/>
+ <xsd:element name="moh_flag" type="xsd:int"/>
+ <xsd:element name="talk_detect_flag" type="xsd:int"/>
+ <xsd:element name="play_user_cnt_flag" type="xsd:int"/>
+ <xsd:element name="wait_for_admin_flag" type="xsd:int"/>
+ <xsd:element name="stop_on_admin_exit_flag" type="xsd:int"/>
+ <xsd:element name="second_pin_flag" type="xsd:int"/>
+ <xsd:element name="allow_sub_conf" type="xsd:int"/>
+ <xsd:element name="secondary_pin" type="xsd:int"/>
+ <xsd:element name="duration" type="xsd:int"/>
+ <xsd:element name="conference_type" type="xsd:string"/>
+ </xsd:all>
+ </xsd:complexType>
+ <xsd:complexType name="DNIS">
+ <xsd:all>
+ <xsd:element name="dnis_id" type="xsd:int"/>
+ <xsd:element name="dnis" type="xsd:int"/>
+ <xsd:element name="line_name" type="xsd:string"/>
+ <xsd:element name="account_id" type="xsd:int"/>
+ <xsd:element name="client_id" type="xsd:int"/>
+ <xsd:element name="conference_id" type="xsd:int"/>
+ <xsd:element name="message_id" type="xsd:int"/>
+ <xsd:element name="dnis_action" type="xsd:string"/>
+ <xsd:element name="digit_timeout" type="xsd:int"/>
+ <xsd:element name="retries" type="xsd:int"/>
+ <xsd:element name="status" type="xsd:int"/>
+ </xsd:all>
+ </xsd:complexType>
+</xsd:schema>
+</types>
+<message name="addAccountRequest">
+ <part name="account" type="tns:Account" /></message>
+<message name="addAccountResponse">
+ <part name="return" type="xsd:string" /></message>
+<message name="modifyAccountRequest">
+ <part name="account" type="tns:Account" /></message>
+<message name="modifyAccountResponse">
+ <part name="return" type="xsd:string" /></message>
+<message name="addClientRequest">
+ <part name="client" type="tns:Client" /></message>
+<message name="addClientResponse">
+ <part name="return" type="xsd:string" /></message>
+<message name="modifyClientRequest">
+ <part name="client" type="tns:Client" /></message>
+<message name="modifyClientResponse">
+ <part name="return" type="xsd:string" /></message>
+<message name="addConferenceRequest">
+ <part name="conference" type="tns:Conference" /></message>
+<message name="addConferenceResponse">
+ <part name="return" type="xsd:string" /></message>
+<message name="modifyConferenceRequest">
+ <part name="conference" type="tns:Conference" /></message>
+<message name="modifyConferenceResponse">
+ <part name="return" type="xsd:string" /></message>
+<message name="deleteAccountRequest">
+ <part name="account_id" type="xsd:int" /></message>
+<message name="deleteAccountResponse">
+ <part name="return" type="xsd:string" /></message>
+<message name="deleteClientRequest">
+ <part name="client_id" type="xsd:int" /></message>
+<message name="deleteClientResponse">
+ <part name="return" type="xsd:string" /></message>
+<message name="deleteConferenceRequest">
+ <part name="conference_id" type="xsd:int" /></message>
+<message name="deleteConferenceResponse">
+ <part name="return" type="xsd:string" /></message>
+<message name="addConferencePINRequest">
+ <part name="conference_id" type="xsd:int" /></message>
+<message name="addConferencePINResponse">
+ <part name="return" type="xsd:string" /></message>
+<message name="modifyConferencePINRequest">
+ <part name="conference_id" type="xsd:int" />
+ <part name="new_pin" type="xsd:int" />
+ <part name="old_pin" type="xsd:int" /></message>
+<message name="modifyConferencePINResponse">
+ <part name="return" type="xsd:string" /></message>
+<message name="deleteConferencePINRequest">
+ <part name="conference_id" type="xsd:int" /></message>
+<message name="deleteConferencePINResponse">
+ <part name="return" type="xsd:string" /></message>
+<message name="addDNISRequest">
+ <part name="dnis" type="tns:DNIS" /></message>
+<message name="addDNISResponse">
+ <part name="return" type="xsd:string" /></message>
+<message name="modifyDNISRequest">
+ <part name="dnis" type="tns:DNIS" /></message>
+<message name="modifyDNISResponse">
+ <part name="return" type="xsd:string" /></message>
+<portType name="voicebridgeAPIPortType">
+ <operation name="addAccount">
+ <input message="tns:addAccountRequest"/>
+ <output message="tns:addAccountResponse"/>
+ </operation>
+ <operation name="modifyAccount">
+ <input message="tns:modifyAccountRequest"/>
+ <output message="tns:modifyAccountResponse"/>
+ </operation>
+ <operation name="addClient">
+ <input message="tns:addClientRequest"/>
+ <output message="tns:addClientResponse"/>
+ </operation>
+ <operation name="modifyClient">
+ <input message="tns:modifyClientRequest"/>
+ <output message="tns:modifyClientResponse"/>
+ </operation>
+ <operation name="addConference">
+ <input message="tns:addConferenceRequest"/>
+ <output message="tns:addConferenceResponse"/>
+ </operation>
+ <operation name="modifyConference">
+ <input message="tns:modifyConferenceRequest"/>
+ <output message="tns:modifyConferenceResponse"/>
+ </operation>
+ <operation name="deleteAccount">
+ <input message="tns:deleteAccountRequest"/>
+ <output message="tns:deleteAccountResponse"/>
+ </operation>
+ <operation name="deleteClient">
+ <input message="tns:deleteClientRequest"/>
+ <output message="tns:deleteClientResponse"/>
+ </operation>
+ <operation name="deleteConference">
+ <input message="tns:deleteConferenceRequest"/>
+ <output message="tns:deleteConferenceResponse"/>
+ </operation>
+ <operation name="addConferencePIN">
+ <input message="tns:addConferencePINRequest"/>
+ <output message="tns:addConferencePINResponse"/>
+ </operation>
+ <operation name="modifyConferencePIN">
+ <input message="tns:modifyConferencePINRequest"/>
+ <output message="tns:modifyConferencePINResponse"/>
+ </operation>
+ <operation name="deleteConferencePIN">
+ <input message="tns:deleteConferencePINRequest"/>
+ <output message="tns:deleteConferencePINResponse"/>
+ </operation>
+ <operation name="addDNIS">
+ <input message="tns:addDNISRequest"/>
+ <output message="tns:addDNISResponse"/>
+ </operation>
+ <operation name="modifyDNIS">
+ <input message="tns:modifyDNISRequest"/>
+ <output message="tns:modifyDNISResponse"/>
+ </operation>
+</portType>
+<binding name="voicebridgeAPIBinding" type="tns:voicebridgeAPIPortType">
+ <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
+ <operation name="addAccount">
+ <soap:operation soapAction="urn:voicebridgeAPI/addAccount" style="rpc"/>
+ <input><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></input>
+ <output><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></output>
+ </operation>
+ <operation name="modifyAccount">
+ <soap:operation soapAction="urn:voicebridgeAPI/modifyAccount" style="rpc"/>
+ <input><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></input>
+ <output><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></output>
+ </operation>
+ <operation name="addClient">
+ <soap:operation soapAction="urn:voicebridgeAPI/addClient" style="rpc"/>
+ <input><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></input>
+ <output><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></output>
+ </operation>
+ <operation name="modifyClient">
+ <soap:operation soapAction="urn:voicebridgeAPI/modifyClient" style="rpc"/>
+ <input><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></input>
+ <output><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></output>
+ </operation>
+ <operation name="addConference">
+ <soap:operation soapAction="urn:voicebridgeAPI/addConference" style="rpc"/>
+ <input><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></input>
+ <output><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></output>
+ </operation>
+ <operation name="modifyConference">
+ <soap:operation soapAction="urn:voicebridgeAPI/modifyConference" style="rpc"/>
+ <input><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></input>
+ <output><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></output>
+ </operation>
+ <operation name="deleteAccount">
+ <soap:operation soapAction="urn:voicebridgeAPI/deleteAccount" style="rpc"/>
+ <input><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></input>
+ <output><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></output>
+ </operation>
+ <operation name="deleteClient">
+ <soap:operation soapAction="urn:voicebridgeAPI/deleteClient" style="rpc"/>
+ <input><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></input>
+ <output><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></output>
+ </operation>
+ <operation name="deleteConference">
+ <soap:operation soapAction="urn:voicebridgeAPI/deleteConference" style="rpc"/>
+ <input><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></input>
+ <output><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></output>
+ </operation>
+ <operation name="addConferencePIN">
+ <soap:operation soapAction="urn:voicebridgeAPI/addConferencePIN" style="rpc"/>
+ <input><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></input>
+ <output><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></output>
+ </operation>
+ <operation name="modifyConferencePIN">
+ <soap:operation soapAction="urn:voicebridgeAPI/modifyConferencePIN" style="rpc"/>
+ <input><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></input>
+ <output><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></output>
+ </operation>
+ <operation name="deleteConferencePIN">
+ <soap:operation soapAction="urn:voicebridgeAPI/deleteConferencePIN" style="rpc"/>
+ <input><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></input>
+ <output><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></output>
+ </operation>
+ <operation name="addDNIS">
+ <soap:operation soapAction="urn:voicebridgeAPI/addDNIS" style="rpc"/>
+ <input><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></input>
+ <output><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></output>
+ </operation>
+ <operation name="modifyDNIS">
+ <soap:operation soapAction="urn:voicebridgeAPI/modifyDNIS" style="rpc"/>
+ <input><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></input>
+ <output><soap:body use="encoded" namespace="urn:voicebridgeAPI" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/></output>
+ </operation>
+</binding>
+<service name="voicebridgeAPI">
+ <port name="voicebridgeAPIPort" binding="tns:voicebridgeAPIBinding">
+ <soap:address location="http://nxxtcom1.kanobe.net:8080/vbsoap/voicebridgeAPI.php"/>
+ </port>
+</service>
+</definitions>
\ No newline at end of file