summaryrefslogtreecommitdiff
path: root/fs_selfservice
diff options
context:
space:
mode:
Diffstat (limited to 'fs_selfservice')
-rwxr-xr-xfs_selfservice/DEPLOY30
-rw-r--r--fs_selfservice/FS-SelfService/Changes6
-rw-r--r--fs_selfservice/FS-SelfService/MANIFEST8
-rw-r--r--fs_selfservice/FS-SelfService/Makefile.PL20
-rw-r--r--fs_selfservice/FS-SelfService/SelfService.pm1707
-rw-r--r--fs_selfservice/FS-SelfService/SelfService/FreeRadiusVoip.pm61
-rw-r--r--fs_selfservice/FS-SelfService/SelfService/XMLRPC.pm88
-rw-r--r--fs_selfservice/FS-SelfService/cgi/ach_payment_results.html13
-rw-r--r--fs_selfservice/FS-SelfService/cgi/agent.cgi458
-rw-r--r--fs_selfservice/FS-SelfService/cgi/agent_customer_menu.html7
-rw-r--r--fs_selfservice/FS-SelfService/cgi/agent_delete_svc.html17
-rw-r--r--fs_selfservice/FS-SelfService/cgi/agent_login.html22
-rw-r--r--fs_selfservice/FS-SelfService/cgi/agent_logout.html5
-rw-r--r--fs_selfservice/FS-SelfService/cgi/agent_main.html33
-rw-r--r--fs_selfservice/FS-SelfService/cgi/agent_menu.html15
-rw-r--r--fs_selfservice/FS-SelfService/cgi/agent_order_pkg.html18
-rw-r--r--fs_selfservice/FS-SelfService/cgi/agent_provision.html23
-rw-r--r--fs_selfservice/FS-SelfService/cgi/agent_provision_svc_acct.html16
-rw-r--r--fs_selfservice/FS-SelfService/cgi/bill.html15
-rw-r--r--fs_selfservice/FS-SelfService/cgi/card.html73
-rwxr-xr-xfs_selfservice/FS-SelfService/cgi/change_bill.html23
-rw-r--r--fs_selfservice/FS-SelfService/cgi/change_password.html51
-rw-r--r--fs_selfservice/FS-SelfService/cgi/change_pay.html73
-rw-r--r--fs_selfservice/FS-SelfService/cgi/change_pkg.html37
-rwxr-xr-xfs_selfservice/FS-SelfService/cgi/change_ship.html102
-rw-r--r--fs_selfservice/FS-SelfService/cgi/check.html54
-rw-r--r--fs_selfservice/FS-SelfService/cgi/contact.html135
-rw-r--r--fs_selfservice/FS-SelfService/cgi/cust_bill-logo.cgi19
-rw-r--r--fs_selfservice/FS-SelfService/cgi/customer_change_pkg.html8
-rwxr-xr-xfs_selfservice/FS-SelfService/cgi/customer_order_pkg.html8
-rw-r--r--fs_selfservice/FS-SelfService/cgi/cvv2.html25
-rw-r--r--fs_selfservice/FS-SelfService/cgi/cvv2.pngbin0 -> 3854 bytes
-rw-r--r--fs_selfservice/FS-SelfService/cgi/cvv2_amex.pngbin0 -> 4573 bytes
-rw-r--r--fs_selfservice/FS-SelfService/cgi/decline.html5
-rw-r--r--fs_selfservice/FS-SelfService/cgi/delete_svc.html14
-rw-r--r--fs_selfservice/FS-SelfService/cgi/footer.html3
-rw-r--r--fs_selfservice/FS-SelfService/cgi/images/cross.pngbin0 -> 655 bytes
-rw-r--r--fs_selfservice/FS-SelfService/cgi/images/wait-orange.gifbin0 -> 1849 bytes
-rw-r--r--fs_selfservice/FS-SelfService/cgi/list_customers.html36
-rw-r--r--fs_selfservice/FS-SelfService/cgi/login.html85
-rw-r--r--fs_selfservice/FS-SelfService/cgi/logout.html5
-rw-r--r--fs_selfservice/FS-SelfService/cgi/make_ach_payment.html58
-rw-r--r--fs_selfservice/FS-SelfService/cgi/make_payment.html68
-rw-r--r--fs_selfservice/FS-SelfService/cgi/map.gifbin0 -> 8181 bytes
-rwxr-xr-xfs_selfservice/FS-SelfService/cgi/misc/areacodes.cgi18
-rwxr-xr-xfs_selfservice/FS-SelfService/cgi/misc/exchanges.cgi18
-rwxr-xr-xfs_selfservice/FS-SelfService/cgi/misc/phonenums.cgi18
-rw-r--r--fs_selfservice/FS-SelfService/cgi/myaccount.html94
-rw-r--r--fs_selfservice/FS-SelfService/cgi/myaccount_menu.html94
-rw-r--r--fs_selfservice/FS-SelfService/cgi/order_pkg.html75
-rwxr-xr-xfs_selfservice/FS-SelfService/cgi/passwd.cgi61
-rw-r--r--fs_selfservice/FS-SelfService/cgi/passwd.html28
-rw-r--r--fs_selfservice/FS-SelfService/cgi/payment_results.html13
-rw-r--r--fs_selfservice/FS-SelfService/cgi/process_change_bill.html10
-rw-r--r--fs_selfservice/FS-SelfService/cgi/process_change_password.html10
-rw-r--r--fs_selfservice/FS-SelfService/cgi/process_change_pay.html10
-rw-r--r--fs_selfservice/FS-SelfService/cgi/process_change_pkg.html10
-rw-r--r--fs_selfservice/FS-SelfService/cgi/process_change_ship.html10
-rwxr-xr-xfs_selfservice/FS-SelfService/cgi/process_order_pkg.html10
-rw-r--r--fs_selfservice/FS-SelfService/cgi/process_order_recharge.html10
-rw-r--r--fs_selfservice/FS-SelfService/cgi/process_svc_acct.html10
-rw-r--r--fs_selfservice/FS-SelfService/cgi/process_svc_external.html12
-rw-r--r--fs_selfservice/FS-SelfService/cgi/promocode.html14
-rw-r--r--fs_selfservice/FS-SelfService/cgi/provision.html8
-rw-r--r--fs_selfservice/FS-SelfService/cgi/provision_list.html92
-rw-r--r--fs_selfservice/FS-SelfService/cgi/provision_svc_acct.html8
-rw-r--r--fs_selfservice/FS-SelfService/cgi/recharge_prepay.html33
-rw-r--r--fs_selfservice/FS-SelfService/cgi/recharge_results.html21
-rw-r--r--fs_selfservice/FS-SelfService/cgi/regcode.html14
-rw-r--r--fs_selfservice/FS-SelfService/cgi/selfservice.cgi667
-rwxr-xr-xfs_selfservice/FS-SelfService/cgi/signup-agentselect.html195
-rwxr-xr-xfs_selfservice/FS-SelfService/cgi/signup-alternate.html218
-rwxr-xr-xfs_selfservice/FS-SelfService/cgi/signup-billaddress.html307
-rwxr-xr-xfs_selfservice/FS-SelfService/cgi/signup-freeoption.html262
-rwxr-xr-xfs_selfservice/FS-SelfService/cgi/signup-snarf.html228
-rwxr-xr-xfs_selfservice/FS-SelfService/cgi/signup.cgi387
-rwxr-xr-xfs_selfservice/FS-SelfService/cgi/signup.html424
-rw-r--r--fs_selfservice/FS-SelfService/cgi/stateselect.html134
-rw-r--r--fs_selfservice/FS-SelfService/cgi/success-delayed.html16
-rw-r--r--fs_selfservice/FS-SelfService/cgi/success.html41
-rw-r--r--fs_selfservice/FS-SelfService/cgi/svc_acct.html58
-rw-r--r--fs_selfservice/FS-SelfService/cgi/view_customer.html24
-rw-r--r--fs_selfservice/FS-SelfService/cgi/view_invoice.html10
-rw-r--r--fs_selfservice/FS-SelfService/cgi/view_support_details.html78
-rw-r--r--fs_selfservice/FS-SelfService/cgi/view_usage.html58
-rw-r--r--fs_selfservice/FS-SelfService/cgi/view_usage_details.html84
-rw-r--r--fs_selfservice/FS-SelfService/cgi/xmlrpc.cgi18
-rw-r--r--fs_selfservice/FS-SelfService/freeside-selfservice-clientd272
-rw-r--r--fs_selfservice/FS-SelfService/freeside-selfservice-xmlrpc-server59
-rwxr-xr-xfs_selfservice/FS-SelfService/ieak.template40
-rw-r--r--fs_selfservice/FS-SelfService/test.pl17
-rw-r--r--fs_selfservice/fri/CHANGE.log271
-rw-r--r--fs_selfservice/fri/LICENSE.txt340
-rw-r--r--fs_selfservice/fri/README.txt123
-rw-r--r--fs_selfservice/fri/includes/ajax.php132
-rw-r--r--fs_selfservice/fri/includes/asi.php156
-rw-r--r--fs_selfservice/fri/includes/bootstrap.php315
-rw-r--r--fs_selfservice/fri/includes/common.php434
-rw-r--r--fs_selfservice/fri/includes/crypt.php81
-rw-r--r--fs_selfservice/fri/includes/database.php72
-rw-r--r--fs_selfservice/fri/includes/display.php222
-rw-r--r--fs_selfservice/fri/includes/freeside.class.php38
-rw-r--r--fs_selfservice/fri/includes/lang.php112
-rw-r--r--fs_selfservice/fri/includes/login.php515
-rw-r--r--fs_selfservice/fri/includes/main.conf.php331
-rw-r--r--fs_selfservice/fri/index.php20
-rw-r--r--fs_selfservice/fri/locale/ari.po590
-rw-r--r--fs_selfservice/fri/locale/ari.utf-8.po590
-rw-r--r--fs_selfservice/fri/locale/de_DE/LC_MESSAGES/ari.mobin0 -> 4161 bytes
-rw-r--r--fs_selfservice/fri/locale/de_DE/LC_MESSAGES/ari.po631
-rw-r--r--fs_selfservice/fri/locale/el_GR/LC_MESSAGES/ari.mobin0 -> 5158 bytes
-rw-r--r--fs_selfservice/fri/locale/el_GR/LC_MESSAGES/ari.po648
-rw-r--r--fs_selfservice/fri/locale/es_ES/LC_MESSAGES/ari.mobin0 -> 9562 bytes
-rw-r--r--fs_selfservice/fri/locale/es_ES/LC_MESSAGES/ari.po616
-rw-r--r--fs_selfservice/fri/locale/fr_FR/LC_MESSAGES/ari.mobin0 -> 6751 bytes
-rw-r--r--fs_selfservice/fri/locale/fr_FR/LC_MESSAGES/ari.po635
-rw-r--r--fs_selfservice/fri/locale/he_IL/LC_MESSAGES/ari.mobin0 -> 4430 bytes
-rw-r--r--fs_selfservice/fri/locale/he_IL/LC_MESSAGES/ari.po646
-rw-r--r--fs_selfservice/fri/locale/hu_HU/LC_MESSAGES/ari.mobin0 -> 4051 bytes
-rw-r--r--fs_selfservice/fri/locale/hu_HU/LC_MESSAGES/ari.po645
-rw-r--r--fs_selfservice/fri/locale/it_IT/LC_MESSAGES/ari.mobin0 -> 16728 bytes
-rw-r--r--fs_selfservice/fri/locale/it_IT/LC_MESSAGES/ari.po999
-rw-r--r--fs_selfservice/fri/locale/locale.txt37
-rw-r--r--fs_selfservice/fri/locale/pt_BR/LC_MESSAGES/ari.mobin0 -> 2064 bytes
-rw-r--r--fs_selfservice/fri/locale/pt_BR/LC_MESSAGES/ari.po647
-rw-r--r--fs_selfservice/fri/locale/readme.txt37
-rw-r--r--fs_selfservice/fri/locale/sv_SE/LC_MESSAGES/ari.mobin0 -> 7134 bytes
-rw-r--r--fs_selfservice/fri/locale/sv_SE/LC_MESSAGES/ari.po678
-rw-r--r--fs_selfservice/fri/misc/audio.php61
-rw-r--r--fs_selfservice/fri/misc/popup.css10
-rw-r--r--fs_selfservice/fri/misc/recording_popup.php46
-rw-r--r--fs_selfservice/fri/modules.template/blank.module81
-rw-r--r--fs_selfservice/fri/modules/VmX.module661
-rw-r--r--fs_selfservice/fri/modules/billing.module250
-rw-r--r--fs_selfservice/fri/modules/callmonitor.module675
-rw-r--r--fs_selfservice/fri/modules/dashboard.module166
-rw-r--r--fs_selfservice/fri/modules/featurecodes.module152
-rw-r--r--fs_selfservice/fri/modules/followme.module678
-rw-r--r--fs_selfservice/fri/modules/myaccount.module109
-rw-r--r--fs_selfservice/fri/modules/phonefeatures.module342
-rw-r--r--fs_selfservice/fri/modules/settings.module813
-rw-r--r--fs_selfservice/fri/modules/voicemail.module805
-rw-r--r--fs_selfservice/fri/theme/global.css87
-rw-r--r--fs_selfservice/fri/theme/header.css83
-rw-r--r--fs_selfservice/fri/theme/iefixes.css16
-rw-r--r--fs_selfservice/fri/theme/images/arrow-asc.gifbin0 -> 86 bytes
-rw-r--r--fs_selfservice/fri/theme/images/arrow-desc.gifbin0 -> 85 bytes
-rw-r--r--fs_selfservice/fri/theme/layout.css420
-rw-r--r--fs_selfservice/fri/theme/logo.gifbin0 -> 2819 bytes
-rw-r--r--fs_selfservice/fri/theme/main.css13
-rw-r--r--fs_selfservice/fri/theme/navigation.css166
-rw-r--r--fs_selfservice/fri/theme/page.tpl.php78
-rw-r--r--fs_selfservice/fri/theme/spacer.gifbin0 -> 43 bytes
-rw-r--r--fs_selfservice/fri/theme/text.css10
-rw-r--r--fs_selfservice/fri/version.php10
-rwxr-xr-xfs_selfservice/fs_passwd_test19
-rwxr-xr-xfs_selfservice/java/biz/freeside/SelfService.java52
-rwxr-xr-xfs_selfservice/java/freeside_login_example.java45
-rwxr-xr-xfs_selfservice/java/freeside_signup_example.java69
-rw-r--r--fs_selfservice/php/freeside.class.php34
-rw-r--r--fs_selfservice/php/freeside.login_example.php37
-rw-r--r--fs_selfservice/php/freeside_signup_example.php49
-rw-r--r--fs_selfservice/php/login.php90
-rw-r--r--fs_selfservice/php/main.php39
-rw-r--r--fs_selfservice/php/order_renew.php166
-rw-r--r--fs_selfservice/php/process_login.php38
-rw-r--r--fs_selfservice/php/process_payment_order_renew.php74
167 files changed, 24747 insertions, 0 deletions
diff --git a/fs_selfservice/DEPLOY b/fs_selfservice/DEPLOY
new file mode 100755
index 000000000..e73012f4b
--- /dev/null
+++ b/fs_selfservice/DEPLOY
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+#this is a quick hack for my dev machine. do not use it.
+# see the "make install-selfservice" and "make update-selfservice" makefile
+# targets to properly install this stuff.
+
+#kill `cat /var/run/freeside-selfservice-server.fs_selfservice.pid`
+
+cd FS-SelfService
+perl Makefile.PL && make && make install
+cd ..
+
+#( cd ..; make deploy; cd fs_selfservice )
+( cd ..; make clean; make install-perl-modules; /etc/init.d/freeside restart; cd fs_selfservice )
+
+#cp /home/ivan/freeside/fs_selfservice/FS-SelfService/cgi/* /var/www/MyAccount
+#chown freeside /var/www/MyAccount/*.cgi
+#chmod 755 /var/www/MyAccount/*.cgi
+#ln -s /var/www/MyAccount/selfservice.cgi /var/www/MyAccount/index.cgi || true
+
+ #cp /home/ivan/freeside/fs_signup/FS-SignupClient/cgi/* /var/www/signup/
+ ##mv /var/www/signup/signup-snarf.html /var/www/signup/signup.html #!!!!!
+ ##mv /var/www/signup/signup-billaddress.html /var/www/signup/signup.html #!!!!!
+ ##mv /var/www/signup/signup-freeoption.html /var/www/signup/signup.html #!!!!!
+ #chown freeside /var/www/signup/signup.cgi
+ #chmod 755 /var/www/signup/signup.cgi
+ #ln -s /var/www/signup/signup.cgi /var/www/signup/index.cgi || true
+
+
+chmod 755 /var/www/selfservice/*.cgi
diff --git a/fs_selfservice/FS-SelfService/Changes b/fs_selfservice/FS-SelfService/Changes
new file mode 100644
index 000000000..b9e26b7dc
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/Changes
@@ -0,0 +1,6 @@
+Revision history for Perl extension FS::SelfService.
+
+0.01 Tue May 28 16:49:41 2002
+ - original version; created by h2xs 1.21 with options
+ -A -X -n FS::SelfService
+
diff --git a/fs_selfservice/FS-SelfService/MANIFEST b/fs_selfservice/FS-SelfService/MANIFEST
new file mode 100644
index 000000000..a619b2b6c
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/MANIFEST
@@ -0,0 +1,8 @@
+Changes
+Makefile.PL
+MANIFEST
+SelfService.pm
+SelfService/XMLRPC.pm
+test.pl
+freeside-selfservice-clientd
+freeside-selfservice-xmlrpc-server
diff --git a/fs_selfservice/FS-SelfService/Makefile.PL b/fs_selfservice/FS-SelfService/Makefile.PL
new file mode 100644
index 000000000..c078f0865
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/Makefile.PL
@@ -0,0 +1,20 @@
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+WriteMakefile(
+ 'NAME' => 'FS::SelfService',
+ 'VERSION_FROM' => 'SelfService.pm', # finds $VERSION
+ 'EXE_FILES' => [ 'freeside-selfservice-clientd',
+ 'freeside-selfservice-xmlrpc-server',
+ ],
+ 'INSTALLSCRIPT' => '/usr/local/sbin',
+ 'INSTALLSITEBIN' => '/usr/local/sbin',
+ 'INSTALLSITESCRIPT' => '/usr/local/sbin', #recent deb users this...
+ 'PERM_RWX' => '750',
+ 'PREREQ_PM' => {
+ 'Storable' => 2.09,
+ }, # e.g., Module::Name => 1.1
+ ($] >= 5.005 ? ## Add these new keywords supported since 5.005
+ (ABSTRACT_FROM => 'SelfService.pm', # retrieve abstract from module
+ AUTHOR => 'Ivan Kohler <ivan-freeside-selfservice@420.am>') : ()),
+);
diff --git a/fs_selfservice/FS-SelfService/SelfService.pm b/fs_selfservice/FS-SelfService/SelfService.pm
new file mode 100644
index 000000000..580ca7334
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/SelfService.pm
@@ -0,0 +1,1707 @@
+package FS::SelfService;
+
+use strict;
+use vars qw( $VERSION @ISA @EXPORT_OK $DEBUG
+ $skip_uid_check $dir $socket %autoload $tag );
+use Exporter;
+use Socket;
+use FileHandle;
+#use IO::Handle;
+use IO::Select;
+use Storable 2.09 qw(nstore_fd fd_retrieve);
+
+$VERSION = '0.03';
+
+@ISA = qw( Exporter );
+
+$DEBUG = 0;
+
+$dir = "/usr/local/freeside";
+$socket = "$dir/selfservice_socket";
+$socket .= '.'.$tag if defined $tag && length($tag);
+
+#maybe should ask ClientAPI for this list
+%autoload = (
+ 'passwd' => 'passwd/passwd',
+ 'chfn' => 'passwd/passwd',
+ 'chsh' => 'passwd/passwd',
+ 'login_info' => 'MyAccount/login_info',
+ 'login' => 'MyAccount/login',
+ 'logout' => 'MyAccount/logout',
+ 'customer_info' => 'MyAccount/customer_info',
+ 'edit_info' => 'MyAccount/edit_info', #add to ss cgi!
+ 'invoice' => 'MyAccount/invoice',
+ 'invoice_logo' => 'MyAccount/invoice_logo',
+ 'list_invoices' => 'MyAccount/list_invoices', #?
+ 'cancel' => 'MyAccount/cancel', #add to ss cgi!
+ 'payment_info' => 'MyAccount/payment_info',
+ 'process_payment' => 'MyAccount/process_payment',
+ 'process_payment_order_pkg' => 'MyAccount/process_payment_order_pkg',
+ 'process_payment_order_renew' => 'MyAccount/process_payment_order_renew',
+ 'process_prepay' => 'MyAccount/process_prepay',
+ 'list_pkgs' => 'MyAccount/list_pkgs', #add to ss (added?)
+ 'list_svcs' => 'MyAccount/list_svcs', #add to ss (added?)
+ 'list_svc_usage' => 'MyAccount/list_svc_usage',
+ 'list_support_usage' => 'MyAccount/list_support_usage',
+ 'order_pkg' => 'MyAccount/order_pkg', #add to ss cgi!
+ 'change_pkg' => 'MyAccount/change_pkg',
+ 'order_recharge' => 'MyAccount/order_recharge',
+ 'renew_info' => 'MyAccount/renew_info',
+ 'order_renew' => 'MyAccount/order_renew',
+ 'cancel_pkg' => 'MyAccount/cancel_pkg', #add to ss cgi!
+ 'charge' => 'MyAccount/charge', #?
+ 'part_svc_info' => 'MyAccount/part_svc_info',
+ 'provision_acct' => 'MyAccount/provision_acct',
+ 'provision_external' => 'MyAccount/provision_external',
+ 'unprovision_svc' => 'MyAccount/unprovision_svc',
+ 'myaccount_passwd' => 'MyAccount/myaccount_passwd',
+ 'signup_info' => 'Signup/signup_info',
+ 'domain_select_hash' => 'Signup/domain_select_hash', # expose?
+ 'new_customer' => 'Signup/new_customer',
+ 'agent_login' => 'Agent/agent_login',
+ 'agent_logout' => 'Agent/agent_logout',
+ 'agent_info' => 'Agent/agent_info',
+ 'agent_list_customers' => 'Agent/agent_list_customers',
+ 'mason_comp' => 'MasonComponent/mason_comp',
+ 'call_time' => 'PrepaidPhone/call_time',
+ 'call_time_nanpa' => 'PrepaidPhone/call_time_nanpa',
+ 'phonenum_balance' => 'PrepaidPhone/phonenum_balance',
+);
+@EXPORT_OK = (
+ keys(%autoload),
+ qw( regionselector regionselector_hashref
+ expselect popselector domainselector didselector )
+);
+
+$ENV{'PATH'} ='/usr/bin:/usr/ucb:/bin';
+$ENV{'SHELL'} = '/bin/sh';
+$ENV{'IFS'} = " \t\n";
+$ENV{'CDPATH'} = '';
+$ENV{'ENV'} = '';
+$ENV{'BASH_ENV'} = '';
+
+#you can add BEGIN { $FS::SelfService::skip_uid_check = 1; }
+#if you grant appropriate permissions to whatever user
+my $freeside_uid = scalar(getpwnam('freeside'));
+die "not running as the freeside user\n"
+ if $> != $freeside_uid && ! $skip_uid_check;
+
+-e $dir or die "FATAL: $dir doesn't exist!";
+-d $dir or die "FATAL: $dir isn't a directory!";
+-r $dir or die "FATAL: Can't read $dir as freeside user!";
+-x $dir or die "FATAL: $dir not searchable (executable) as freeside user!";
+
+foreach my $autoload ( keys %autoload ) {
+
+ my $eval =
+ "sub $autoload { ". '
+ my $param;
+ if ( ref($_[0]) ) {
+ $param = shift;
+ } else {
+ #warn scalar(@_). ": ". join(" / ", @_);
+ $param = { @_ };
+ }
+
+ $param->{_packet} = \''. $autoload{$autoload}. '\';
+
+ simple_packet($param);
+ }';
+
+ eval $eval;
+ die $@ if $@;
+
+}
+
+sub simple_packet {
+ my $packet = shift;
+ warn "sending ". $packet->{_packet}. " to server"
+ if $DEBUG;
+ socket(SOCK, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!";
+ connect(SOCK, sockaddr_un($socket)) or die "connect to $socket: $!";
+ nstore_fd($packet, \*SOCK) or die "can't send packet: $!";
+ SOCK->flush;
+
+ #shoudl trap: Magic number checking on storable file failed at blib/lib/Storable.pm (autosplit into blib/lib/auto/Storable/fd_retrieve.al) line 337, at /usr/local/share/perl/5.6.1/FS/SelfService.pm line 71
+
+ #block until there is a message on socket
+# my $w = new IO::Select;
+# $w->add(\*SOCK);
+# my @wait = $w->can_read;
+
+ warn "reading message from server"
+ if $DEBUG;
+
+ my $return = fd_retrieve(\*SOCK) or die "error reading result: $!";
+ die $return->{'_error'} if defined $return->{_error} && $return->{_error};
+
+ warn "returning message to client"
+ if $DEBUG;
+
+ $return;
+}
+
+=head1 NAME
+
+FS::SelfService - Freeside self-service API
+
+=head1 SYNOPSIS
+
+ # password and shell account changes
+ use FS::SelfService qw(passwd chfn chsh);
+
+ # "my account" functionality
+ use FS::SelfService qw( login customer_info invoice cancel payment_info process_payment );
+
+ my $rv = login( { 'username' => $username,
+ 'domain' => $domain,
+ 'password' => $password,
+ }
+ );
+
+ if ( $rv->{'error'} ) {
+ #handle login error...
+ } else {
+ #successful login
+ my $session_id = $rv->{'session_id'};
+ }
+
+ my $customer_info = customer_info( { 'session_id' => $session_id } );
+
+ #payment_info and process_payment are available in 1.5+ only
+ my $payment_info = payment_info( { 'session_id' => $session_id } );
+
+ #!!! process_payment example
+
+ #!!! list_pkgs example
+
+ #!!! order_pkg example
+
+ #!!! cancel_pkg example
+
+ # signup functionality
+ use FS::SelfService qw( signup_info new_customer );
+
+ my $signup_info = signup_info;
+
+ $rv = new_customer( {
+ 'first' => $first,
+ 'last' => $last,
+ 'company' => $company,
+ 'address1' => $address1,
+ 'address2' => $address2,
+ 'city' => $city,
+ 'state' => $state,
+ 'zip' => $zip,
+ 'country' => $country,
+ 'daytime' => $daytime,
+ 'night' => $night,
+ 'fax' => $fax,
+ 'payby' => $payby,
+ 'payinfo' => $payinfo,
+ 'paycvv' => $paycvv,
+ 'paystart_month' => $paystart_month
+ 'paystart_year' => $paystart_year,
+ 'payissue' => $payissue,
+ 'payip' => $payip
+ 'paydate' => $paydate,
+ 'payname' => $payname,
+ 'invoicing_list' => $invoicing_list,
+ 'referral_custnum' => $referral_custnum,
+ 'agentnum' => $agentnum,
+ 'pkgpart' => $pkgpart,
+
+ 'username' => $username,
+ '_password' => $password,
+ 'popnum' => $popnum,
+ #OR
+ 'countrycode' => 1,
+ 'phonenum' => $phonenum,
+ 'pin' => $pin,
+ }
+ );
+
+ my $error = $rv->{'error'};
+ if ( $error eq '_decline' ) {
+ print_decline();
+ } elsif ( $error ) {
+ reprint_signup();
+ } else {
+ print_success();
+ }
+
+=head1 DESCRIPTION
+
+Use this API to implement your own client "self-service" module.
+
+If you just want to customize the look of the existing "self-service" module,
+see XXXX instead.
+
+=head1 PASSWORD, GECOS, SHELL CHANGING FUNCTIONS
+
+=over 4
+
+=item passwd
+
+=item chfn
+
+=item chsh
+
+=back
+
+=head1 "MY ACCOUNT" FUNCTIONS
+
+=over 4
+
+=item login HASHREF
+
+Creates a user session. Takes a hash reference as parameter with the
+following keys:
+
+=over 4
+
+=item username
+
+Username
+
+=item domain
+
+Domain
+
+=item password
+
+Password
+
+=back
+
+Returns a hash reference with the following keys:
+
+=over 4
+
+=item error
+
+Empty on success, or an error message on errors.
+
+=item session_id
+
+Session identifier for successful logins
+
+=back
+
+=item customer_info HASHREF
+
+Returns general customer information.
+
+Takes a hash reference as parameter with a single key: B<session_id>
+
+Returns a hash reference with the following keys:
+
+=over 4
+
+=item name
+
+Customer name
+
+=item balance
+
+Balance owed
+
+=item open
+
+Array reference of hash references of open inoices. Each hash reference has
+the following keys: invnum, date, owed
+
+=item small_custview
+
+An HTML fragment containing shipping and billing addresses.
+
+=item The following fields are also returned
+
+first last company address1 address2 city county state zip country daytime night fax ship_first ship_last ship_company ship_address1 ship_address2 ship_city ship_state ship_zip ship_country ship_daytime ship_night ship_fax payby payinfo payname month year invoicing_list postal_invoicing
+
+=back
+
+=item edit_info HASHREF
+
+Takes a hash reference as parameter with any of the following keys:
+
+first last company address1 address2 city county state zip country daytime night fax ship_first ship_last ship_company ship_address1 ship_address2 ship_city ship_state ship_zip ship_country ship_daytime ship_night ship_fax payby payinfo paycvv payname month year invoicing_list postal_invoicing
+
+If a field exists, the customer record is updated with the new value of that
+field. If a field does not exist, that field is not changed on the customer
+record.
+
+Returns a hash reference with a single key, B<error>, empty on success, or an
+error message on errors
+
+=item invoice HASHREF
+
+Returns an invoice. Takes a hash reference as parameter with two keys:
+session_id and invnum
+
+Returns a hash reference with the following keys:
+
+=over 4
+
+=item error
+
+Empty on success, or an error message on errors
+
+=item invnum
+
+Invoice number
+
+=item invoice_text
+
+Invoice text
+
+=back
+
+=item list_invoices HASHREF
+
+Returns a list of all customer invoices. Takes a hash references with a single
+key, session_id.
+
+Returns a hash reference with the following keys:
+
+=over 4
+
+=item error
+
+Empty on success, or an error message on errors
+
+=item invoices
+
+Reference to array of hash references with the following keys:
+
+=over 4
+
+=item invnum
+
+Invoice ID
+
+=item _date
+
+Invoice date, in UNIX epoch time
+
+=back
+
+=back
+
+=item cancel HASHREF
+
+Cancels this customer.
+
+Takes a hash reference as parameter with a single key: B<session_id>
+
+Returns a hash reference with a single key, B<error>, which is empty on
+success or an error message on errors.
+
+=item payment_info HASHREF
+
+Returns information that may be useful in displaying a payment page.
+
+Takes a hash reference as parameter with a single key: B<session_id>.
+
+Returns a hash reference with the following keys:
+
+=over 4
+
+=item error
+
+Empty on success, or an error message on errors
+
+=item balance
+
+Balance owed
+
+=item payname
+
+Exact name on credit card (CARD/DCRD)
+
+=item address1
+
+Address line one
+
+=item address2
+
+Address line two
+
+=item city
+
+City
+
+=item state
+
+State
+
+=item zip
+
+Zip or postal code
+
+=item payby
+
+Customer's current default payment type.
+
+=item card_type
+
+For CARD/DCRD payment types, the card type (Visa card, MasterCard, Discover card, American Express card, etc.)
+
+=item payinfo
+
+For CARD/DCRD payment types, the card number
+
+=item month
+
+For CARD/DCRD payment types, expiration month
+
+=item year
+
+For CARD/DCRD payment types, expiration year
+
+=item cust_main_county
+
+County/state/country data - array reference of hash references, each of which has the fields of a cust_main_county record (see L<FS::cust_main_county>). Note these are not FS::cust_main_county objects, but hash references of columns and values.
+
+=item states
+
+Array reference of all states in the current default country.
+
+=item card_types
+
+Hash reference of card types; keys are card types, values are the exact strings
+passed to the process_payment function
+
+=cut
+
+#this doesn't actually work yet
+#
+#=item paybatch
+#
+#Unique transaction identifier (prevents multiple charges), passed to the
+#process_payment function
+
+=back
+
+=item process_payment HASHREF
+
+Processes a payment and possible change of address or payment type. Takes a
+hash reference as parameter with the following keys:
+
+=over 4
+
+=item session_id
+
+Session identifier
+
+=item amount
+
+Amount
+
+=item save
+
+If true, address and card information entered will be saved for subsequent
+transactions.
+
+=item auto
+
+If true, future credit card payments will be done automatically (sets payby to
+CARD). If false, future credit card payments will be done on-demand (sets
+payby to DCRD). This option only has meaning if B<save> is set true.
+
+=item payname
+
+Name on card
+
+=item address1
+
+Address line one
+
+=item address2
+
+Address line two
+
+=item city
+
+City
+
+=item state
+
+State
+
+=item zip
+
+Zip or postal code
+
+=item payinfo
+
+Card number
+
+=item month
+
+Card expiration month
+
+=item year
+
+Card expiration year
+
+=cut
+
+#this doesn't actually work yet
+#
+#=item paybatch
+#
+#Unique transaction identifier, returned from the payment_info function.
+#Prevents multiple charges.
+
+=back
+
+Returns a hash reference with a single key, B<error>, empty on success, or an
+error message on errors.
+
+=item process_payment_order_pkg
+
+Combines the B<process_payment> and B<order_pkg> functions in one step. If the
+payment processes sucessfully, the package is ordered. Takes a hash reference
+as parameter with the keys of both methods.
+
+Returns a hash reference with a single key, B<error>, empty on success, or an
+error message on errors.
+
+=item process_payment_order_renew
+
+Combines the B<process_payment> and B<order_renew> functions in one step. If
+the payment processes sucessfully, the renewal is processed. Takes a hash
+reference as parameter with the keys of both methods.
+
+Returns a hash reference with a single key, B<error>, empty on success, or an
+error message on errors.
+
+=item list_pkgs
+
+Returns package information for this customer. For more detail on services,
+see L</list_svcs>.
+
+Takes a hash reference as parameter with a single key: B<session_id>
+
+Returns a hash reference containing customer package information. The hash reference contains the following keys:
+
+=over 4
+
+=item custnum
+
+Customer number
+
+=item error
+
+Empty on success, or an error message on errors.
+
+=item cust_pkg HASHREF
+
+Array reference of hash references, each of which has the fields of a cust_pkg
+record (see L<FS::cust_pkg>) as well as the fields below. Note these are not
+the internal FS:: objects, but hash references of columns and values.
+
+=over 4
+
+=item part_pkg fields
+
+All fields of part_pkg for this specific cust_pkg (be careful with this
+information - it may reveal more about your available packages than you would
+like users to know in aggregate)
+
+=cut
+
+#XXX pare part_pkg fields down to a more secure subset
+
+=item part_svc
+
+An array of hash references indicating information on unprovisioned services
+available for provisioning for this specific cust_pkg. Each has the following
+keys:
+
+=over 4
+
+=item part_svc fields
+
+All fields of part_svc (be careful with this information - it may reveal more
+about your available packages than you would like users to know in aggregate)
+
+=cut
+
+#XXX pare part_svc fields down to a more secure subset
+
+=back
+
+=item cust_svc
+
+An array of hash references indicating information on the customer services
+already provisioned for this specific cust_pkg. Each has the following keys:
+
+=over 4
+
+=item label
+
+Array reference with three elements: The first element is the name of this service. The second element is a meaningful user-specific identifier for the service (i.e. username, domain or mail alias). The last element is the table name of this service.
+
+=back
+
+=item svcnum
+
+Primary key for this service
+
+=item svcpart
+
+Service definition (see L<FS::part_svc>)
+
+=item pkgnum
+
+Customer package (see L<FS::cust_pkg>)
+
+=item overlimit
+
+Blank if the service is not over limit, or the date the service exceeded its usage limit (as a UNIX timestamp).
+
+=back
+
+=back
+
+=item list_svcs
+
+Returns service information for this customer.
+
+Takes a hash reference as parameter with a single key: B<session_id>
+
+Returns a hash reference containing customer package information. The hash reference contains the following keys:
+
+=over 4
+
+=item custnum
+
+Customer number
+
+=item svcs
+
+An array of hash references indicating information on all of this customer's
+services. Each has the following keys:
+
+=over 4
+
+=item svcnum
+
+Primary key for this service
+
+=item label
+
+Name of this service
+
+=item value
+
+Meaningful user-specific identifier for the service (i.e. username, domain, or
+mail alias).
+
+=back
+
+Account (svc_acct) services also have the following keys:
+
+=over 4
+
+=item username
+
+Username
+
+=item email
+
+username@domain
+
+=item seconds
+
+Seconds remaining
+
+=item upbytes
+
+Upload bytes remaining
+
+=item downbytes
+
+Download bytes remaining
+
+=item totalbytes
+
+Total bytes remaining
+
+=item recharge_amount
+
+Cost of a recharge
+
+=item recharge_seconds
+
+Number of seconds gained by recharge
+
+=item recharge_upbytes
+
+Number of upload bytes gained by recharge
+
+=item recharge_downbytes
+
+Number of download bytes gained by recharge
+
+=item recharge_totalbytes
+
+Number of total bytes gained by recharge
+
+=back
+
+=back
+
+=item order_pkg
+
+Orders a package for this customer.
+
+Takes a hash reference as parameter with the following keys:
+
+=over 4
+
+=item session_id
+
+Session identifier
+
+=item pkgpart
+
+Package to order (see L<FS::part_pkg>).
+
+=item svcpart
+
+Service to order (see L<FS::part_svc>).
+
+Normally optional; required only to provision a non-svc_acct service, or if the
+package definition does not contain one svc_acct service definition with
+quantity 1 (it may contain others with quantity >1). A svcpart of "none" can
+also be specified to indicate that no initial service should be provisioned.
+
+=back
+
+Fields used when provisioning an svc_acct service:
+
+=over 4
+
+=item username
+
+Username
+
+=item _password
+
+Password
+
+=item sec_phrase
+
+Optional security phrase
+
+=item popnum
+
+Optional Access number number
+
+=back
+
+Fields used when provisioning an svc_domain service:
+
+=over 4
+
+=item domain
+
+Domain
+
+=back
+
+Fields used when provisioning an svc_phone service:
+
+=over 4
+
+=item phonenum
+
+Phone number
+
+=item pin
+
+Voicemail PIN
+
+=item sip_password
+
+SIP password
+
+=back
+
+Fields used when provisioning an svc_external service:
+
+=over 4
+
+=item id
+
+External numeric ID.
+
+=item title
+
+External text title.
+
+=back
+
+Returns a hash reference with a single key, B<error>, empty on success, or an
+error message on errors. The special error '_decline' is returned for
+declined transactions.
+
+=item renew_info
+
+Provides useful info for early renewals.
+
+Takes a hash reference as parameter with the following keys:
+
+=over 4
+
+=item session_id
+
+Session identifier
+
+=back
+
+Returns a hash reference. On errors, it contains a single key, B<error>, with
+the error message. Otherwise, contains a single key, B<dates>, pointing to
+an array refernce of hash references. Each hash reference contains the
+following keys:
+
+=over 4
+
+=item bill_date
+
+(Future) Bill date. Indicates a future date for which billing could be run.
+Specified as a integer UNIX timestamp. Pass this value to the B<order_renew>
+function.
+
+=item bill_date_pretty
+
+(Future) Bill date as a human-readable string. (Convenience for display;
+subject to change, so best not to parse for the date.)
+
+=item amount
+
+Base amount which will be charged if renewed early as of this date.
+
+=item renew_date
+
+Renewal date; i.e. even-futher future date at which the customer will be paid
+through if the early renewal is completed with the given B<bill-date>.
+Specified as a integer UNIX timestamp.
+
+=item renew_date_pretty
+
+Renewal date as a human-readable string. (Convenience for display;
+subject to change, so best not to parse for the date.)
+
+=back
+
+=item order_renew
+
+Renews this customer early; i.e. runs billing for this customer in advance.
+
+Takes a hash reference as parameter with the following keys:
+
+=over 4
+
+=item session_id
+
+Session identifier
+
+=item date
+
+Integer date as returned by the B<renew_info> function, indicating the advance
+date for which to run billing.
+
+=back
+
+Returns a hash reference with a single key, B<error>, empty on success, or an
+error message on errors.
+
+=item cancel_pkg
+
+Cancels a package for this customer.
+
+Takes a hash reference as parameter with the following keys:
+
+=over 4
+
+=item session_id
+
+Session identifier
+
+=item pkgpart
+
+pkgpart of package to cancel
+
+=back
+
+Returns a hash reference with a single key, B<error>, empty on success, or an
+error message on errors.
+
+=back
+
+=head1 SIGNUP FUNCTIONS
+
+=over 4
+
+=item signup_info HASHREF
+
+Takes a hash reference as parameter with the following keys:
+
+=over 4
+
+=item session_id - Optional agent/reseller interface session
+
+=back
+
+Returns a hash reference containing information that may be useful in
+displaying a signup page. The hash reference contains the following keys:
+
+=over 4
+
+=item cust_main_county
+
+County/state/country data - array reference of hash references, each of which has the fields of a cust_main_county record (see L<FS::cust_main_county>). Note these are not FS::cust_main_county objects, but hash references of columns and values.
+
+=item part_pkg
+
+Available packages - array reference of hash references, each of which has the fields of a part_pkg record (see L<FS::part_pkg>). Each hash reference also has an additional 'payby' field containing an array reference of acceptable payment types specific to this package (see below and L<FS::part_pkg/payby>). Note these are not FS::part_pkg objects, but hash references of columns and values. Requires the 'signup_server-default_agentnum' configuration value to be set, or
+an agentnum specified explicitly via reseller interface session_id in the
+options.
+
+=item agent
+
+Array reference of hash references, each of which has the fields of an agent record (see L<FS::agent>). Note these are not FS::agent objects, but hash references of columns and values.
+
+=item agentnum2part_pkg
+
+Hash reference; keys are agentnums, values are array references of available packages for that agent, in the same format as the part_pkg arrayref above.
+
+=item svc_acct_pop
+
+Access numbers - array reference of hash references, each of which has the fields of an svc_acct_pop record (see L<FS::svc_acct_pop>). Note these are not FS::svc_acct_pop objects, but hash references of columns and values.
+
+=item security_phrase
+
+True if the "security_phrase" feature is enabled
+
+=item payby
+
+Array reference of acceptable payment types for signup
+
+=over 4
+
+=item CARD
+
+credit card - automatic
+
+=item DCRD
+
+credit card - on-demand - version 1.5+ only
+
+=item CHEK
+
+electronic check - automatic
+
+=item DCHK
+
+electronic check - on-demand - version 1.5+ only
+
+=item LECB
+
+Phone bill billing
+
+=item BILL
+
+billing, not recommended for signups
+
+=item COMP
+
+free, definitely not recommended for signups
+
+=item PREPAY
+
+special billing type: applies a credit (see FS::prepay_credit) and sets billing type to BILL
+
+=back
+
+=item cvv_enabled
+
+True if CVV features are available (1.5+ or 1.4.2 with CVV schema patch)
+
+=item msgcat
+
+Hash reference of message catalog values, to support error message customization. Currently available keys are: passwords_dont_match, invalid_card, unknown_card_type, and not_a (as in "Not a Discover card"). Values are configured in the web interface under "View/Edit message catalog".
+
+=item statedefault
+
+Default state
+
+=item countrydefault
+
+Default country
+
+=back
+
+=item new_customer HASHREF
+
+Creates a new customer. Takes a hash reference as parameter with the
+following keys:
+
+=over 4
+
+=item first
+
+first name (required)
+
+=item last
+
+last name (required)
+
+=item ss
+
+(not typically collected; mostly used for ACH transactions)
+
+=item company
+
+Company name
+
+=item address1 (required)
+
+Address line one
+
+=item address2
+
+Address line two
+
+=item city (required)
+
+City
+
+=item county
+
+County
+
+=item state (required)
+
+State
+
+=item zip (required)
+
+Zip or postal code
+
+=item daytime
+
+Daytime phone number
+
+=item night
+
+Evening phone number
+
+=item fax
+
+Fax number
+
+=item payby
+
+CARD, DCRD, CHEK, DCHK, LECB, BILL, COMP or PREPAY (see L</signup_info> (required)
+
+=item payinfo
+
+Card number for CARD/DCRD, account_number@aba_number for CHEK/DCHK, prepaid "pin" for PREPAY, purchase order number for BILL
+
+=item paycvv
+
+Credit card CVV2 number (1.5+ or 1.4.2 with CVV schema patch)
+
+=item paydate
+
+Expiration date for CARD/DCRD
+
+=item payname
+
+Exact name on credit card for CARD/DCRD, bank name for CHEK/DCHK
+
+=item invoicing_list
+
+comma-separated list of email addresses for email invoices. The special value 'POST' is used to designate postal invoicing (it may be specified alone or in addition to email addresses),
+
+=item referral_custnum
+
+referring customer number
+
+=item agentnum
+
+Agent number
+
+=item pkgpart
+
+pkgpart of initial package
+
+=item username
+
+Username
+
+=item _password
+
+Password
+
+=item sec_phrase
+
+Security phrase
+
+=item popnum
+
+Access number (index, not the literal number)
+
+=item countrycode
+
+Country code (to be provisioned as a service)
+
+=item phonenum
+
+Phone number (to be provisioned as a service)
+
+=item pin
+
+Voicemail PIN
+
+=back
+
+Returns a hash reference with the following keys:
+
+=over 4
+
+=item error
+
+Empty on success, or an error message on errors. The special error '_decline' is returned for declined transactions; other error messages should be suitable for display to the user (and are customizable in under Configuration | View/Edit message catalog)
+
+=back
+
+=item regionselector HASHREF | LIST
+
+Takes as input a hashref or list of key/value pairs with the following keys:
+
+=over 4
+
+=item selected_county
+
+Currently selected county
+
+=item selected_state
+
+Currently selected state
+
+=item selected_country
+
+Currently selected country
+
+=item prefix
+
+Specify a unique prefix string if you intend to use the HTML output multiple time son one page.
+
+=item onchange
+
+Specify a javascript subroutine to call on changes
+
+=item default_state
+
+Default state
+
+=item default_country
+
+Default country
+
+=item locales
+
+An arrayref of hash references specifying regions. Normally you can just pass the value of the I<cust_main_county> field returned by B<signup_info>.
+
+=back
+
+Returns a list consisting of three HTML fragments for county selection,
+state selection and country selection, respectively.
+
+=cut
+
+#false laziness w/FS::cust_main_county (this is currently the "newest" version)
+sub regionselector {
+ my $param;
+ if ( ref($_[0]) ) {
+ $param = shift;
+ } else {
+ $param = { @_ };
+ }
+ $param->{'selected_country'} ||= $param->{'default_country'};
+ $param->{'selected_state'} ||= $param->{'default_state'};
+
+ my $prefix = exists($param->{'prefix'}) ? $param->{'prefix'} : '';
+
+ my $countyflag = 0;
+
+ my %cust_main_county;
+
+# unless ( @cust_main_county ) { #cache
+ #@cust_main_county = qsearch('cust_main_county', {} );
+ #foreach my $c ( @cust_main_county ) {
+ foreach my $c ( @{ $param->{'locales'} } ) {
+ #$countyflag=1 if $c->county;
+ $countyflag=1 if $c->{county};
+ #push @{$cust_main_county{$c->country}{$c->state}}, $c->county;
+ #$cust_main_county{$c->country}{$c->state}{$c->county} = 1;
+ $cust_main_county{$c->{country}}{$c->{state}}{$c->{county}} = 1;
+ }
+# }
+ $countyflag=1 if $param->{selected_county};
+
+ my $script_html = <<END;
+ <SCRIPT>
+ function opt(what,value,text) {
+ var optionName = new Option(text, value, false, false);
+ var length = what.length;
+ what.options[length] = optionName;
+ }
+ function ${prefix}country_changed(what) {
+ country = what.options[what.selectedIndex].text;
+ for ( var i = what.form.${prefix}state.length; i >= 0; i-- )
+ what.form.${prefix}state.options[i] = null;
+END
+ #what.form.${prefix}state.options[0] = new Option('', '', false, true);
+
+ foreach my $country ( sort keys %cust_main_county ) {
+ $script_html .= "\nif ( country == \"$country\" ) {\n";
+ foreach my $state ( sort keys %{$cust_main_county{$country}} ) {
+ my $text = $state || '(n/a)';
+ $script_html .= qq!opt(what.form.${prefix}state, "$state", "$text");\n!;
+ }
+ $script_html .= "}\n";
+ }
+
+ $script_html .= <<END;
+ }
+ function ${prefix}state_changed(what) {
+END
+
+ if ( $countyflag ) {
+ $script_html .= <<END;
+ state = what.options[what.selectedIndex].text;
+ country = what.form.${prefix}country.options[what.form.${prefix}country.selectedIndex].text;
+ for ( var i = what.form.${prefix}county.length; i >= 0; i-- )
+ what.form.${prefix}county.options[i] = null;
+END
+
+ foreach my $country ( sort keys %cust_main_county ) {
+ $script_html .= "\nif ( country == \"$country\" ) {\n";
+ foreach my $state ( sort keys %{$cust_main_county{$country}} ) {
+ $script_html .= "\nif ( state == \"$state\" ) {\n";
+ #foreach my $county ( sort @{$cust_main_county{$country}{$state}} ) {
+ foreach my $county ( sort keys %{$cust_main_county{$country}{$state}} ) {
+ my $text = $county || '(n/a)';
+ $script_html .=
+ qq!opt(what.form.${prefix}county, "$county", "$text");\n!;
+ }
+ $script_html .= "}\n";
+ }
+ $script_html .= "}\n";
+ }
+ }
+
+ $script_html .= <<END;
+ }
+ </SCRIPT>
+END
+
+ my $county_html = $script_html;
+ if ( $countyflag ) {
+ $county_html .= qq!<SELECT NAME="${prefix}county" onChange="$param->{'onchange'}">!;
+ $county_html .= '</SELECT>';
+ } else {
+ $county_html .=
+ qq!<INPUT TYPE="hidden" NAME="${prefix}county" VALUE="$param->{'selected_county'}">!;
+ }
+
+ my $state_html = qq!<SELECT NAME="${prefix}state" !.
+ qq!onChange="${prefix}state_changed(this); $param->{'onchange'}">!;
+ foreach my $state ( sort keys %{ $cust_main_county{$param->{'selected_country'}} } ) {
+ my $text = $state || '(n/a)';
+ my $selected = $state eq $param->{'selected_state'} ? 'SELECTED' : '';
+ $state_html .= "\n<OPTION $selected VALUE=$state>$text</OPTION>"
+ }
+ $state_html .= '</SELECT>';
+
+ my $country_html = '';
+ if ( scalar( keys %cust_main_county ) > 1 ) {
+
+ $country_html = qq(<SELECT NAME="${prefix}country" ).
+ qq(onChange="${prefix}country_changed(this); ).
+ $param->{'onchange'}.
+ '"'.
+ '>';
+ my $countrydefault = $param->{default_country} || 'US';
+ foreach my $country (
+ sort { ($b eq $countrydefault) <=> ($a eq $countrydefault) or $a cmp $b }
+ keys %cust_main_county
+ ) {
+ my $selected = $country eq $param->{'selected_country'}
+ ? ' SELECTED'
+ : '';
+ $country_html .= "\n<OPTION$selected>$country</OPTION>"
+ }
+ $country_html .= '</SELECT>';
+ } else {
+
+ $country_html = qq(<INPUT TYPE="hidden" NAME="${prefix}country" ).
+ ' VALUE="'. (keys %cust_main_county )[0]. '">';
+
+ }
+
+ ($county_html, $state_html, $country_html);
+
+}
+
+sub regionselector_hashref {
+ my ($county_html, $state_html, $country_html) = regionselector(@_);
+ {
+ 'county_html' => $county_html,
+ 'state_html' => $state_html,
+ 'country_html' => $country_html,
+ };
+}
+
+#=item expselect HASHREF | LIST
+#
+#Takes as input a hashref or list of key/value pairs with the following keys:
+#
+#=over 4
+#
+#=item prefix - Specify a unique prefix string if you intend to use the HTML output multiple time son one page.
+#
+#=item date - current date, in yyyy-mm-dd or m-d-yyyy format
+#
+#=back
+
+=item expselect PREFIX [ DATE ]
+
+Takes as input a unique prefix string and the current expiration date, in
+yyyy-mm-dd or m-d-yyyy format
+
+Returns an HTML fragments for expiration date selection.
+
+=cut
+
+sub expselect {
+ #my $param;
+ #if ( ref($_[0]) ) {
+ # $param = shift;
+ #} else {
+ # $param = { @_ };
+ #my $prefix = $param->{'prefix'};
+ #my $prefix = exists($param->{'prefix'}) ? $param->{'prefix'} : '';
+ #my $date = exists($param->{'date'}) ? $param->{'date'} : '';
+ my $prefix = shift;
+ my $date = scalar(@_) ? shift : '';
+
+ my( $m, $y ) = ( 0, 0 );
+ if ( $date =~ /^(\d{4})-(\d{2})-\d{2}$/ ) { #PostgreSQL date format
+ ( $m, $y ) = ( $2, $1 );
+ } elsif ( $date =~ /^(\d{1,2})-(\d{1,2}-)?(\d{4}$)/ ) {
+ ( $m, $y ) = ( $1, $3 );
+ }
+ my $return = qq!<SELECT NAME="$prefix!. qq!_month" SIZE="1">!;
+ for ( 1 .. 12 ) {
+ $return .= qq!<OPTION VALUE="$_"!;
+ $return .= " SELECTED" if $_ == $m;
+ $return .= ">$_";
+ }
+ $return .= qq!</SELECT>/<SELECT NAME="$prefix!. qq!_year" SIZE="1">!;
+ my @t = localtime;
+ my $thisYear = $t[5] + 1900;
+ for ( ($thisYear > $y && $y > 0 ? $y : $thisYear) .. ($thisYear+10) ) {
+ $return .= qq!<OPTION VALUE="$_"!;
+ $return .= " SELECTED" if $_ == $y;
+ $return .= ">$_";
+ }
+ $return .= "</SELECT>";
+
+ $return;
+}
+
+=item popselector HASHREF | LIST
+
+Takes as input a hashref or list of key/value pairs with the following keys:
+
+=over 4
+
+=item popnum
+
+Access number number
+
+=item pops
+
+An arrayref of hash references specifying access numbers. Normally you can just pass the value of the I<svc_acct_pop> field returned by B<signup_info>.
+
+=back
+
+Returns an HTML fragment for access number selection.
+
+=cut
+
+#horrible false laziness with FS/FS/svc_acct_pop.pm::popselector
+sub popselector {
+ my $param;
+ if ( ref($_[0]) ) {
+ $param = shift;
+ } else {
+ $param = { @_ };
+ }
+ my $popnum = $param->{'popnum'};
+ my $pops = $param->{'pops'};
+
+ return '<INPUT TYPE="hidden" NAME="popnum" VALUE="">' unless @$pops;
+ return $pops->[0]{city}. ', '. $pops->[0]{state}.
+ ' ('. $pops->[0]{ac}. ')/'. $pops->[0]{exch}. '-'. $pops->[0]{loc}.
+ '<INPUT TYPE="hidden" NAME="popnum" VALUE="'. $pops->[0]{popnum}. '">'
+ if scalar(@$pops) == 1;
+
+ my %pop = ();
+ my %popnum2pop = ();
+ foreach (@$pops) {
+ push @{ $pop{ $_->{state} }->{ $_->{ac} } }, $_;
+ $popnum2pop{$_->{popnum}} = $_;
+ }
+
+ my $text = <<END;
+ <SCRIPT>
+ function opt(what,href,text) {
+ var optionName = new Option(text, href, false, false)
+ var length = what.length;
+ what.options[length] = optionName;
+ }
+END
+
+ my $init_popstate = $param->{'init_popstate'};
+ if ( $init_popstate ) {
+ $text .= '<INPUT TYPE="hidden" NAME="init_popstate" VALUE="'.
+ $init_popstate. '">';
+ } else {
+ $text .= <<END;
+ function acstate_changed(what) {
+ state = what.options[what.selectedIndex].text;
+ what.form.popac.options.length = 0
+ what.form.popac.options[0] = new Option("Area code", "-1", false, true);
+END
+ }
+
+ my @states = $init_popstate ? ( $init_popstate ) : keys %pop;
+ foreach my $state ( sort { $a cmp $b } @states ) {
+ $text .= "\nif ( state == \"$state\" ) {\n" unless $init_popstate;
+
+ foreach my $ac ( sort { $a cmp $b } keys %{ $pop{$state} }) {
+ $text .= "opt(what.form.popac, \"$ac\", \"$ac\");\n";
+ if ($ac eq $param->{'popac'}) {
+ $text .= "what.form.popac.options[what.form.popac.length-1].selected = true;\n";
+ }
+ }
+ $text .= "}\n" unless $init_popstate;
+ }
+ $text .= "popac_changed(what.form.popac)}\n";
+
+ $text .= <<END;
+ function popac_changed(what) {
+ ac = what.options[what.selectedIndex].text;
+ what.form.popnum.options.length = 0;
+ what.form.popnum.options[0] = new Option("City", "-1", false, true);
+
+END
+
+ foreach my $state ( @states ) {
+ foreach my $popac ( keys %{ $pop{$state} } ) {
+ $text .= "\nif ( ac == \"$popac\" ) {\n";
+
+ foreach my $pop ( @{$pop{$state}->{$popac}}) {
+ my $o_popnum = $pop->{popnum};
+ my $poptext = $pop->{city}. ', '. $pop->{state}.
+ ' ('. $pop->{ac}. ')/'. $pop->{exch}. '-'. $pop->{loc};
+
+ $text .= "opt(what.form.popnum, \"$o_popnum\", \"$poptext\");\n";
+ if ($popnum == $o_popnum) {
+ $text .= "what.form.popnum.options[what.form.popnum.length-1].selected = true;\n";
+ }
+ }
+ $text .= "}\n";
+ }
+ }
+
+
+ $text .= "}\n</SCRIPT>\n";
+
+ $text .=
+ qq!<TABLE CELLPADDING="0"><TR><TD><SELECT NAME="acstate"! .
+ qq!SIZE=1 onChange="acstate_changed(this)"><OPTION VALUE=-1>State!;
+ $text .= "<OPTION" . ($_ eq $param->{'acstate'} ? " SELECTED" : "") .
+ ">$_" foreach sort { $a cmp $b } @states;
+ $text .= '</SELECT>'; #callback? return 3 html pieces? #'</TD>';
+
+ $text .=
+ qq!<SELECT NAME="popac" SIZE=1 onChange="popac_changed(this)">!.
+ qq!<OPTION>Area code</SELECT></TR><TR VALIGN="top">!;
+
+ $text .= qq!<TR><TD><SELECT NAME="popnum" SIZE=1 STYLE="width: 20em"><OPTION>City!;
+
+
+ #comment this block to disable initial list polulation
+ my @initial_select = ();
+ if ( scalar( @$pops ) > 100 ) {
+ push @initial_select, $popnum2pop{$popnum} if $popnum2pop{$popnum};
+ } else {
+ @initial_select = @$pops;
+ }
+ foreach my $pop ( sort { $a->{state} cmp $b->{state} } @initial_select ) {
+ $text .= qq!<OPTION VALUE="!. $pop->{popnum}. '"'.
+ ( ( $popnum && $pop->{popnum} == $popnum ) ? ' SELECTED' : '' ). ">".
+ $pop->{city}. ', '. $pop->{state}.
+ ' ('. $pop->{ac}. ')/'. $pop->{exch}. '-'. $pop->{loc};
+ }
+
+ $text .= qq!</SELECT></TD></TR></TABLE>!;
+
+ $text;
+
+}
+
+=item domainselector HASHREF | LIST
+
+Takes as input a hashref or list of key/value pairs with the following keys:
+
+=over 4
+
+=item pkgnum
+
+Package number
+
+=item domsvc
+
+Service number of the selected item.
+
+=back
+
+Returns an HTML fragment for domain selection.
+
+=cut
+
+sub domainselector {
+ my $param;
+ if ( ref($_[0]) ) {
+ $param = shift;
+ } else {
+ $param = { @_ };
+ }
+ my $domsvc= $param->{'domsvc'};
+ my $rv =
+ domain_select_hash(map {$_ => $param->{$_}} qw(pkgnum svcpart pkgpart) );
+ my $domains = $rv->{'domains'};
+ $domsvc = $rv->{'domsvc'} unless $domsvc;
+
+ return '<INPUT TYPE="hidden" NAME="domsvc" VALUE="">'
+ unless scalar(keys %$domains);
+
+ if (scalar(keys %$domains) == 1) {
+ my $key;
+ foreach(keys %$domains) {
+ $key = $_;
+ }
+ return '<TR><TD ALIGN="right">Domain</TD><TD>'. $domains->{$key}.
+ '<INPUT TYPE="hidden" NAME="domsvc" VALUE="'. $key. '"></TD></TR>'
+ }
+
+ my $text .= qq!<TR><TD ALIGN="right">Domain</TD><TD><SELECT NAME="domsvc" SIZE=1 STYLE="width: 20em"><OPTION>(Choose Domain)!;
+
+
+ foreach my $domain ( sort { $domains->{$a} cmp $domains->{$b} } keys %$domains ) {
+ $text .= qq!<OPTION VALUE="!. $domain. '"'.
+ ( ( $domsvc && $domain == $domsvc ) ? ' SELECTED' : '' ). ">".
+ $domains->{$domain};
+ }
+
+ $text .= qq!</SELECT></TD></TR>!;
+
+ $text;
+
+}
+
+=item didselector HASHREF | LIST
+
+Takes as input a hashref or list of key/value pairs with the following keys:
+
+=over 4
+
+=item field
+
+Field name for the returned HTML fragment.
+
+=item svcpart
+
+Service definition (see L<FS::part_svc>)
+
+=back
+
+Returns an HTML fragment for DID selection.
+
+=cut
+
+sub didselector {
+ my $param;
+ if ( ref($_[0]) ) {
+ $param = shift;
+ } else {
+ $param = { @_ };
+ }
+
+ my $rv = mason_comp( 'comp'=>'/elements/select-did.html',
+ 'args'=>[ %$param ],
+ );
+
+ #hmm.
+ $rv->{'error'} || $rv->{'output'};
+
+}
+
+=back
+
+=head1 RESELLER FUNCTIONS
+
+Note: Resellers can also use the B<signup_info> and B<new_customer> functions
+with their active session, and the B<customer_info> and B<order_pkg> functions
+with their active session and an additional I<custnum> parameter.
+
+For the most part, development of the reseller web interface has been
+superceded by agent-virtualized access to the backend.
+
+=over 4
+
+=item agent_login
+
+Agent login
+
+=item agent_info
+
+Agent info
+
+=item agent_list_customers
+
+List agent's customers.
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<freeside-selfservice-clientd>, L<freeside-selfservice-server>
+
+=cut
+
+1;
+
diff --git a/fs_selfservice/FS-SelfService/SelfService/FreeRadiusVoip.pm b/fs_selfservice/FS-SelfService/SelfService/FreeRadiusVoip.pm
new file mode 100644
index 000000000..0df24f7d7
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/SelfService/FreeRadiusVoip.pm
@@ -0,0 +1,61 @@
+#Add this to the modules section of radiusd.conf
+# perl {
+# #path to this module
+# module=/usr/local/share/perl/5.8.8/FS/SelfService/FreeRadiusVoip.pm
+# func_authorize = authorize;
+# }
+#
+#In the Authorize section
+#Make sure that you have 'files' uncommented. Then add a line containing 'perl'
+# after it.
+#
+# #N/A# Add a line containing 'perl' to the Accounting section.
+#
+# and on debian systems, add this to /etc/init.d/freeradius, with the
+# correct path (http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=416266)
+# LD_PRELOAD=/usr/lib/libperl.so.5.8.8
+# export LD_PRELOAD
+
+BEGIN { $FS::SelfService::skip_uid_check = 1; }
+
+use strict;
+use vars qw(%RAD_REQUEST %RAD_REPLY %RAD_CHECK);
+#use Data::Dumper;
+use FS::SelfService qw(call_time);
+
+use constant RLM_MODULE_REJECT=> 0; #immediately reject the request
+use constant RLM_MODULE_FAIL=> 1; #module failed, don't reply
+use constant RLM_MODULE_OK=> 2; #the module is OK, continue
+use constant RLM_MODULE_HANDLED=> 3; #the module handled the request, so stop
+use constant RLM_MODULE_INVALID=> 4; #the module considers the request invalid
+use constant RLM_MODULE_USERLOCK=> 5; #reject the request (user is locked out)
+use constant RLM_MODULE_NOTFOUND=> 6; #user not found
+use constant RLM_MODULE_NOOP=> 7; #module succeeded without doing anything
+use constant RLM_MODULE_UPDATED=> 8; #OK (pairs modified)
+use constant RLM_MODULE_NUMCODES=> 9; #How many return codes there are
+
+sub authorize {
+
+ #&log_request_attributes();
+
+ my $response = call_time( 'src' => $RAD_REQUEST{'Calling-Station-Id'},
+ 'dst' => $RAD_REQUEST{'Called-Station-Id'}, );
+
+ if ( $response->{'error'} ) {
+ $RAD_REPLY{'Reply-Message'} = $response->{'error'};
+ return RLM_MODULE_REJECT;
+ } else {
+ $RAD_REPLY{'Session-Timeout'} = $response->{'seconds'};
+ return RLM_MODULE_OK;
+ }
+
+}
+
+sub log_request_attributes {
+ # This shouldn't be done in production environments!
+ # This is only meant for debugging!
+ for (keys %RAD_REQUEST) {
+ &radiusd::radlog(1, "RAD_REQUEST: $_ = $RAD_REQUEST{$_}");
+ }
+}
+
diff --git a/fs_selfservice/FS-SelfService/SelfService/XMLRPC.pm b/fs_selfservice/FS-SelfService/SelfService/XMLRPC.pm
new file mode 100644
index 000000000..4e0d3e909
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/SelfService/XMLRPC.pm
@@ -0,0 +1,88 @@
+package FS::SelfService::XMLRPC;
+
+=head1 NAME
+
+FS::SelfService::XMLRPC - Freeside XMLRPC accessible self-service API
+
+=head1 SYNOPSIS
+
+=head1 DESCRIPTION
+
+Use this API to implement your own client "self-service" module vi XMLRPC.
+
+Each routine described in L<FS::SelfService> is available vi XMLRPC as the
+method FS.SelfService.XMLRPC.B<method>. All values are passed to the
+selfservice-server in a struct of strings. The return values are in a
+struct as strings, arrays, or structs as appropriate for the values
+described in L<FS::SelfService>.
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<freeside-selfservice-clientd>, L<freeside-selfservice-server>,L<FS::SelfService>
+
+=cut
+
+use strict;
+use vars qw($DEBUG $AUTOLOAD);
+use FS::SelfService;
+
+$DEBUG = 0;
+$FS::SelfService::DEBUG = $DEBUG;
+
+sub AUTOLOAD {
+ my $call = $AUTOLOAD;
+ $call =~ s/^FS::SelfService::XMLRPC:://;
+ if (exists($FS::SelfService::autoload{$call})) {
+ shift; #discard package name;
+ $call = "FS::SelfService::$call";
+ no strict 'refs';
+ &{$call}(@_);
+ }else{
+ die "No such procedure: $call";
+ }
+}
+
+package SOAP::Transport::HTTP::Daemon; # yuck
+
+use POSIX qw(:sys_wait_h);
+
+no warnings 'redefine';
+
+sub handle {
+ my $self = shift->new;
+
+ local $SIG{CHLD} = 'IGNORE';
+
+ACCEPT:
+ while (my $c = $self->accept) {
+
+ my $kid = 0;
+ do {
+ $kid = waitpid(-1, WNOHANG);
+ warn "found kid $kid";
+ } while $kid > 0;
+
+ my $pid = fork;
+ next ACCEPT if $pid;
+
+ if ( not defined $pid ) {
+ warn "fork() failed: $!";
+ $c = undef;
+ } else {
+ while (my $r = $c->get_request) {
+ $self->request($r);
+ $self->SUPER::handle;
+ $c->send_response($self->response);
+ }
+ # replaced ->close, thanks to Sean Meisner <Sean.Meisner@VerizonWireless.com>
+ # shutdown() doesn't work on AIX. close() is used in this case. Thanks to Jos Clijmans <jos.clijmans@recyfin.be>
+ UNIVERSAL::isa($c, 'shutdown') ? $c->shutdown(2) : $c->close();
+ $c->close;
+ }
+ exit;
+ }
+}
+
+1;
diff --git a/fs_selfservice/FS-SelfService/cgi/ach_payment_results.html b/fs_selfservice/FS-SelfService/cgi/ach_payment_results.html
new file mode 100644
index 000000000..62419d152
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/ach_payment_results.html
@@ -0,0 +1,13 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+<FONT SIZE=4>Payment results</FONT><BR><BR>
+<%= if ( $error ) {
+ $OUT .= qq!<FONT SIZE="+1" COLOR="#ff0000">Error processing your payment: $error</FONT>!;
+} else {
+ $OUT .= 'Your payment was processed successfully. Thank you.';
+} %>
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/agent.cgi b/fs_selfservice/FS-SelfService/cgi/agent.cgi
new file mode 100644
index 000000000..6e8de619a
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/agent.cgi
@@ -0,0 +1,458 @@
+#!/usr/bin/perl -T
+#!/usr/bin/perl -Tw
+
+#some false laziness w/selfservice.cgi
+
+use strict;
+use vars qw($DEBUG $me $cgi $session_id $form_max $template_dir);
+use subs qw(do_template);
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
+use Business::CreditCard;
+use Text::Template;
+#use HTML::Entities;
+use FS::SelfService qw( agent_login agent_logout agent_info
+ agent_list_customers
+ signup_info new_customer
+ customer_info list_pkgs order_pkg
+ part_svc_info provision_acct provision_external
+ unprovision_svc
+ );
+
+$DEBUG = 0;
+$me = 'agent.cgi:';
+
+$template_dir = '.';
+
+$form_max = 255;
+
+warn "$me starting\n" if $DEBUG;
+
+warn "$me initializing CGI\n" if $DEBUG;
+$cgi = new CGI;
+
+unless ( defined $cgi->param('session') ) {
+ warn "$me no session defined, sending login page\n" if $DEBUG;
+ do_template('agent_login',{});
+ exit;
+}
+
+if ( $cgi->param('session') eq 'login' ) {
+
+ warn "$me processing login\n" if $DEBUG;
+
+ $cgi->param('username') =~ /^\s*([a-z0-9_\-\.\&]{0,$form_max})\s*$/i
+ or die "illegal username";
+ my $username = $1;
+
+ $cgi->param('password') =~ /^(.{0,$form_max})$/
+ or die "illegal password";
+ my $password = $1;
+
+ my $rv = agent_login(
+ 'username' => $username,
+ 'password' => $password,
+ );
+ if ( $rv->{error} ) {
+ do_template('agent_login', {
+ 'error' => $rv->{error},
+ 'username' => $username,
+ } );
+ exit;
+ } else {
+ $cgi->param('session' => $rv->{session_id} );
+ $cgi->param('action' => 'agent_main' );
+ }
+}
+
+$session_id = $cgi->param('session');
+
+warn "$me checking action\n" if $DEBUG;
+$cgi->param('action') =~
+ /^(agent_main|signup|process_signup|list_customers|view_customer|agent_provision|provision_svc|process_svc_acct|process_svc_external|delete_svc|agent_order_pkg|process_order_pkg|logout)$/
+ or die "unknown action ". $cgi->param('action');
+my $action = $1;
+
+warn "$me running $action\n" if $DEBUG;
+my $result = eval "&$action();";
+die $@ if $@;
+
+if ( $result->{error} eq "Can't resume session" ) { #ick
+ do_template('agent_login',{});
+ exit;
+}
+
+warn "$me processing template $action\n" if $DEBUG;
+do_template($action, {
+ 'session_id' => $session_id,
+ %{$result}
+});
+warn "$me done processing template $action\n" if $DEBUG;
+
+#--
+
+sub logout {
+ $action = 'agent_logout';
+ agent_logout( 'session_id' => $session_id );
+}
+
+sub agent_main { agent_info( 'session_id' => $session_id ); }
+
+sub signup { signup_info( 'session_id' => $session_id ); }
+
+sub process_signup {
+
+ my $init_data = signup_info( 'session_id' => $session_id );
+ if ( $init_data->{'error'} ) {
+ if ( $init_data->{'error'} eq "Can't resume session" ) { #ick
+ do_template('agent_login',{});
+ exit;
+ } else { #?
+ die $init_data->{'error'};
+ }
+ }
+
+ my $error = '';
+
+ #false laziness w/signup.cgi, identical except for agentnum vs session_id
+ my $payby = $cgi->param('payby');
+ if ( $payby eq 'CHEK' || $payby eq 'DCHK' ) {
+ #$payinfo = join('@', map { $cgi->param( $payby. "_payinfo$_" ) } (1,2) );
+ $cgi->param('payinfo' => $cgi->param($payby. '_payinfo1'). '@'.
+ $cgi->param($payby. '_payinfo2')
+ );
+ } else {
+ $cgi->param('payinfo' => $cgi->param( $payby. '_payinfo' ) );
+ }
+ $cgi->param('paydate' => $cgi->param( $payby. '_month' ). '-'.
+ $cgi->param( $payby. '_year' )
+ );
+ $cgi->param('payname' => $cgi->param( $payby. '_payname' ) );
+ $cgi->param('paycvv' => defined $cgi->param( $payby. '_paycvv' )
+ ? $cgi->param( $payby. '_paycvv' )
+ : ''
+ );
+
+ if ( $cgi->param('invoicing_list') ) {
+ $cgi->param('invoicing_list' => $cgi->param('invoicing_list'). ', POST')
+ if $cgi->param('invoicing_list_POST');
+ } else {
+ $cgi->param('invoicing_list' => 'POST' );
+ }
+
+ if ( $cgi->param('_password') ne $cgi->param('_password2') ) {
+ $error = $init_data->{msgcat}{passwords_dont_match}; #msgcat
+ $cgi->param('_password', '');
+ $cgi->param('_password2', '');
+ }
+
+ if ( $payby =~ /^(CARD|DCRD)$/ && $cgi->param('CARD_type') ) {
+ my $payinfo = $cgi->param('payinfo');
+ $payinfo =~ s/\D//g;
+
+ $payinfo =~ /^(\d{13,16})$/
+ or $error ||= $init_data->{msgcat}{invalid_card}; #. $self->payinfo;
+ $payinfo = $1;
+ validate($payinfo)
+ or $error ||= $init_data->{msgcat}{invalid_card}; #. $self->payinfo;
+ cardtype($payinfo) eq $cgi->param('CARD_type')
+ or $error ||= $init_data->{msgcat}{not_a}. $cgi->param('CARD_type');
+ }
+
+ unless ( $error ) {
+ my $rv = new_customer ( {
+ 'session_id' => $session_id,
+ map { $_ => scalar($cgi->param($_)) }
+ qw( last first ss company
+ address1 address2 city county state zip country
+ daytime night fax
+
+ ship_last ship_first ship_company
+ ship_address1 ship_address2 ship_city ship_county ship_state
+ ship_zip ship_country
+ ship_daytime ship_night ship_fax
+
+ payby payinfo paycvv paydate payname invoicing_list
+ referral_custnum promo_code reg_code
+ pkgpart username sec_phrase _password popnum refnum
+ ),
+ grep { /^snarf_/ } $cgi->param
+ } );
+ $error = $rv->{'error'};
+ }
+ #eslaf
+
+ if ( $error ) {
+ $action = 'signup';
+ my $r = {
+ $cgi->Vars,
+ %{$init_data},
+ 'error' => $error,
+ };
+ #warn join('\n', map "$_ => $r->{$_}", keys %$r )."\n";
+ $r;
+ } else {
+ $action = 'agent_main';
+ my $agent_info = agent_info( 'session_id' => $session_id );
+ $agent_info->{'message'} = 'Signup successful';
+ $agent_info;
+ }
+
+}
+
+sub list_customers {
+
+ my $results =
+ agent_list_customers( 'session_id' => $session_id,
+ map { $_ => $cgi->param($_) }
+ grep defined($cgi->param($_)),
+ qw(prospect active susp cancel),
+ 'search',
+ );
+
+ if ( scalar( @{$results->{'customers'}} ) == 1 ) {
+ $action = 'view_customer';
+ customer_info (
+ 'agent_session_id' => $session_id,
+ 'custnum' => $results->{'customers'}[0]{'custnum'},
+ );
+ } else {
+ $results;
+ }
+
+}
+
+sub view_customer {
+
+ #my $init_data = signup_info( 'session_id' => $session_id );
+ #if ( $init_data->{'error'} ) {
+ # if ( $init_data->{'error'} eq "Can't resume session" ) { #ick
+ # do_template('agent_login',{});
+ # exit;
+ # } else { #?
+ # die $init_data->{'error'};
+ # }
+ #}
+ #
+ #my $customer_info =
+ customer_info (
+ 'agent_session_id' => $session_id,
+ 'custnum' => $cgi->param('custnum'),
+ );
+ #
+ #return {
+ # ( map { $_ => $init_data->{$_} }
+ # qw( part_pkg security_phrase svc_acct_pop ),
+ # ),
+ # %$customer_info,
+ #};
+}
+
+sub agent_order_pkg {
+
+ my $init_data = signup_info( 'session_id' => $session_id );
+ if ( $init_data->{'error'} ) {
+ if ( $init_data->{'error'} eq "Can't resume session" ) { #ick
+ do_template('agent_login',{});
+ exit;
+ } else { #?
+ die $init_data->{'error'};
+ }
+ }
+
+ my $customer_info = customer_info (
+ 'agent_session_id' => $session_id,
+ 'custnum' => $cgi->param('custnum'),
+ );
+
+ return {
+ ( map { $_ => $init_data->{$_} }
+ qw( part_pkg security_phrase svc_acct_pop ),
+ ),
+ %$customer_info,
+ };
+
+}
+
+sub agent_provision {
+ my $result = list_pkgs(
+ 'agent_session_id' => $session_id,
+ 'custnum' => $cgi->param('custnum'),
+ );
+ die $result->{'error'} if exists $result->{'error'} && $result->{'error'};
+ $result;
+}
+
+sub provision_svc {
+
+ my $result = part_svc_info(
+ 'agent_session_id' => $session_id,
+ map { $_ => $cgi->param($_) } qw( pkgnum svcpart custnum ),
+ );
+ die $result->{'error'} if exists $result->{'error'} && $result->{'error'};
+
+ $result->{'svcdb'} =~ /^svc_(.*)$/
+ #or return { 'error' => 'Unknown svcdb '. $result->{'svcdb'} };
+ or die 'Unknown svcdb '. $result->{'svcdb'};
+ $action .= "_$1";
+ $action = "agent_$action";
+
+ $result;
+}
+
+sub process_svc_acct {
+
+ my $result = provision_acct (
+ 'agent_session_id' => $session_id,
+ map { $_ => $cgi->param($_) } qw(
+ custnum pkgnum svcpart username _password _password2 sec_phrase popnum )
+ );
+
+ if ( exists $result->{'error'} && $result->{'error'} ) {
+ #warn "$result $result->{'error'}";
+ $action = 'provision_svc_acct';
+ $action = "agent_$action";
+ return {
+ $cgi->Vars,
+ %{ part_svc_info( 'agent_session_id' => $session_id,
+ map { $_ => $cgi->param($_) } qw(pkgnum svcpart custnum)
+ )
+ },
+ 'error' => $result->{'error'},
+ };
+ } else {
+ #warn "$result $result->{'error'}";
+ $action = 'agent_provision';
+ return {
+ %{agent_provision()},
+ 'message' => $result->{'svc'}. ' setup successfully.',
+ };
+ }
+
+}
+
+sub process_svc_external {
+
+ my $result = provision_external (
+ 'agent_session_id' => $session_id,
+ map { $_ => $cgi->param($_) } qw( custnum pkgnum svcpart )
+ );
+
+ #warn "$result $result->{'error'}";
+ $action = 'agent_provision';
+ return {
+ %{agent_provision()},
+ 'message' => $result->{'error'}
+ ? '<FONT COLOR="#FF0000">'. $result->{'error'}. '</FONT>'
+ : $result->{'svc'}. ' setup successfully'.
+ ': serial number '.
+ sprintf('%010d', $result->{'id'}). '-'. $result->{'title'}
+ };
+
+}
+
+sub delete_svc {
+ my $result = unprovision_svc(
+ 'agent_session_id' => $session_id,
+ 'custnum' => $cgi->param('custnum'),
+ 'svcnum' => $cgi->param('svcnum'),
+ );
+
+ $action = 'agent_provision';
+
+ return {
+ %{agent_provision()},
+ 'message' => $result->{'error'}
+ ? '<FONT COLOR="#FF0000">'. $result->{'error'}. '</FONT>'
+ : $result->{'svc'}. ' removed.'
+ };
+
+}
+
+sub process_order_pkg {
+
+ my $results = '';
+
+ unless ( length($cgi->param('_password')) ) {
+ my $init_data = signup_info( 'session_id' => $session_id );
+ #die $init_data->{'error'} if $init_data->{'error'};
+ $results = { 'error' => $init_data->{msgcat}{empty_password} };
+ }
+ if ( $cgi->param('_password') ne $cgi->param('_password2') ) {
+ my $init_data = signup_info( 'session_id' => $session_id );
+ $results = { 'error' => $init_data->{msgcat}{passwords_dont_match} };
+ $cgi->param('_password', '');
+ $cgi->param('_password2', '');
+ }
+
+ $results ||= order_pkg (
+ 'agent_session_id' => $session_id,
+ map { $_ => $cgi->param($_) }
+ qw( custnum pkgpart username _password _password2 sec_phrase popnum )
+ );
+
+ if ( $results->{'error'} ) {
+ $action = 'agent_order_pkg';
+ return {
+ $cgi->Vars,
+ %{agent_order_pkg()},
+ #'message' => '<FONT COLOR="#FF0000">'. $results->{'error'}. '</FONT>',
+ 'error' => '<FONT COLOR="#FF0000">'. $results->{'error'}. '</FONT>',
+ };
+ } else {
+ $action = 'view_customer';
+ #$cgi->delete( grep { $_ ne 'custnum' } $cgi->param );
+ return {
+ %{view_customer()},
+ 'message' => 'Package order successful.',
+ };
+ }
+
+}
+
+#--
+
+sub do_template {
+ my $name = shift;
+ my $fill_in = shift;
+ #warn join(' / ', map { "$_=>".$fill_in->{$_} } keys %$fill_in). "\n";
+
+ $cgi->delete_all();
+ $fill_in->{'selfurl'} = $cgi->self_url; #OLD
+ $fill_in->{'self_url'} = $cgi->self_url;
+ $fill_in->{'cgi'} = \$cgi;
+
+ my $template = new Text::Template( TYPE => 'FILE',
+ SOURCE => "$template_dir/$name.html",
+ DELIMITERS => [ '<%=', '%>' ],
+ UNTAINT => 1, )
+ or die $Text::Template::ERROR;
+
+ local $^W = 0;
+ print $cgi->header( '-expires' => 'now' ),
+ $template->fill_in( PACKAGE => 'FS::SelfService::_agentcgi',
+ HASH => $fill_in
+ );
+}
+
+package FS::SelfService::_agentcgi;
+
+use HTML::Entities;
+use FS::SelfService qw(regionselector expselect popselector);
+
+#false laziness w/selfservice.cgi
+sub include {
+ my $name = shift;
+ my $template = new Text::Template( TYPE => 'FILE',
+ SOURCE => "$main::template_dir/$name.html",
+ DELIMITERS => [ '<%=', '%>' ],
+ UNTAINT => 1,
+ )
+ or die $Text::Template::ERROR;
+
+ $template->fill_in( PACKAGE => 'FS::SelfService::_agentcgi',
+ #HASH => $fill_in
+ );
+
+}
+
diff --git a/fs_selfservice/FS-SelfService/cgi/agent_customer_menu.html b/fs_selfservice/FS-SelfService/cgi/agent_customer_menu.html
new file mode 100644
index 000000000..603fc0bd2
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/agent_customer_menu.html
@@ -0,0 +1,7 @@
+<%= $url = "$selfurl?session=$session_id;custnum=$custnum;action="; ''; %>
+<TD VALIGN="top" HEIGHT=384 BGCOLOR="#dddddd">
+<A HREF="<%= $url %>agent_provision">Setup services</A><BR><BR>
+<A HREF="<%= $url %>agent_order_pkg">Purchase additional package</A><BR><BR>
+
+</TD>
+
diff --git a/fs_selfservice/FS-SelfService/cgi/agent_delete_svc.html b/fs_selfservice/FS-SelfService/cgi/agent_delete_svc.html
new file mode 100644
index 000000000..63fa127b2
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/agent_delete_svc.html
@@ -0,0 +1,17 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+<%= $small_custview %>
+<BR>
+<%= if ( $error ) {
+
+ $OUT .= qq!<FONT SIZE="+1" COLOR="#ff0000">Error: $error</FONT>!;
+} else {
+ $OUT .= "<FONT SIZE=4>$svc removed.</FONT>";
+} %>
+
+</TD></TR></TABLE>
+
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/agent_login.html b/fs_selfservice/FS-SelfService/cgi/agent_login.html
new file mode 100644
index 000000000..4b0778ec5
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/agent_login.html
@@ -0,0 +1,22 @@
+<HTML><HEAD><TITLE>Reseller Login</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=5>Reseller Login</FONT><BR><BR>
+<FONT SIZE="+1" COLOR="#ff0000"><%= $error %></FONT>
+<FORM ACTION="<%= $self_url %>" METHOD=POST>
+<INPUT TYPE="hidden" NAME="session" VALUE="login">
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=2 CELLPADDING=0>
+<TR>
+ <TH ALIGN="right">Username </TH>
+ <TD>
+ <INPUT TYPE="text" NAME="username" VALUE="<%= $username %>">
+ </TD>
+</TR>
+<TR>
+ <TH ALIGN="right">Password </TH>
+ <TD>
+ <INPUT TYPE="password" NAME="password">
+ </TD>
+</TR>
+</TABLE>
+<BR><BR><INPUT TYPE="submit" VALUE="Login">
+</FORM></BODY></HTML>
+
diff --git a/fs_selfservice/FS-SelfService/cgi/agent_logout.html b/fs_selfservice/FS-SelfService/cgi/agent_logout.html
new file mode 100644
index 000000000..98094679a
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/agent_logout.html
@@ -0,0 +1,5 @@
+<HTML><HEAD><TITLE>Reseller</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>Reseller</FONT><BR><BR>
+You have been logged out.
+</BODY></HTML>
+
diff --git a/fs_selfservice/FS-SelfService/cgi/agent_main.html b/fs_selfservice/FS-SelfService/cgi/agent_main.html
new file mode 100644
index 000000000..3aefd61b1
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/agent_main.html
@@ -0,0 +1,33 @@
+<HTML><HEAD><TITLE>Reseller</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>Reseller</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<TABLE BORDER=0 CELLPADDING=4><TR>
+<%= include('agent_menu') %>
+<TD VALIGN="top">
+
+<%= $message
+ ? "<FONT SIZE=\"+2\"><B>$message</B></FONT>"
+ : "Hello $agent!"
+%><BR><BR>
+
+<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=2 BGCOLOR="#eeeeee">
+<TR><TH BGCOLOR="#cccccc">Customer summary</TH></TR>
+<TR><TD BGCOLOR="#dddddd">
+
+ <B><%= $num_prospect %></B>
+ <%= $num_prospect ? qq!<A HREF="${url}list_customers;prospect=1">! : '' %>prospects</A>
+
+ <BR><FONT COLOR="#00CC00"><B><%= $num_active %></B></FONT>
+ <%= $num_active ? qq!<A HREF="${url}list_customers;active=1">! : '' %>active</A>
+
+ <BR><FONT COLOR="#FF9900"><B><%= $num_susp %></B></FONT>
+ <%= $num_susp ? qq!<A HREF="${url}list_customers;susp=1">! : '' %>suspended</A>
+
+ <BR><FONT COLOR="#FF0000"><B><%= $num_cancel %></B></FONT>
+ <%= $num_cancel ? qq!<A HREF="${url}list_customers;cancel=1">! : '' %>cancelled</A>
+
+</TD></TR></TABLE>
+
+</TD></TR></TABLE>
+
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/agent_menu.html b/fs_selfservice/FS-SelfService/cgi/agent_menu.html
new file mode 100644
index 000000000..84a295304
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/agent_menu.html
@@ -0,0 +1,15 @@
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<TD VALIGN="top" HEIGHT=384 BGCOLOR="#dddddd">
+
+<A HREF="<%= $url %>agent_main">Overview</A><BR><BR>
+<A HREF="<%= $url %>signup">New customer<!--/prospect--></A><BR><BR>
+<FORM ACTION="<%= $selfurl %>">
+<INPUT TYPE="hidden" NAME="session" VALUE="<%= $session_id %>">
+<INPUT TYPE="hidden" NAME="action" VALUE="list_customers">
+<INPUT TYPE="text" NAME="search" SIZE=20><BR>
+<SMALL><I>cust&nbsp;#,&nbsp;last&nbsp;name,&nbsp;or&nbsp;company</I></SMALL><BR>
+<INPUT TYPE="submit" VALUE="Search customers"><BR>
+</FORM>
+<A HREF="<%= $url %>logout">Logout</A><BR><BR>
+
+</TD>
diff --git a/fs_selfservice/FS-SelfService/cgi/agent_order_pkg.html b/fs_selfservice/FS-SelfService/cgi/agent_order_pkg.html
new file mode 100644
index 000000000..18a37e891
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/agent_order_pkg.html
@@ -0,0 +1,18 @@
+<HTML><HEAD><TITLE>Reseller</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>Reseller</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;custnum=$custnum;action="; ''; %>
+<TABLE BORDER=0 CELLPADDING=4><TR>
+<%= include('agent_menu') %>
+<TD VALIGN="top">
+<%= $small_custview %>
+<BR>
+
+<TABLE BORDER=0 CELLPADDING=4><TR>
+<%= include('agent_customer_menu') %>
+<TD VALIGN="top">
+<%= include('order_pkg') %>
+</TD></TR></TABLE>
+
+</TD></TR></TABLE>
+
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/agent_provision.html b/fs_selfservice/FS-SelfService/cgi/agent_provision.html
new file mode 100644
index 000000000..f7f39b513
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/agent_provision.html
@@ -0,0 +1,23 @@
+<HTML><HEAD><TITLE>Reseller</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>Reseller</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;custnum=$custnum;action="; ''; %>
+<TABLE BORDER=0 CELLPADDING=4><TR>
+<%= include('agent_menu') %>
+<TD VALIGN="top">
+
+<%= $message
+ ? "<FONT SIZE=\"+2\"><B>$message</B></FONT><BR><BR>"
+ : ''
+%>
+
+<%= $small_custview %>
+<BR>
+
+<TABLE BORDER=0 CELLPADDING=4><TR>
+<%= include('agent_customer_menu') %>
+<TD VALIGN="top">
+<%= include('provision_list') %>
+</TD></TR></TABLE>
+
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/agent_provision_svc_acct.html b/fs_selfservice/FS-SelfService/cgi/agent_provision_svc_acct.html
new file mode 100644
index 000000000..a867edb08
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/agent_provision_svc_acct.html
@@ -0,0 +1,16 @@
+<HTML><HEAD><TITLE>Reseller</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>Reseller</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;custnum=$custnum;action="; ''; %>
+<TABLE BORDER=0 CELLPADDING=4><TR>
+<%= include('agent_menu') %>
+<TD VALIGN="top">
+<%= $small_custview %>
+<BR>
+<TABLE BORDER=0 CELLPADDING=4><TR>
+<%= include('agent_customer_menu') %>
+<TD VALIGN="top">
+<%= include('svc_acct') %>
+</TD></TR></TABLE>
+
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/bill.html b/fs_selfservice/FS-SelfService/cgi/bill.html
new file mode 100644
index 000000000..1b5902740
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/bill.html
@@ -0,0 +1,15 @@
+<TR>
+ <TD ALIGN="right">P.O.&nbsp;number</TD>
+ <TD><INPUT TYPE="text" NAME="payinfo" SIZE=10 MAXLENGTH=20 VALUE="<%=$payinfo%>"></TD>
+</TR><TR>
+ <TD ALIGN="right">Attention</TD>
+ <TD><INPUT TYPE="text" SIZE=32 MAXLENGTH=80 NAME="payname" VALUE="<%=$payname%>"></TD>
+</TR><TR>
+ <TD><INPUT TYPE="checkbox" NAME="postal_invoicing" VALUE="POST" <%=
+ $postal_invoicing ? 'CHECKED' : ''
+ %>></TD>
+ <TD>Postal mail invoice</TD>
+</TR><TR>
+ <TD>Email address(es)</TD>
+ <TD><INPUT TYPE="text" NAME="invoicing_list" VALUE="<%= join(',', $invoicing_list ) %>"></TD>
+</TR>
diff --git a/fs_selfservice/FS-SelfService/cgi/card.html b/fs_selfservice/FS-SelfService/cgi/card.html
new file mode 100644
index 000000000..cf6d20d8d
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/card.html
@@ -0,0 +1,73 @@
+<TR>
+ <TD ALIGN="right">Card&nbsp;number</TD>
+ <TD>
+ <TABLE>
+ <TR>
+ <TD>
+ <INPUT TYPE="text" NAME="payinfo" SIZE=20 MAXLENGTH=19 VALUE="<%=$payinfo%>"> </TD>
+ <TD>Exp.</TD>
+ <TD>
+ <SELECT NAME="month">
+ <%= for ( ( map "0$_", 1 .. 9 ), 10 .. 12 ) {
+ $OUT .= '<OPTION'. ($_ == $month ? ' SELECTED' : ''). ">$_\n";
+ } %>
+ </SELECT>
+ </TD>
+ <TD> / </TD>
+ <TD>
+ <SELECT NAME="year">
+ <%= my @a = localtime; for ( $a[5]+1900 .. $a[5]+1915 ) {
+ $OUT .= '<OPTION'. ($_ == $year ? ' SELECTED' : ''). ">$_\n";
+ } %>
+ </SELECT>
+ </TD>
+ </TR>
+ </TABLE>
+ </TD>
+</TR>
+<%=
+ if ( $withcvv ) {
+ $OUT .= qq!<TR>!;
+ $OUT .= qq!<TD ALIGN="right">CVV2&nbsp;(<A HREF="javascript:myopen('cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>)</TD>!;
+ $OUT .= qq!<TD><INPUT TYPE="text" NAME="paycvv" VALUE="" SIZE=4 MAXLENGTH=4></TD>!;
+ $OUT .= qq!</TR>!;
+ }
+ '';
+%>
+<TR>
+ <TD ALIGN="right">Exact&nbsp;name&nbsp;on&nbsp;card</TD>
+ <TD><INPUT TYPE="text" SIZE=32 MAXLENGTH=80 NAME="payname" VALUE="<%=$payname%>"></TD>
+</TR><TR>
+ <TD ALIGN="right">Card&nbsp;billing&nbsp;address</TD>
+ <TD>
+ <INPUT TYPE="text" SIZE=40 MAXLENGTH=80 NAME="address1" VALUE="<%=$address1%>">
+ </TD>
+</TR><TR>
+ <TD ALIGN="right">Address&nbsp;line&nbsp;2</TD>
+ <TD>
+ <INPUT TYPE="text" SIZE=40 MAXLENGTH=80 NAME="address2" VALUE="<%=$address2%>">
+ </TD>
+</TR><TR>
+ <TD ALIGN="right">City</TD>
+ <TD>
+ <TABLE>
+ <TR>
+ <TD>
+ <INPUT TYPE="text" NAME="city" SIZE="12" MAXLENGTH=80 VALUE="<%=$city%>">
+ </TD>
+ <TD>State</TD>
+ <TD>
+ <SELECT NAME="state">
+ <%= for ( @states ) {
+ $OUT .= '<OPTION'. ($_ eq $state ? ' SELECTED' : '' ). ">$_\n";
+ } %>
+ </SELECT>
+ </TD>
+ <TD>Zip</TD>
+ <TD>
+ <INPUT TYPE="text" NAME="zip" SIZE=11 MAXLENGTH=10 VALUE="<%=$zip%>">
+ </TD>
+ </TR>
+ </TABLE>
+ </TD>
+</TR>
diff --git a/fs_selfservice/FS-SelfService/cgi/change_bill.html b/fs_selfservice/FS-SelfService/cgi/change_bill.html
new file mode 100755
index 000000000..f186c9b51
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/change_bill.html
@@ -0,0 +1,23 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee">
+<FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+<FONT SIZE=4>Edit billing address</FONT><BR><BR>
+<%= if ( $error ) {
+ $OUT .= qq!<FONT SIZE="+1" COLOR="#ff0000">Error: $error</FONT><BR><BR>!;
+} ''; %>
+
+<FORM NAME="ChangeBillForm" ACTION="<%= $selfurl %>" METHOD=POST onSubmit="document.bottomform.submit.disabled=true;">
+<INPUT TYPE="hidden" NAME="session" VALUE="<%= $session_id %>">
+<INPUT TYPE="hidden" NAME="action" VALUE="process_change_bill">
+<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0>
+
+<%= $r=qq!<font color="#ff0000">*</font>&nbsp;!; include('contact') %>
+
+<INPUT TYPE="submit" NAME="submit" VALUE="<%= $custnum ? "Apply Changes" : "Add Customer" %>">
+<BR>
+</FORM>
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/change_password.html b/fs_selfservice/FS-SelfService/cgi/change_password.html
new file mode 100644
index 000000000..dcfce3173
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/change_password.html
@@ -0,0 +1,51 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+
+<FONT SIZE=4>Change password</FONT><BR><BR>
+
+<%= if ( $error ) {
+ $OUT .= qq!<FONT SIZE="+1" COLOR="#ff0000">$error</FONT><BR><BR>!;
+} ''; %>
+
+<FORM ACTION="<%= $selfurl %>" METHOD="POST">
+<INPUT TYPE="hidden" NAME="session" VALUE="<%= $session_id %>">
+<INPUT TYPE="hidden" NAME="action" VALUE="process_change_password">
+
+<TABLE BGCOLOR="#cccccc">
+
+ <TR>
+ <TH ALIGN="right">Change password for account: </TH>
+ <TD>
+ <SELECT NAME="svcnum">
+ <%= foreach my $svc ( @svcs ) {
+ $OUT .= '<OPTION VALUE="'. $svc->{'svcnum'}. '"'.
+ ( $svc->{'svcnum'} eq $svcnum ? ' SELECTED' : '' ). '>'.
+ $svc->{'label'}. ': '. $svc->{'value'}. "\n";
+ }
+ %>
+ </SELECT>
+ </TD>
+ </TR>
+
+ <TR>
+ <TH ALIGN="right">New password: </TH>
+ <TD><INPUT TYPE="password" NAME="new_password" SIZE="18"></TD>
+ </TR>
+
+ <TR>
+ <TH ALIGN="right">Re-enter new password: </TH>
+ <TD><INPUT TYPE="password" NAME="new_password2" SIZE="18"></TD>
+ </TR>
+
+</TABLE>
+<BR>
+
+<INPUT TYPE="submit" VALUE="Change password">
+
+</FORM>
+
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/change_pay.html b/fs_selfservice/FS-SelfService/cgi/change_pay.html
new file mode 100644
index 000000000..2bea9550b
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/change_pay.html
@@ -0,0 +1,73 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee">
+<script language="JavaScript"><!--
+ var mywindow = -1;
+ function myopen(filename,windowname,properties) {
+ myclose();
+ mywindow = window.open(filename,windowname,properties);
+ }
+ function myclose() {
+ if ( mywindow != -1 )
+ mywindow.close();
+ mywindow = -1
+ }
+//--></script>
+<FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+<FONT SIZE=4>Change payment information</FONT><BR><BR>
+<%= if ( $error ) {
+ $OUT .= qq!<FONT SIZE="+1" COLOR="#ff0000">Error: $error</FONT><BR><BR>!;
+ } ''; %>
+
+<FORM NAME="OneTrueForm" METHOD="POST" ACTION="<%=$selfurl%>" onSubmit="document.OneTrueForm.process.disabled=true">
+<%=
+ use Tie::IxHash;
+ use HTML::Widgets::SelectLayers;
+
+ my $preauto = '<TR><TD COLSPAN=3><INPUT TYPE="checkbox" NAME="auto" VALUE="1"';
+ my $postauto = '>Charge future payments to this card automatically</TD></TR>';
+
+ my $tail = qq(</TABLE><INPUT TYPE="hidden" NAME="session" VALUE="$session_id">).
+ qq(<INPUT TYPE="hidden" NAME="action" VALUE="process_change_pay">).
+ qq(<BR>).
+ qq(<INPUT TYPE="submit" NAME="process" ).
+ qq(VALUE="Save payment information"> ).
+ qq(<!-- onClick="this.disabled=true"> -->);
+
+
+ my %paybychecked = (
+ 'BILL' => include('bill'),
+ 'CARD' => include('card')."$preauto CHECKED $postauto",
+ 'DCRD' => include('card')."$preauto $postauto",
+ 'CHEK' => include('check')."$preauto CHECKED $postauto",
+ 'DCHK' => include('check')."$preauto $postauto",
+ );
+ my %payby_index = ( 'CARD' => qq/Credit Card/,
+ 'DCRD' => qq/Credit Card/,
+ 'CHEK' => qq/Check/,
+ 'DCHK' => qq/Check/,
+ 'LECB' => qq/Phone Bill Billing/,
+ 'BILL' => qq/Billing/,
+ 'COMP' => qq/Complimentary/,
+ 'PREPAY' => qq/Prepaid Card/,
+ );
+ tie my %options, 'Tie::IxHash', ();
+ foreach my $payby_option ( @paybys ) {
+ $options{$payby_option} = $payby_index{$payby_option};
+ }
+ $options{$payby} = $payby_index{$payby}
+ unless exists($options{$payby});
+
+ HTML::Widgets::SelectLayers->new(
+ options => \%options,
+ selected_layer => $payby,
+# form_name => 'dummy',
+# form_action => 'dummy.cgi',
+ layer_callback => sub { my $layer = shift; return '<TABLE BGCOLOR="#cccccc">'.$paybychecked{$layer}.qq!<INPUT TYPE="hidden" NAME="payby" VALUE="$layer">$tail!; },
+ )->html;
+
+%>
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/change_pkg.html b/fs_selfservice/FS-SelfService/cgi/change_pkg.html
new file mode 100644
index 000000000..a841308a5
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/change_pkg.html
@@ -0,0 +1,37 @@
+<SCRIPT TYPE="text/javascript">
+function enable_change_pkg () {
+ if ( document.ChangePkgForm.pkgpart.selectedIndex > 0 ) {
+ document.ChangePkgForm.submit.disabled = false;
+ } else {
+ document.ChangePkgForm.submit.disabled = true;
+ }
+}
+</SCRIPT>
+<FONT SIZE=4>Purchase replacement package for "<%= $pkg; %>"</FONT><BR><BR>
+<%= if ( $error ) {
+ $OUT .= qq!<FONT SIZE="+1" COLOR="#ff0000">$error</FONT><BR><BR>!;
+} ''; %>
+<FORM NAME="ChangePkgForm" ACTION="<%= $selfurl %>" METHOD=POST>
+<INPUT TYPE="hidden" NAME="session" VALUE="<%= $session_id %>">
+<INPUT TYPE="hidden" NAME="action" VALUE="process_change_pkg">
+<INPUT TYPE="hidden" NAME="pkgnum" VALUE="<%= $pkgnum %>">
+<INPUT TYPE="hidden" NAME="pkg" VALUE="<%= $pkg %>">
+<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0>
+<TR>
+ <TD COLSPAN=2><SELECT NAME="pkgpart" onChange="enable_change_pkg()">
+ <OPTION VALUE="">
+
+ <%=
+ foreach my $part_pkg ( @part_pkg ) {
+ $OUT .= '<OPTION VALUE="'. $part_pkg->{'pkgpart'}. '"';
+ $OUT .= ' SELECTED' if $pkgpart && $part_pkg->{'pkgpart'} == $pkgpart;
+ $OUT .= '>'. $part_pkg->{'pkg'};
+ }
+ %>
+
+ </SELECT></TD>
+</TR>
+</TABLE>
+<INPUT NAME="submit" TYPE="submit" VALUE="Purchase" disabled>
+</FORM>
+
diff --git a/fs_selfservice/FS-SelfService/cgi/change_ship.html b/fs_selfservice/FS-SelfService/cgi/change_ship.html
new file mode 100755
index 000000000..28ee94ed6
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/change_ship.html
@@ -0,0 +1,102 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee">
+<FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+<FONT SIZE=4>Edit service address</FONT><BR><BR>
+<%= if ( $error ) {
+ $OUT .= qq!<FONT SIZE="+1" COLOR="#ff0000">Error: $error</FONT><BR><BR>!;
+} ''; %>
+
+<FORM NAME="OneTrueForm" ACTION="<%= $selfurl %>" METHOD=POST onSubmit="document.bottomform.submit.disabled=true;">
+<INPUT TYPE="hidden" NAME="session" VALUE="<%= $session_id %>">
+<INPUT TYPE="hidden" NAME="action" VALUE="process_change_ship">
+<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0>
+
+<%=
+ foreach (
+ qw( last first company address1 address2 city county state zip country
+ daytime night fax )
+ ) {
+ $OUT .= qq!<INPUT TYPE="hidden" NAME="$_" VALUE="${$_}">!;
+ };
+ '';
+%>
+<SCRIPT>
+function bill_changed(what) {
+ if ( what.form.same.checked ) {
+<%=
+ for (qw( last first company address1 address2 city zip daytime night fax )) {
+ $OUT .= "what.form.ship_$_.value = what.form.$_.value;";
+ }
+ '';
+%>
+ what.form.ship_country.selectedIndex = what.form.country.selectedIndex;
+
+ function fix_ship_county() {
+ what.form.ship_county.selectedIndex = what.form.county.selectedIndex;
+ }
+
+ function fix_ship_state() {
+ what.form.ship_state.selectedIndex = what.form.state.selectedIndex;
+ ship_state_changed(what.form.ship_state, fix_ship_county );
+ }
+
+ ship_country_changed(what.form.ship_country, fix_ship_state );
+
+ }
+}
+function samechanged(what) {
+ if ( what.checked ) {
+ bill_changed(what);
+
+<%=
+ for (qw( last first company address1 address2 city county state zip country daytime night fax )) {
+ $OUT .= "what.form.ship_$_.disabled = true;";
+ $OUT .= "what.form.ship_$_.style.backgroundColor = '#dddddd';";
+ }
+ if ( $require_address2 ) {
+ $OUT .= "document.getElementById('ship_address2_required').style.visibility = 'hidden';";
+ $OUT .= "document.getElementById('ship_address2_label').style.visibility = 'hidden';";
+ }
+%>
+
+ } else {
+
+<%=
+ for (qw( last first company address1 address2 city county state zip country daytime night fax )) {
+ $OUT .= "what.form.ship_$_.disabled = false;";
+ $OUT .= "what.form.ship_$_.style.backgroundColor = '#ffffff';";
+ }
+ if ( $require_address2 ) {
+ $OUT .= "document.getElementById('ship_address2_required').style.visibility = '';";
+ $OUT .= "document.getElementById('ship_address2_label').style.visibility = '';";
+ }
+%>
+ }
+}
+</SCRIPT>
+(<INPUT TYPE="checkbox" NAME="same" VALUE="Y" onClick="samechanged(this)"
+ <%= (!$ship_last || $cgi->param('same') eq 'Y') ? 'CHECKED' : '' %>
+ >same as billing address)
+<%= $r=qq!<font color="#ff0000">*</font>&nbsp;!;
+ if (!$ship_last || $cgi->param('same') eq 'Y') {
+ $disabled = 'DISABLED STYLE="background-color: #dddddd"';
+ foreach ( qw( last first company address1 address2 city county state
+ zip country daytime night fax )
+ ) {
+ ${"ship_$_"} = ${$_};
+ }
+ }else{
+ $disabled = '';
+ }
+ $pre = 'ship_';
+ include('contact');
+%>
+
+<INPUT TYPE="submit" NAME="submit" VALUE="<%= $custnum ? "Apply Changes" : "Add Customer" %>">
+<BR>
+</FORM>
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/check.html b/fs_selfservice/FS-SelfService/cgi/check.html
new file mode 100644
index 000000000..68753fe08
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/check.html
@@ -0,0 +1,54 @@
+<TR>
+ <TD ALIGN="right">Account&nbsp;type</TD>
+ <TD>
+ <SELECT NAME="paytype">
+ <%= foreach ( @paytypes ) {
+ $selected = $paytype eq $_ ? ' SELECTED' : '';
+ $OUT .= qq(<OPTION$selected VALUE="$_">$_\n);
+ } %>
+ </SELECT>
+ </TD>
+</TD><TR>
+ <TD ALIGN="right">Account&nbsp;number</TD>
+ <TD><INPUT TYPE="text" NAME="payinfo1" SIZE=10 MAXLENGTH=20 VALUE="<%=$payinfo1%>"></TD>
+</TD><TR>
+ <TD ALIGN="right">ABA/Routing&nbsp;number</TD>
+ <TD><INPUT TYPE="text" NAME="payinfo2" SIZE=10 MAXLENGTH=9 VALUE="<%=$payinfo2%>"></TD>
+</TR><TR>
+ <TD ALIGN="right">Bank&nbsp;name</TD>
+ <TD><INPUT TYPE="text" SIZE=32 MAXLENGTH=80 NAME="payname" VALUE="<%=$payname%>"></TD>
+</TR><TR>
+ <%=
+ $OUT = '';
+ if ($show_paystate) {
+ $OUT .= qq!<TD ALIGN="right">Bank state</TD><TD><SELECT NAME="paystate">!;
+ for ( @states ) {
+ $OUT .= '<OPTION'. ($_ eq $paystate ? ' SELECTED' : '' ). ">$_\n";
+ }
+ $OUT .= '</SELECT></TD></TR><TR>';
+ }
+ %>
+ <%=
+ $OUT = '';
+ if ($show_ss) {
+ $OUT .= '<TD ALIGN="right">Account&nbsp;holder<BR>Social&nbsp;';
+ $OUT .= 'security&nbsp;or&nbsp;tax&nbsp;ID&nbsp;#</TD><TD>';
+ $OUT .= qq!<INPUT TYPE="text" SIZE=32 MAXLENGTH=80 NAME="ss" VALUE="$ss">!;
+ $OUT .= '</TD></TR><TR>';
+ }
+ %>
+ <%=
+ $OUT = '';
+ if ($show_stateid) {
+ $OUT .= '<TD ALIGN="right">';
+ $OUT .= qq!Account&nbsp;holder<BR>$stateid_label</TD><TD>!;
+ $OUT .= qq!<INPUT TYPE="text" SIZE=32 MAXLENGTH=80 NAME="stateid" VALUE="$stateid"></TD>!;
+ $OUT .= qq!<TD ALIGN="right">$stateid_state_label</TD>!;
+ $OUT .= '<TD><SELECT NAME="stateid_state">';
+ for ( @states ) {
+ $OUT .= '<OPTION'. ($_ eq $stateid_state ? ' SELECTED' : '' ). ">$_\n";
+ }
+ $OUT .='</SELECT></TD></TR><TR>';
+ }
+ %>
+</TR>
diff --git a/fs_selfservice/FS-SelfService/cgi/contact.html b/fs_selfservice/FS-SelfService/cgi/contact.html
new file mode 100644
index 000000000..20c15df78
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/contact.html
@@ -0,0 +1,135 @@
+<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0>
+
+<TR>
+ <TH ALIGN="right"><%=$r%>Contact&nbsp;name<BR>(last,&nbsp;first)</TH>
+ <TD COLSPAN=5>
+ <INPUT TYPE="text" NAME="<%=$pre%>last" VALUE="<%= ${$pre.'last'} %>" onChange="<%= $onchange %>" <%=$disabled%>> ,
+ <INPUT TYPE="text" NAME="<%=$pre%>first" VALUE="<%= ${$pre.'first'} %>" onChange="<%= $onchange %>" <%=$disabled%>>
+ </TD>
+</TR>
+
+<TR>
+ <TD ALIGN="right">Company</TD>
+ <TD COLSPAN=7>
+ <INPUT TYPE="text" NAME="<%=$pre%>company" VALUE="<%= ${$pre.'company'} %>" SIZE=70 onChange="<%= $onchange %>" <%=$disabled%>>
+ </TD>
+</TR>
+
+<TR>
+ <TH ALIGN="right"><%=$r%>Address</TH>
+ <TD COLSPAN=7>
+ <INPUT TYPE="text" NAME="<%=$pre%>address1" VALUE="<%= ${$pre.'address1'} %>" SIZE=70 onChange="<%= $onchange %>" <%=$disabled%>>
+ </TD>
+</TR>
+
+<TR>
+ <TD ALIGN="right">
+ <%=
+ my $style =
+ ( $disabled
+ || !$require_address2
+ || ( !$pre && $ship_last )
+ )
+ ? 'visibility:hidden'
+ : '';
+
+ $OUT .= qq!<FONT ID="${pre}address2_required" color="#ff0000" STYLE="$style">*</FONT>&nbsp;<FONT ID="${pre}address2_label" STYLE="$style"><B>Unit&nbsp;#</B></FONT>!;
+ %>
+ </TD>
+ <TD COLSPAN=7>
+ <INPUT TYPE="text" NAME="<%=$pre%>address2" VALUE="<%= ${$pre.'address2'} %>" SIZE=70 onChange="<%= $onchange %>" <%=$disabled%>>
+ </TD>
+</TR>
+
+<TR>
+ <TH ALIGN="right"><%=$r%>City</TH>
+ <TD>
+ <INPUT TYPE="text" ID="<%=$pre%>city" NAME="<%=$pre%>city" VALUE="<%= ${$pre.'city'} %>" onChange="<%= $onchange %>" <%=$disabled%>>
+ </TD>
+ <%=
+ ($county_html, $state_html, $country_html) =
+ FS::SelfService::regionselector( {
+ prefix => $pre,
+ selected_county => ${$pre.'county'},
+ selected_state => ${$pre.'state'},
+ selected_country => ${$pre.'country'},
+ default_state => $statedefault,
+ default_country => $countrydefault,
+ locales => \@cust_main_county,
+ } );
+
+ $OUT .= qq!<TH ALIGN="right">${r}State/County</TH>!;
+ $OUT .= qq!<TD>$county_html $state_html</TD>!;
+ $OUT .= qq!<TH>${r}Zip</TH>!;
+ $OUT .= qq!<TD><INPUT TYPE="text" NAME="${pre}zip" VALUE="${$pre.'zip'}" SIZE=10 onChange="$onchange" $disabled></TD>!;
+ $OUT .= qq!</TR>!;
+ $OUT .= qq!<TR>!;
+ $OUT .= qq!<TH ALIGN="right">${r}Country</TH>!;
+ $OUT .= qq!<TD COLSPAN=5>$country_html</TD>!;
+ %>
+</TR>
+
+<SCRIPT>
+ <%=
+ if ( $disabled ) {
+ $OUT .= qq!var what = document.getElementById("${pre}city");!;
+ for (qw( county state country ) ) {
+ $OUT .= "what.form.$pre$_.disabled = true;";
+ $OUT .= "what.form.$pre$_.style.backgroundColor = '#dddddd';";
+ }
+ }else{
+ '';
+ }
+ %>
+</SCRIPT>
+
+<TR>
+ <TD ALIGN="right">Day Phone</TD>
+ <TD COLSPAN=5>
+ <INPUT TYPE="text" NAME="<%=$pre%>daytime" VALUE="<%= ${$pre.'daytime'} %>" SIZE=18 onChange="<%= $onchange %>" <%=$disabled%>>
+ </TD>
+</TR>
+
+<TR>
+ <TD ALIGN="right">Night Phone</TD>
+ <TD COLSPAN=5>
+ <INPUT TYPE="text" NAME="<%=$pre%>night" VALUE="<%= ${$pre.'night'} %>" SIZE=18 onChange="<%= $onchange %>" <%=$disabled%>>
+ </TD>
+</TR>
+
+<TR>
+ <TD ALIGN="right">Fax</TD>
+ <TD COLSPAN=5>
+ <INPUT TYPE="text" NAME="<%=$pre%>fax" VALUE="<%= ${$pre.'fax'} %>" SIZE=12 onChange="<%= $onchange %>" <%=$disabled%>>
+ </TD>
+</TR>
+
+</TABLE>
+<%=$r%>required fields<BR>
+
+<!--
+#my($county_html, $state_html, $country_html) =
+# FS::cust_main_county::regionselector( $cust_main->get($pre.'county'),
+# $cust_main->get($pre.'state'),
+# $cust_main->get($pre.'country'),
+# $pre,
+# $onchange,
+# $disabled,
+# );
+
+my %select_hash = (
+ 'county' => ${$pre.'county'},
+ 'state' => ${$pre.'state'},
+ 'country' => ${$pre.'country'},
+ 'prefix' => $pre,
+ 'onchange' => $onchange,
+ 'disabled' => $disabled,
+);
+
+my @counties = counties( ${$pre.'state'},
+ ${$pre.'country'},
+ );
+my $county_style = scalar(@counties) > 1 ? '' : 'STYLE="visibility:hidden"';
+
+my $r = qq!<font color="#ff0000">*</font>&nbsp;!;
+-->
diff --git a/fs_selfservice/FS-SelfService/cgi/cust_bill-logo.cgi b/fs_selfservice/FS-SelfService/cgi/cust_bill-logo.cgi
new file mode 100644
index 000000000..5f344a32e
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/cust_bill-logo.cgi
@@ -0,0 +1,19 @@
+#!/usr/bin/perl -T
+#!/usr/bin/perl -Tw
+
+use strict;
+use CGI;
+use FS::SelfService qw( invoice_logo );
+
+my $cgi = new CGI;
+
+my($query) = $cgi->keywords;
+$query =~ /^([^\.\/]*)$/ or '' =~ /^()$/;
+my $templatename = $1;
+my $hashref = invoice_logo('templatename' => $templatename);
+
+print $cgi->header( '-type' => $hashref->{'content_type'},
+ '-expires' => 'now',
+ ).
+ $hashref->{'logo'};
+
diff --git a/fs_selfservice/FS-SelfService/cgi/customer_change_pkg.html b/fs_selfservice/FS-SelfService/cgi/customer_change_pkg.html
new file mode 100644
index 000000000..46d3faf86
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/customer_change_pkg.html
@@ -0,0 +1,8 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+<%= include('change_pkg') %>
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/customer_order_pkg.html b/fs_selfservice/FS-SelfService/cgi/customer_order_pkg.html
new file mode 100755
index 000000000..78cc16c27
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/customer_order_pkg.html
@@ -0,0 +1,8 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+<%= include('order_pkg') %>
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/cvv2.html b/fs_selfservice/FS-SelfService/cgi/cvv2.html
new file mode 100644
index 000000000..b178c8513
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/cvv2.html
@@ -0,0 +1,25 @@
+<HTML>
+ <HEAD>
+ <TITLE>
+ CVV2 information
+ </TITLE>
+ </HEAD>
+ <BODY BGCOLOR="#e8e8e8">
+ The CVV2 number (also called CVC2 or CID) is a three- or four-digit
+ security code used to reduce credit card fraud.<BR><BR>
+ <TABLE BORDER=0 CELLSPACING=4>
+ <TR>
+ <TH>Visa / MasterCard / Discover</TH>
+ <TH>American Express</TH>
+ </TR>
+ <TR>
+ <TD>
+ <IMG BORDER=0 ALT="Visa/MasterCard/Discover" SRC="cvv2.png">
+ </TD>
+ <TD>
+ <IMG BORDER=0 ALT="American Express" SRC="cvv2_amex.png">
+ </TD>
+ </TABLE>
+ <CENTER><A HREF="javascript:close()">(close window)</A></CENTER>
+ </BODY>
+</HTML>
diff --git a/fs_selfservice/FS-SelfService/cgi/cvv2.png b/fs_selfservice/FS-SelfService/cgi/cvv2.png
new file mode 100644
index 000000000..4610dcbe6
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/cvv2.png
Binary files differ
diff --git a/fs_selfservice/FS-SelfService/cgi/cvv2_amex.png b/fs_selfservice/FS-SelfService/cgi/cvv2_amex.png
new file mode 100644
index 000000000..21c36a0ab
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/cvv2_amex.png
Binary files differ
diff --git a/fs_selfservice/FS-SelfService/cgi/decline.html b/fs_selfservice/FS-SelfService/cgi/decline.html
new file mode 100644
index 000000000..a37ba3ab6
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/decline.html
@@ -0,0 +1,5 @@
+<HTML><HEAD><TITLE>Processing error</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=7>Processing error</FONT><BR><BR>
+There has been an error processing your account. Please contact customer
+support.
+</BODY></HTML>
diff --git a/fs_selfservice/FS-SelfService/cgi/delete_svc.html b/fs_selfservice/FS-SelfService/cgi/delete_svc.html
new file mode 100644
index 000000000..4155d09cf
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/delete_svc.html
@@ -0,0 +1,14 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+
+<%= if ( $error ) {
+ $OUT .= qq!<FONT SIZE="+1" COLOR="#ff0000">Error: $error</FONT>!;
+} else {
+ $OUT .= "<FONT SIZE=4>$svc removed.</FONT>";
+} %>
+
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/footer.html b/fs_selfservice/FS-SelfService/cgi/footer.html
new file mode 100644
index 000000000..98cc79b74
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/footer.html
@@ -0,0 +1,3 @@
+<HR>
+<FONT SIZE="-2">powered by <a href="http://www.freeside.biz/freeside">freeside</a></FONT>
+</BODY></HTML>
diff --git a/fs_selfservice/FS-SelfService/cgi/images/cross.png b/fs_selfservice/FS-SelfService/cgi/images/cross.png
new file mode 100644
index 000000000..1514d51a3
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/images/cross.png
Binary files differ
diff --git a/fs_selfservice/FS-SelfService/cgi/images/wait-orange.gif b/fs_selfservice/FS-SelfService/cgi/images/wait-orange.gif
new file mode 100644
index 000000000..92c7f3476
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/images/wait-orange.gif
Binary files differ
diff --git a/fs_selfservice/FS-SelfService/cgi/list_customers.html b/fs_selfservice/FS-SelfService/cgi/list_customers.html
new file mode 100644
index 000000000..7fe7fa493
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/list_customers.html
@@ -0,0 +1,36 @@
+<HTML><HEAD><TITLE>Reseller</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>Reseller</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<TABLE BORDER=0 CELLPADDING=4><TR>
+<%= include('agent_menu') %>
+<TD VALIGN="top">
+
+<%=
+ if ( @customers ) {
+ $OUT .= '<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=2 BGCOLOR="#eeeeee">'.
+ '<TR><TH BGCOLOR="#cccccc" COLSPAN=3>Customers</TH><TD>';
+ my $col1 = "ffffff";
+ my $col2 = "dddddd";
+ my $col = $col1;
+
+ foreach my $customer ( @customers ) {
+ my $td = qq!<TD BGCOLOR="#$col">!;
+ my $a = qq!<A HREF="${url}view_customer;custnum=!.
+ $customer->{'custnum'}. '">';
+ $OUT .=
+ '<TR>'.
+ "$td<FONT COLOR=\"". $customer->{'statuscolor'}. '">'.
+ ucfirst($customer->{'status'}). "</TD>". "$td</TD>".
+ "$td$a". $customer->{'name'}. "</A></TD>".
+ '</TR>';
+ #"$td</TD>".
+ $col = $col eq $col1 ? $col2 : $col1;
+ }
+ $OUT .= '</TABLE>';
+ } else {
+ $OUT .= 'No customers.<BR><BR>';
+ }
+%>
+
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/login.html b/fs_selfservice/FS-SelfService/cgi/login.html
new file mode 100644
index 000000000..e5daec859
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/login.html
@@ -0,0 +1,85 @@
+<HTML><HEAD><TITLE>Login</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=5>Login</FONT><BR><BR>
+<FONT SIZE="+1" COLOR="#ff0000"><%= $error %></FONT>
+
+<FORM ACTION="<%= $self_url %>" METHOD=POST>
+<INPUT TYPE="hidden" NAME="session" VALUE="login">
+
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=2 CELLPADDING=0>
+
+<TR>
+ <TH ALIGN="right">Username </TH>
+ <TD>
+ <INPUT TYPE="text" NAME="username" VALUE="<%= $username %>"><%= $single_domain ? '@'.$single_domain : '' %>
+ </TD>
+</TR>
+
+<%=
+if ( $single_domain ) {
+
+ $OUT .= qq(<INPUT TYPE="hidden" NAME="domain" VALUE="$single_domain">);
+
+} else {
+
+ $OUT .= qq(
+ <TR>
+ <TH ALIGN="right">Domain </TH>
+ <TD>
+ <INPUT TYPE="text" NAME="domain" VALUE="$domain">
+ </TD>
+ </TR>
+ );
+
+}
+
+%>
+
+<TR>
+ <TH ALIGN="right">Password </TH>
+ <TD>
+ <INPUT TYPE="password" NAME="password">
+ </TD>
+</TR>
+<TR>
+ <TD COLSPAN=2 ALIGN="center"><INPUT TYPE="submit" VALUE="Login"></TD>
+</TR>
+</TABLE>
+</FORM>
+
+<%=
+
+if ( $phone_login ) {
+
+ $OUT .= qq(
+
+ <B>OR</B><BR><BR>
+
+ <FORM ACTION="$self_url" METHOD=POST>
+ <INPUT TYPE="hidden" NAME="session" VALUE="login">
+ <TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=2 CELLPADDING=0>
+ <TR>
+ <TH ALIGN="right">Phone number </TH>
+ <TD>
+ <INPUT TYPE="text" NAME="username" VALUE="$username">
+ </TD>
+ </TR>
+ <INPUT TYPE="hidden" NAME="domain" VALUE="svc_phone">
+ <TR>
+ <TH ALIGN="right">PIN </TH>
+ <TD>
+ <INPUT TYPE="password" NAME="password">
+ </TD>
+ </TR>
+ <TR>
+ <TD COLSPAN=2 ALIGN="center"><INPUT TYPE="submit" VALUE="Login"></TD>
+ </TR>
+ </TABLE>
+ </FORM>
+
+ );
+
+}
+
+%>
+
+</BODY></HTML>
diff --git a/fs_selfservice/FS-SelfService/cgi/logout.html b/fs_selfservice/FS-SelfService/cgi/logout.html
new file mode 100644
index 000000000..0e774e9eb
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/logout.html
@@ -0,0 +1,5 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+You have been logged out.
+</BODY></HTML>
+
diff --git a/fs_selfservice/FS-SelfService/cgi/make_ach_payment.html b/fs_selfservice/FS-SelfService/cgi/make_ach_payment.html
new file mode 100644
index 000000000..2394c10d4
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/make_ach_payment.html
@@ -0,0 +1,58 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee">
+<script language="JavaScript"><!--
+ var mywindow = -1;
+ function myopen(filename,windowname,properties) {
+ myclose();
+ mywindow = window.open(filename,windowname,properties);
+ }
+ function myclose() {
+ if ( mywindow != -1 )
+ mywindow.close();
+ mywindow = -1
+ }
+//--></script>
+<FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+<FONT SIZE=4>Make a payment</FONT><BR><BR>
+<FORM NAME="OneTrueForm" METHOD="POST" ACTION="<%=$selfurl%>" onSubmit="document.OneTrueForm.process.disabled=true">
+<INPUT TYPE="hidden" NAME="session" VALUE="<%=$session_id%>">
+<INPUT TYPE="hidden" NAME="action" VALUE="ach_payment_results">
+<TABLE BGCOLOR="#cccccc">
+<TR>
+ <TD ALIGN="right">Amount&nbsp;Due</TD>
+ <TD>
+ <TABLE><TR><TD BGCOLOR="#ffffff">
+ $<%=sprintf("%.2f",$balance)%>
+ </TD></TR></TABLE>
+ </TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Payment&nbsp;amount</TD>
+ <TD>
+ <TABLE><TR><TD BGCOLOR="#ffffff">
+ $<INPUT TYPE="text" NAME="amount" SIZE=8 VALUE="<%=sprintf("%.2f",$balance)%>">
+ </TD></TR></TABLE>
+ </TD>
+</TR>
+<%= include('check') %>
+<TR>
+ <TD COLSPAN=2>
+ <INPUT TYPE="checkbox" CHECKED NAME="save" VALUE="1">
+ Remember this information
+ </TD>
+</TR><TR>
+ <TD COLSPAN=2>
+ <INPUT TYPE="checkbox"<%= $payby eq 'CHEK' ? ' CHECKED' : '' %> NAME="auto" VALUE="1" onClick="if (this.checked) { document.OneTrueForm.save.checked=true; }">
+ Charge future payments to this account automatically
+ </TD>
+</TR>
+</TABLE>
+<BR>
+<INPUT TYPE="hidden" NAME="paybatch" VALUE="<%=$paybatch%>">
+<INPUT TYPE="submit" NAME="process" VALUE="Process payment"> <!-- onClick="this.disabled=true"> -->
+</FORM>
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/make_payment.html b/fs_selfservice/FS-SelfService/cgi/make_payment.html
new file mode 100644
index 000000000..a468d998a
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/make_payment.html
@@ -0,0 +1,68 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee">
+<script language="JavaScript"><!--
+ var mywindow = -1;
+ function myopen(filename,windowname,properties) {
+ myclose();
+ mywindow = window.open(filename,windowname,properties);
+ }
+ function myclose() {
+ if ( mywindow != -1 )
+ mywindow.close();
+ mywindow = -1
+ }
+//--></script>
+<FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+<FONT SIZE=4>Make a payment</FONT><BR><BR>
+<FORM NAME="OneTrueForm" METHOD="POST" ACTION="<%=$selfurl%>" onSubmit="document.OneTrueForm.process.disabled=true">
+<INPUT TYPE="hidden" NAME="session" VALUE="<%=$session_id%>">
+<INPUT TYPE="hidden" NAME="action" VALUE="payment_results">
+<TABLE BGCOLOR="#cccccc">
+<TR>
+ <TD ALIGN="right">Amount&nbsp;Due</TD>
+ <TD>
+ <TABLE><TR><TD BGCOLOR="#ffffff">
+ $<%=sprintf("%.2f",$balance)%>
+ </TD></TR></TABLE>
+ </TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Payment&nbsp;amount</TD>
+ <TD>
+ <TABLE><TR><TD BGCOLOR="#ffffff">
+ $<INPUT TYPE="text" NAME="amount" SIZE=8 VALUE="<%=sprintf("%.2f",$balance)%>">
+ </TD></TR></TABLE>
+ </TD>
+</TR><TR>
+ <TD ALIGN="right">Card&nbsp;type</TD>
+ <TD>
+ <SELECT NAME="card_type"><OPTION></OPTION>
+ <%= foreach ( keys %card_types ) {
+ $selected = $card_type eq $card_types{$_} ? ' SELECTED' : '';
+ $OUT .= qq(<OPTION$selected VALUE="). $card_types{$_}. qq(">$_\n);
+ } %>
+ </SELECT>
+ </TD>
+</TR>
+<%= include('card') %>
+<TR>
+ <TD COLSPAN=2>
+ <INPUT TYPE="checkbox" CHECKED NAME="save" VALUE="1">
+ Remember this information
+ </TD>
+</TR><TR>
+ <TD COLSPAN=2>
+ <INPUT TYPE="checkbox"<%= $payby eq 'CARD' ? ' CHECKED' : '' %> NAME="auto" VALUE="1" onClick="if (this.checked) { document.OneTrueForm.save.checked=true; }">
+ Charge future payments to this card automatically
+ </TD>
+</TR>
+</TABLE>
+<BR>
+<INPUT TYPE="hidden" NAME="paybatch" VALUE="<%=$paybatch%>">
+<INPUT TYPE="submit" NAME="process" VALUE="Process payment"> <!-- onClick="this.disabled=true"> -->
+</FORM>
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/map.gif b/fs_selfservice/FS-SelfService/cgi/map.gif
new file mode 100644
index 000000000..ef884d8f9
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/map.gif
Binary files differ
diff --git a/fs_selfservice/FS-SelfService/cgi/misc/areacodes.cgi b/fs_selfservice/FS-SelfService/cgi/misc/areacodes.cgi
new file mode 100755
index 000000000..b33e58c5a
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/misc/areacodes.cgi
@@ -0,0 +1,18 @@
+#!/usr/bin/perl -w
+
+use strict;
+use CGI;
+use FS::SelfService qw( mason_comp );
+
+my $cgi = new CGI;
+
+my $rv = mason_comp( 'comp' => '/misc/areacodes.cgi',
+ 'query_string' => $cgi->query_string, #pass CGI params...
+ );
+
+#hmm.
+my $output = $rv->{'error'} || $rv->{'output'};
+
+print $cgi->header( '-expires' => 'now' ).
+ $output;
+
diff --git a/fs_selfservice/FS-SelfService/cgi/misc/exchanges.cgi b/fs_selfservice/FS-SelfService/cgi/misc/exchanges.cgi
new file mode 100755
index 000000000..d8df970d9
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/misc/exchanges.cgi
@@ -0,0 +1,18 @@
+#!/usr/bin/perl -w
+
+use strict;
+use CGI;
+use FS::SelfService qw( mason_comp );
+
+my $cgi = new CGI;
+
+my $rv = mason_comp( 'comp' => '/misc/exchanges.cgi',
+ 'query_string' => $cgi->query_string, #pass CGI params...
+ );
+
+#hmm.
+my $output = $rv->{'error'} || $rv->{'output'};
+
+print $cgi->header( '-expires' => 'now' ).
+ $output;
+
diff --git a/fs_selfservice/FS-SelfService/cgi/misc/phonenums.cgi b/fs_selfservice/FS-SelfService/cgi/misc/phonenums.cgi
new file mode 100755
index 000000000..e7d695d07
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/misc/phonenums.cgi
@@ -0,0 +1,18 @@
+#!/usr/bin/perl -w
+
+use strict;
+use CGI;
+use FS::SelfService qw( mason_comp );
+
+my $cgi = new CGI;
+
+my $rv = mason_comp( 'comp' => '/misc/phonenums.cgi',
+ 'query_string' => $cgi->query_string, #pass CGI params...
+ );
+
+#hmm.
+my $output = $rv->{'error'} || $rv->{'output'};
+
+print $cgi->header( '-expires' => 'now' ).
+ $output;
+
diff --git a/fs_selfservice/FS-SelfService/cgi/myaccount.html b/fs_selfservice/FS-SelfService/cgi/myaccount.html
new file mode 100644
index 000000000..cb5ed352e
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/myaccount.html
@@ -0,0 +1,94 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+
+Hello <%= $name %>!<BR><BR>
+<%= $small_custview %>
+<BR>
+<%= if ( $balance > 0 ) {
+ $OUT .= qq! <B><A HREF="${url}make_payment">Make a payment</A></B><BR><BR>!;
+} %>
+<%=
+ if ( @open_invoices ) {
+ $OUT .= '<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=2 BGCOLOR="#eeeeee">'.
+ '<TR><TH BGCOLOR="#ff6666" COLSPAN=5>Open Invoices</TH></TR>';
+ my $link = qq!<A HREF="<%= $url %>myaccount!;
+ my $col1 = "ffffff";
+ my $col2 = "dddddd";
+ my $col = $col1;
+
+ foreach my $invoice ( @open_invoices ) {
+ my $td = qq!<TD BGCOLOR="#$col">!;
+ my $a=qq!<A HREF="${url}view_invoice;invnum=!. $invoice->{'invnum'}. '">';
+ $OUT .=
+ "<TR>$td${a}Invoice #". $invoice->{'invnum'}. "</A></TD>$td</TD>".
+ "$td$a". $invoice->{'date'}. "</A></TD>$td</TD>".
+ qq!<TD BGCOLOR="#$col" ALIGN="right">$a\$!. $invoice->{'owed'}.
+ '</A></TD>'.
+ '</TR>';
+ $col = $col eq $col1 ? $col2 : $col1;
+ }
+ $OUT .= '</TABLE><BR>';
+ } else {
+ $OUT .= 'You have no outstanding invoices.<BR><BR>';
+ }
+%>
+
+<%=
+ if ( @support_services ) {
+ $OUT .= '<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=2 BGCOLOR="#eeeeee">'.
+ '<TR><TH BGCOLOR="#ff6666" COLSPAN="3">Support Time Remaining</TH>'.
+ '</TR><TR><TH ALIGN="left">#</TH><TH>Package</TH>'.
+ '<TH>Time Remaining</TH></TR>';
+ my $col1 = "ffffff";
+ my $col2 = "dddddd";
+ my $col = $col1;
+
+ foreach my $support ( @support_services ) {
+ my $td = qq!<TD BGCOLOR="#$col">!;
+ my $a = qq!<A HREF="${url}view_support_details;svcnum=!.
+ $support->{'svcnum'}. '">';
+ $OUT .=
+ "<TR>$td$a". $support->{'pkgnum'}. "</A></TD>".
+ $td.$a. $support->{'pkg'}. "</A></TD>".
+ $td.$a. $support->{'time'}. "</A></TD>".
+ '</TR>';
+ $col = $col eq $col1 ? $col2 : $col1;
+ }
+ $OUT .= '</TABLE><BR>';
+ } else {
+ $OUT .= '';
+ }
+%>
+
+<%=
+ if ( @tickets ) {
+ $OUT .= '<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=2 BGCOLOR="#eeeeee">'.
+ '<TR><TH BGCOLOR="#ff6666" COLSPAN=5>Open Tickets</TH></TR>'.
+ '<TR><TH>#</TH><TH>Subject</TH><TH>Priority</TH><TH>Queue</TH>'.
+ '<TH>Status</TH></TR>';
+ my $col1 = "ffffff";
+ my $col2 = "dddddd";
+ my $col = $col1;
+
+ foreach my $ticket ( @tickets ) {
+ my $td = qq!<TD BGCOLOR="#$col">!;
+ $OUT .=
+ "<TR>$td". $ticket->{'id'}. "</TD>".
+ $td. $ticket->{'subject'}. "</TD>".
+ $td. ($ticket->{'content'} || $ticket->{'priority'}). "</TD>".
+ $td. $ticket->{'queue'}. "</TD>".
+ $td. $ticket->{'status'}. "</TD>".
+ '</TR>';
+ $col = $col eq $col1 ? $col2 : $col1;
+ }
+ $OUT .= '</TABLE>';
+ } else {
+ $OUT .= '';
+ }
+%>
+
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html b/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html
new file mode 100644
index 000000000..ec5a8fa42
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/myaccount_menu.html
@@ -0,0 +1,94 @@
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<TABLE BORDER=0><TR>
+<TD VALIGN="top" HEIGHT="100%" BGCOLOR="#dddddd">
+
+<TABLE CELLSPACING=0 BORDER=0 HEIGHT="100%">
+
+<%=
+
+my @menu = (
+{ title=>' ' },
+{ title=>'Overview', url=>'myaccount', size=>'+1', },
+{ title=>' ' },
+
+{ title=>'Purchase', size=>'+1', },
+ { title=>'Purchase additional package',
+ url=>'customer_order_pkg', 'indent'=>2 },
+);
+
+if ( 1 ) { #XXXFIXME "enable selfservice prepay features" flag or something, eventually per-pkg or something really fancy
+
+ push @menu, (
+ { title=>'Recharge my account with a credit card',
+ url=>'make_payment', indent=>2 },
+ { title=>'Recharge my account with a check',
+ url=>'make_ach_payment', indent=>2 },
+ { title=>'Recharge my account with a prepaid card',
+ url=>'recharge_prepay', indent=>2 },
+ );
+
+}
+
+push @menu, (
+
+{ title=>' ' },
+
+{ title=>'View my usage', url=>'view_usage', size=>'+1', },
+{ title=>'Setup my services', url=>'provision', size=>'+1', },
+
+{ title=>' ' },
+
+{ title=>'Change my information', size=>'+1', },
+ { title=>'Change billing address', url=>'change_bill', indent=>2 },
+ { title=>'Change service address', url=>'change_ship', indent=>2 },
+ { title=>'Change payment information', url=>'change_pay', indent=>2 },
+ { title=>'Change password(s)', url=>'change_password', indent=>2 },
+
+{ title=>' ' },
+
+{ title=>'Logout', url=>'logout', size=>'+1', },
+
+);
+
+foreach my $item ( @menu ) {
+
+ $OUT .= '<TR><TD';
+ if ( exists $item->{'url'} && $action eq $item->{'url'} ) {
+ $OUT .= ' BGCOLOR="#eeeeee" '.
+ ' STYLE="border-top: 1px solid black;'.
+ ' border-left: 1px solid black;'.
+ ' border-bottom: 1px solid black"';
+ } else {
+ $OUT .= ' STYLE="border-right: 1px solid black"';
+ }
+ $OUT.='>';
+
+ $OUT .= '<FONT SIZE="'. $item->{'size'}. '">'
+ if exists $item->{'size'};
+
+ $OUT .= '&nbsp;' x $item->{'indent'}
+ if exists $item->{'indent'};
+
+ $OUT .= '<A HREF="'. $url. $item->{'url'}. '">'
+ if exists $item->{'url'} && $action ne $item->{'url'};
+
+ $item->{'title'} =~ s/ /&nbsp;/g;
+ $OUT .= $item->{'title'};
+
+ $OUT .= '</FONT>'
+ if exists $item->{'size'};
+
+ $OUT .= '</A>'
+ if exists $item->{'url'} && $action ne $item->{'url'};
+
+ $OUT .= '</TD></TR>';
+
+}
+
+%>
+
+<TR><TD STYLE="border-right: 1px solid black" HEIGHT="100%"><BR><BR><BR><BR></TD></TR>
+
+</TABLE>
+
+</TD>
diff --git a/fs_selfservice/FS-SelfService/cgi/order_pkg.html b/fs_selfservice/FS-SelfService/cgi/order_pkg.html
new file mode 100644
index 000000000..9cdd4cd6c
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/order_pkg.html
@@ -0,0 +1,75 @@
+<SCRIPT TYPE="text/javascript">
+function enable_order_pkg () {
+ if ( document.OrderPkgForm.pkgpart.selectedIndex > 0 ) {
+ document.OrderPkgForm.submit.disabled = false;
+ } else {
+ document.OrderPkgForm.submit.disabled = true;
+ }
+}
+</SCRIPT>
+<FONT SIZE=4>Purchase additional package</FONT><BR><BR>
+<%= if ( $error ) {
+ $OUT .= qq!<FONT SIZE="+1" COLOR="#ff0000">$error</FONT><BR><BR>!;
+} ''; %>
+<FORM NAME="OrderPkgForm" ACTION="<%= $selfurl %>" METHOD=POST>
+<INPUT TYPE="hidden" NAME="session" VALUE="<%= $session_id %>">
+<INPUT TYPE="hidden" NAME="action" VALUE="process_order_pkg">
+<INPUT TYPE="hidden" NAME="custnum" VALUE="<%= $custnum %>">
+<TABLE BGCOLOR="#cccccc" BORDER=0 CELLSPACING=0>
+<TR>
+ <TD COLSPAN=2><SELECT NAME="pkgpart" onChange="enable_order_pkg()">
+ <OPTION VALUE="">
+
+ <%=
+ foreach my $part_pkg ( @part_pkg ) {
+ $OUT .= '<OPTION VALUE="'. $part_pkg->{'pkgpart'}. '"';
+ $OUT .= ' SELECTED' if $pkgpart && $part_pkg->{'pkgpart'} == $pkgpart;
+ $OUT .= '>'. $part_pkg->{'pkg'};
+ }
+ %>
+
+ </SELECT></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Username</TD>
+ <TD><INPUT TYPE="text" NAME="username" VALUE="<%= $username %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password" VALUE="<%= $_password %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Re-enter Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password2" VALUE="<%= $_password2 %>"></TD>
+</TR>
+<%=
+ if ( $security_phrase ) {
+ $OUT .= <<ENDOUT;
+<TR>
+ <TD ALIGN="right">Security Phrase</TD>
+ <TD><INPUT TYPE="text" NAME="sec_phrase" VALUE="$sec_phrase">
+ </TD>
+</TR>
+ENDOUT
+ } else {
+ $OUT .= '<INPUT TYPE="hidden" NAME="sec_phrase" VALUE="">';
+ }
+%>
+<%=
+ if ( @svc_acct_pop ) {
+ $OUT .= '<TR><TD ALIGN="right">Access number</TD><TD>'.
+ popselector( 'popnum' => $popnum,
+ 'pops' => \@svc_acct_pop,
+ 'init_popstate' => $init_popstate,
+ 'popac' => $popac,
+ 'acstate' => $acstate,
+ ).
+ '</TD></TR>';
+ } else {
+ $OUT .= popselector(popnum=>$popnum, pops=>\@svc_acct_pop);
+ }
+%>
+</TABLE>
+<INPUT NAME="submit" TYPE="submit" VALUE="Purchase" disabled>
+</FORM>
+
diff --git a/fs_selfservice/FS-SelfService/cgi/passwd.cgi b/fs_selfservice/FS-SelfService/cgi/passwd.cgi
new file mode 100755
index 000000000..87e5e6843
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/passwd.cgi
@@ -0,0 +1,61 @@
+#!/usr/bin/perl -T
+#!/usr/bin/perl -Tw
+
+use strict;
+use Getopt::Std;
+use FS::SelfService qw(passwd);
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
+
+my $freeside_uid = scalar(getpwnam('freeside'));
+
+$ENV{'PATH'} ='/usr/local/bin:/usr/bin:/usr/ucb:/bin';
+$ENV{'SHELL'} = '/bin/sh';
+$ENV{'IFS'} = " \t\n";
+$ENV{'CDPATH'} = '';
+$ENV{'ENV'} = '';
+$ENV{'BASH_ENV'} = '';
+
+die "passwd.cgi isn't running as freeside user\n" if $> != $freeside_uid;
+
+my $cgi = new CGI;
+
+$cgi->param('username') =~ /^([^\n]{0,255}$)/ or die "Illegal username";
+my $me = $1;
+
+$cgi->param('domain') =~ /^([^\n]{0,255}$)/ or die "Illegal domain";
+my $domain = $1;
+
+$cgi->param('old_password') =~ /^([^\n]{0,255}$)/ or die "Illegal old_password";
+my $old_password = $1;
+
+$cgi->param('new_password') =~ /^([^\n]{0,255}$)/ or die "Illegal new_password";
+my $new_password = $1;
+
+die "New passwords don't match"
+ unless $new_password eq $cgi->param('new_password2');
+
+my $rv = passwd(
+ 'username' => $me,
+ 'domain' => $domain,
+ 'old_password' => $old_password,
+ 'new_password' => $new_password,
+);
+
+my $error = $rv->{error};
+
+if ($error) {
+ die $error;
+} else {
+ print $cgi->header(), <<END;
+<html>
+ <head>
+ <title>Password changed</title>
+ </head>
+ <body bgcolor="#e8e8e8">
+ <h3>Password changed</h3>
+<br>Your password has been changed.
+ </body>
+</html>
+END
+}
diff --git a/fs_selfservice/FS-SelfService/cgi/passwd.html b/fs_selfservice/FS-SelfService/cgi/passwd.html
new file mode 100644
index 000000000..459c96aa8
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/passwd.html
@@ -0,0 +1,28 @@
+<html>
+ <head>
+ <title>Change password</title>
+ </head>
+ <body bgcolor="#e8e8e8">
+ <h3>Change password</h3>
+ <form action="passwd.cgi" method="post">
+ <table bgcolor="#cccccc" border=0 cellspacing=2>
+ <tr><th align="right">Username</th>
+ <td><input type="text" name="username" size="18"></td>
+ </tr>
+ <tr><th align="right">Domain</th>
+ <td><input type="text" name="domain" size="18"></td>
+ </tr>
+ <tr><th align="right">Current password</th>
+ <td><input type="password" name="old_password" size="18"></td>
+ </tr>
+ <tr><th align="right">New password</th>
+ <td><input type="password" name="new_password" size="18"></td>
+ </tr>
+ <tr><th align="right">Re-enter new password</th>
+ <td><input type="password" name="new_password2" size="18"></td>
+ </tr>
+ </table>
+ <br><input type="submit" value="Change password">
+ </body>
+</html>
+
diff --git a/fs_selfservice/FS-SelfService/cgi/payment_results.html b/fs_selfservice/FS-SelfService/cgi/payment_results.html
new file mode 100644
index 000000000..62419d152
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/payment_results.html
@@ -0,0 +1,13 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+<FONT SIZE=4>Payment results</FONT><BR><BR>
+<%= if ( $error ) {
+ $OUT .= qq!<FONT SIZE="+1" COLOR="#ff0000">Error processing your payment: $error</FONT>!;
+} else {
+ $OUT .= 'Your payment was processed successfully. Thank you.';
+} %>
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/process_change_bill.html b/fs_selfservice/FS-SelfService/cgi/process_change_bill.html
new file mode 100644
index 000000000..93e05cf7f
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/process_change_bill.html
@@ -0,0 +1,10 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+
+<FONT SIZE=4>Information updated successfully.</FONT>
+
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/process_change_password.html b/fs_selfservice/FS-SelfService/cgi/process_change_password.html
new file mode 100644
index 000000000..bfd23127c
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/process_change_password.html
@@ -0,0 +1,10 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+
+<FONT SIZE=4>Password changed for <%= $value %> <%= $label %>.</FONT>
+
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/process_change_pay.html b/fs_selfservice/FS-SelfService/cgi/process_change_pay.html
new file mode 100644
index 000000000..93e05cf7f
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/process_change_pay.html
@@ -0,0 +1,10 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+
+<FONT SIZE=4>Information updated successfully.</FONT>
+
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/process_change_pkg.html b/fs_selfservice/FS-SelfService/cgi/process_change_pkg.html
new file mode 100644
index 000000000..7c0f0a6ca
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/process_change_pkg.html
@@ -0,0 +1,10 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+
+<FONT SIZE=4>Package change successful.</FONT>
+
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/process_change_ship.html b/fs_selfservice/FS-SelfService/cgi/process_change_ship.html
new file mode 100644
index 000000000..93e05cf7f
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/process_change_ship.html
@@ -0,0 +1,10 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+
+<FONT SIZE=4>Information updated successfully.</FONT>
+
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/process_order_pkg.html b/fs_selfservice/FS-SelfService/cgi/process_order_pkg.html
new file mode 100755
index 000000000..3e4471d33
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/process_order_pkg.html
@@ -0,0 +1,10 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+
+<FONT SIZE=4>Package order successful.</FONT>
+
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/process_order_recharge.html b/fs_selfservice/FS-SelfService/cgi/process_order_recharge.html
new file mode 100644
index 000000000..ef0516ac9
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/process_order_recharge.html
@@ -0,0 +1,10 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+
+<FONT SIZE=4><%= $svc %> recharged successfully.</FONT>
+
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/process_svc_acct.html b/fs_selfservice/FS-SelfService/cgi/process_svc_acct.html
new file mode 100644
index 000000000..813521fda
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/process_svc_acct.html
@@ -0,0 +1,10 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+
+<FONT SIZE=4><%= $svc %> setup successfully.</FONT>
+
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/process_svc_external.html b/fs_selfservice/FS-SelfService/cgi/process_svc_external.html
new file mode 100644
index 000000000..1d2937b3e
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/process_svc_external.html
@@ -0,0 +1,12 @@
+<HTML><HEAD><TITLE><%= $error ? 'MyAccount' : sprintf("Your serial number is %010d-$title", $id) %></TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+
+<FONT SIZE=4><%= $svc %> setup successfully.</FONT>
+
+<BR><BR>Your serial number is <%= sprintf("%010d-$title", $id) %>
+
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/promocode.html b/fs_selfservice/FS-SelfService/cgi/promocode.html
new file mode 100644
index 000000000..f8ee7f6eb
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/promocode.html
@@ -0,0 +1,14 @@
+<HTML><HEAD><TITLE>ISP Signup</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=7>ISP Signup - promotional code</FONT><BR><BR>
+<SCRIPT>
+function gotoURL(object) {
+ window.location.href = 'signup.cgi?promo_code=' + object.promo_code.value;
+}
+</SCRIPT>
+<FORM>
+Enter promotional code <INPUT TYPE="text" NAME="promo_code">
+<INPUT type="submit" VALUE="Signup" onClick="gotoURL(this.form)">
+
+</FORM>
+</BODY>
+</HTML>
diff --git a/fs_selfservice/FS-SelfService/cgi/provision.html b/fs_selfservice/FS-SelfService/cgi/provision.html
new file mode 100644
index 000000000..5ae7b42b7
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/provision.html
@@ -0,0 +1,8 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+<%= include('provision_list') %>
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/provision_list.html b/fs_selfservice/FS-SelfService/cgi/provision_list.html
new file mode 100644
index 000000000..88d1c848b
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/provision_list.html
@@ -0,0 +1,92 @@
+<FONT SIZE=4>Setup services</FONT><BR><BR>
+
+<SCRIPT>
+function areyousure(href, message) {
+ if (confirm(message) == true)
+ window.location.href = href;
+}
+</SCRIPT>
+
+<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=2 BGCOLOR="#ffffff">
+
+<%= foreach my $pkg (
+ grep { scalar(@{$_->{part_svc}})
+ || scalar(@{$_->{cust_svc}})
+ } @cust_pkg
+ ) {
+
+ $OUT .= #'<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=2 BGCOLOR="#ffffff">'.
+ '<TR><TH BGCOLOR="#6666ff" COLSPAN=2>'.
+ $pkg->{'pkg'}. '</TH><TH BGCOLOR="#6666ff" >' .
+ qq!(<A style="font-size: smaller;color: #000000" HREF="! .
+ qq!${url}customer_change_pkg;pkgnum=$pkg->{'pkgnum'};pkg=$pkg->{'pkg'}">! .
+ 'change</A>)</TH></TR>';
+
+ my $col1 = "ffffff";
+ my $col2 = "dddddd";
+ my $col = $col1;
+
+ foreach my $cust_svc ( @{ $pkg->{cust_svc} } ) {
+ my $td = qq!<TD BGCOLOR="#$col"!;
+
+ $OUT .= '<TR>'.
+ "$td ALIGN=right>". $cust_svc->{label}[0]. ': </TD>'.
+ "$td><B>". $cust_svc->{label}[1]. '</B>';
+ $OUT .= '<BR><I>password: '. encode_entities($cust_svc->{_password}). '</I>'
+ if exists($cust_svc->{_password});
+ $OUT .= '</TD>'.
+ "$td><FONT SIZE=-1>";
+
+ #if ( $cust_svc->{label}[2] eq 'svc_acct' ) {
+ # $OUT .= qq!(<A HREF="${url}changepw;svcnum=$cust_svc->{'svcnum'}">!.
+ # 'change&nbsp;pw) ';
+ #}
+
+ unless ( $cust_svc->{'svcnum'} == $svcnum ) {
+ $OUT .= qq!(<A HREF="javascript:areyousure('${url}delete_svc;svcnum=$cust_svc->{svcnum}', 'This will permanently delete the $cust_svc->{label}[1] $cust_svc->{label}[0]. Are you sure?')">!.
+ 'delete</A>)';
+
+ }
+ $OUT .= '</FONT></TD></TR>';
+ $col = $col eq $col1 ? $col2 : $col1;
+ }
+
+ $OUT .= '<TR><TD COLSPAN=3 BGCOLOR="#000000"></TD></TR>'
+ if scalar(@{$pkg->{part_svc}}) && scalar(@{$pkg->{cust_svc}});
+
+ $col = $col1;
+
+ foreach my $part_svc ( @{ $pkg->{part_svc} } ) {
+
+ my $td = qq!<TD BGCOLOR="#$col"!;
+
+ my $link;
+
+ if ( $part_svc->{'svcdb'} eq 'svc_external'
+ #&& $conf->exists('svc_external-skip_manual')
+ ) {
+ $link = "${url}process_svc_external;".
+ "pkgnum=$pkg->{'pkgnum'};".
+ "svcpart=$part_svc->{'svcpart'}";
+ } else {
+ $link = "${url}provision_svc;".
+ "pkgnum=$pkg->{'pkgnum'};".
+ "svcpart=$part_svc->{'svcpart'}";
+ }
+
+ $OUT .= "<TR>$td COLSPAN=3 ALIGN=center>".
+ qq!<A HREF="$link">!. 'Setup '. $part_svc->{'svc'}. '</A> '.
+ '('. $part_svc->{'num_avail'}. ' available)'.
+ '</TD></TR>'
+ #self-service only supports these services so far
+ if grep { $part_svc->{'svcdb'} eq $_ } qw( svc_acct svc_external );
+
+ $col = $col eq $col1 ? $col2 : $col1;
+ }
+
+ #$OUT .= '</TABLE><BR>';
+ $OUT .= '<TR><TD BGCOLOR="#eeeeee" COLSPAN=3>&nbsp;</TD></TR>';
+
+} %>
+
+</TABLE>
diff --git a/fs_selfservice/FS-SelfService/cgi/provision_svc_acct.html b/fs_selfservice/FS-SelfService/cgi/provision_svc_acct.html
new file mode 100644
index 000000000..550493bbc
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/provision_svc_acct.html
@@ -0,0 +1,8 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+<%= include('svc_acct') %>
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/recharge_prepay.html b/fs_selfservice/FS-SelfService/cgi/recharge_prepay.html
new file mode 100644
index 000000000..3de4c8790
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/recharge_prepay.html
@@ -0,0 +1,33 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+<FONT SIZE=4>Recharge with prepaid card</FONT><BR><BR>
+<FORM NAME="OneTrueForm" METHOD="POST" ACTION="<%=$selfurl%>" onSubmit="document.OneTrueForm.process.disabled=true">
+<INPUT TYPE="hidden" NAME="session" VALUE="<%=$session_id%>">
+<INPUT TYPE="hidden" NAME="action" VALUE="recharge_results">
+<TABLE BGCOLOR="#cccccc">
+<!--
+<TR>
+ <TD ALIGN="right">Amount&nbsp;Due</TD>
+ <TD>
+ <TABLE><TR><TD BGCOLOR="#ffffff">
+ $<%=sprintf("%.2f",$balance)%>
+ </TD></TR></TABLE>
+ </TD>
+</TR>
+-->
+<TR>
+ <TD ALIGN="right">Prepaid&nbsp;card&nbsp;number</TD>
+ <TD>
+ <INPUT TYPE="text" NAME="prepaid_cardnum" SIZE=20 MAXLENGTH=19 VALUE="<%=$prepaid_cardnum%>">
+ </TD>
+</TR>
+</TABLE>
+<BR>
+<INPUT TYPE="hidden" NAME="paybatch" VALUE="<%=$paybatch%>">
+<INPUT TYPE="submit" NAME="process" VALUE="Recharge"> <!-- onClick="this.disabled=true"> -->
+</FORM>
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/recharge_results.html b/fs_selfservice/FS-SelfService/cgi/recharge_results.html
new file mode 100644
index 000000000..6d928e3f9
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/recharge_results.html
@@ -0,0 +1,21 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+<FONT SIZE=4>Recharge results</FONT><BR><BR>
+<%= if ( $error ) {
+ $OUT .= qq!<FONT SIZE="+1" COLOR="#ff0000">Error processing your prepaid card: $error</FONT>!;
+} else {
+ $OUT .= 'Prepaid card recharge successful!<BR><BR>';
+
+ $OUT .= '$'. sprintf('%.2f', $amount). ' added to your account.<BR><BR>'
+ if $amount;
+
+ $OUT .= $duration. ' added to your account.<BR><BR>'
+ if $seconds;
+
+ $OUT .= 'Thank you.';
+} %>
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/regcode.html b/fs_selfservice/FS-SelfService/cgi/regcode.html
new file mode 100644
index 000000000..e639b9b53
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/regcode.html
@@ -0,0 +1,14 @@
+<HTML><HEAD><TITLE>ISP Signup</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=7>ISP Signup - registration code</FONT><BR><BR>
+<SCRIPT>
+function gotoURL(object) {
+ window.location.href = 'signup.cgi?reg_code=' + object.reg_code.value;
+}
+</SCRIPT>
+<FORM>
+Enter registration code <INPUT TYPE="text" NAME="reg_code">
+<INPUT type="submit" VALUE="Signup" onClick="gotoURL(this.form)">
+
+</FORM>
+</BODY>
+</HTML>
diff --git a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi
new file mode 100644
index 000000000..865b5cecd
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi
@@ -0,0 +1,667 @@
+#!/usr/bin/perl -Tw
+
+use strict;
+use vars qw($DEBUG $cgi $session_id $form_max $template_dir);
+use subs qw(do_template);
+use CGI;
+use CGI::Carp qw(fatalsToBrowser);
+use Text::Template;
+use HTML::Entities;
+use Date::Format;
+use Number::Format 1.50;
+use FS::SelfService qw( login_info login customer_info edit_info invoice
+ payment_info process_payment
+ process_prepay
+ list_pkgs order_pkg signup_info order_recharge
+ part_svc_info provision_acct provision_external
+ unprovision_svc change_pkg domainselector
+ list_svcs list_svc_usage list_support_usage
+ myaccount_passwd
+ );
+
+$template_dir = '.';
+
+$DEBUG = 1;
+
+$form_max = 255;
+
+$cgi = new CGI;
+
+unless ( defined $cgi->param('session') ) {
+ my $login_info = login_info();
+
+ do_template('login', $login_info );
+ exit;
+}
+
+if ( $cgi->param('session') eq 'login' ) {
+
+ $cgi->param('username') =~ /^\s*([a-z0-9_\-\.\&]{0,$form_max})\s*$/i
+ or die "illegal username";
+ my $username = $1;
+
+ $cgi->param('domain') =~ /^\s*([\w\-\.]{0,$form_max})\s*$/
+ or die "illegal domain";
+ my $domain = $1;
+
+ $cgi->param('password') =~ /^(.{0,$form_max})$/
+ or die "illegal password";
+ my $password = $1;
+
+ my $rv = login(
+ 'username' => $username,
+ 'domain' => $domain,
+ 'password' => $password,
+ );
+ if ( $rv->{error} ) {
+ my $login_info = login_info();
+ do_template('login', {
+ 'error' => $rv->{error},
+ 'username' => $username,
+ 'domain' => $domain,
+ %$login_info,
+ } );
+ exit;
+ } else {
+ $cgi->param('session' => $rv->{session_id} );
+ $cgi->param('action' => 'myaccount' );
+ }
+}
+
+$session_id = $cgi->param('session');
+
+#order|pw_list XXX ???
+$cgi->param('action') =~
+ /^(myaccount|view_invoice|make_payment|make_ach_payment|payment_results|ach_payment_results|recharge_prepay|recharge_results|logout|change_bill|change_ship|change_pay|process_change_bill|process_change_ship|process_change_pay|customer_order_pkg|process_order_pkg|customer_change_pkg|process_change_pkg|process_order_recharge|provision|provision_svc|process_svc_acct|process_svc_external|delete_svc|view_usage|view_usage_details|view_support_details|change_password|process_change_password)$/
+ or die "unknown action ". $cgi->param('action');
+my $action = $1;
+
+warn "calling $action sub\n"
+ if $DEBUG;
+$FS::SelfService::DEBUG = $DEBUG;
+my $result = eval "&$action();";
+die $@ if $@;
+
+if ( $result->{error} eq "Can't resume session"
+ || $result->{error} eq "Expired session" ) { #ick
+
+ my $login_info = login_info();
+ do_template('login', $login_info);
+ exit;
+}
+
+#warn $result->{'open_invoices'};
+#warn scalar(@{$result->{'open_invoices'}});
+
+warn "processing template $action\n"
+ if $DEBUG;
+do_template($action, {
+ 'session_id' => $session_id,
+ 'action' => $action, #so the menu knows what tab we're on...
+ %{$result}
+});
+
+#--
+
+sub myaccount { customer_info( 'session_id' => $session_id ); }
+
+sub change_bill { my $payment_info =
+ payment_info( 'session_id' => $session_id );
+ return $payment_info if ( $payment_info->{'error'} );
+ my $customer_info =
+ customer_info( 'session_id' => $session_id );
+ return {
+ %$payment_info,
+ %$customer_info,
+ };
+ }
+sub change_ship { change_bill(@_); }
+sub change_pay { change_bill(@_); }
+
+sub _process_change_info {
+ my ($erroraction, @fields) = @_;
+
+ my $results = '';
+
+ $results ||= edit_info (
+ 'session_id' => $session_id,
+ map { ($_ => $cgi->param($_)) } grep { defined($cgi->param($_)) } @fields,
+ );
+
+
+ if ( $results->{'error'} ) {
+ no strict 'refs';
+ $action = $erroraction;
+ return {
+ $cgi->Vars,
+ %{&$action()},
+ 'error' => '<FONT COLOR="#FF0000">'. $results->{'error'}. '</FONT>',
+ };
+ } else {
+ return $results;
+ }
+}
+
+sub process_change_bill {
+ _process_change_info( 'change_bill',
+ qw( first last company address1 address2 city state
+ county zip country daytime night fax )
+ );
+}
+
+sub process_change_ship {
+ my @list = map { "ship_$_" }
+ qw( first last company address1 address2 city state
+ county zip country daytime night fax
+ );
+ if ($cgi->param('same') eq 'Y') {
+ foreach (@list) { $cgi->param($_, '') }
+ }
+
+ _process_change_info( 'change_ship', @list );
+}
+
+sub process_change_pay {
+ my $postal = $cgi->param( 'postal_invoicing' );
+ my @list =
+ qw( payby payinfo payinfo1 payinfo2 month year payname
+ address1 address2 city county state zip country auto paytype
+ paystate ss stateid stateid_state invoicing_list
+ );
+ push @list, 'postal_invoicing' if $postal;
+ unless ( $postal || $cgi->param( 'invoicing_list' ) ) {
+ $action = 'change_pay';
+ return {
+ %{&change_pay()},
+ $cgi->Vars,
+ 'error' => '<FONT COLOR="#FF0000">Postal or email required.</FONT>',
+ };
+ }
+ _process_change_info( 'change_pay', @list );
+}
+
+sub view_invoice {
+
+ $cgi->param('invnum') =~ /^(\d+)$/ or die "illegal invnum";
+ my $invnum = $1;
+
+ invoice( 'session_id' => $session_id,
+ 'invnum' => $invnum,
+ );
+
+}
+
+sub customer_order_pkg {
+ my $init_data = signup_info( 'customer_session_id' => $session_id );
+ return $init_data if ( $init_data->{'error'} );
+
+ my $customer_info = customer_info( 'session_id' => $session_id );
+ return $customer_info if ( $customer_info->{'error'} );
+
+ return {
+ ( map { $_ => $init_data->{$_} }
+ qw( part_pkg security_phrase svc_acct_pop ),
+ ),
+ %$customer_info,
+ };
+}
+
+sub customer_change_pkg {
+ my $init_data = signup_info( 'customer_session_id' => $session_id );
+ return $init_data if ( $init_data->{'error'} );
+
+ my $customer_info = customer_info( 'session_id' => $session_id );
+ return $customer_info if ( $customer_info->{'error'} );
+
+ return {
+ ( map { $_ => $init_data->{$_} }
+ qw( part_pkg security_phrase svc_acct_pop ),
+ ),
+ ( map { $_ => $cgi->param($_) }
+ qw( pkgnum pkg )
+ ),
+ %$customer_info,
+ };
+}
+
+sub process_order_pkg {
+
+ my $results = '';
+
+ unless ( length($cgi->param('_password')) ) {
+ my $init_data = signup_info( 'customer_session_id' => $session_id );
+ $results = { 'error' => $init_data->{msgcat}{empty_password} };
+ $results = { 'error' => $init_data->{error} } if($init_data->{error});
+ }
+ if ( $cgi->param('_password') ne $cgi->param('_password2') ) {
+ my $init_data = signup_info( 'customer_session_id' => $session_id );
+ $results = { 'error' => $init_data->{msgcat}{passwords_dont_match} };
+ $results = { 'error' => $init_data->{error} } if($init_data->{error});
+ $cgi->param('_password', '');
+ $cgi->param('_password2', '');
+ }
+
+ $results ||= order_pkg (
+ 'session_id' => $session_id,
+ map { $_ => $cgi->param($_) }
+ qw( custnum pkgpart username _password _password2 sec_phrase popnum )
+ );
+
+
+ if ( $results->{'error'} ) {
+ $action = 'customer_order_pkg';
+ return {
+ $cgi->Vars,
+ %{customer_order_pkg()},
+ 'error' => '<FONT COLOR="#FF0000">'. $results->{'error'}. '</FONT>',
+ };
+ } else {
+ return $results;
+ }
+
+}
+
+sub process_change_pkg {
+
+ my $results = '';
+
+ $results ||= change_pkg (
+ 'session_id' => $session_id,
+ map { $_ => $cgi->param($_) }
+ qw( pkgpart pkgnum )
+ );
+
+
+ if ( $results->{'error'} ) {
+ $action = 'customer_change_pkg';
+ return {
+ $cgi->Vars,
+ %{customer_change_pkg()},
+ 'error' => '<FONT COLOR="#FF0000">'. $results->{'error'}. '</FONT>',
+ };
+ } else {
+ return $results;
+ }
+
+}
+
+sub process_order_recharge {
+
+ my $results = '';
+
+ $results ||= order_recharge (
+ 'session_id' => $session_id,
+ map { $_ => $cgi->param($_) }
+ qw( svcnum )
+ );
+
+
+ if ( $results->{'error'} ) {
+ $action = 'view_usage';
+ if ($results->{'error'} eq '_decline') {
+ $results->{'error'} = "There has been an error processing your account. Please contact customer support."
+ }
+ return {
+ $cgi->Vars,
+ %{view_usage()},
+ 'error' => '<FONT COLOR="#FF0000">'. $results->{'error'}. '</FONT>',
+ };
+ } else {
+ return $results;
+ }
+
+}
+
+sub make_payment {
+ payment_info( 'session_id' => $session_id );
+}
+
+sub payment_results {
+
+ use Business::CreditCard;
+
+ #we should only do basic checking here for DoS attacks and things
+ #that couldn't be constructed by the web form... let process_payment() do
+ #the rest, it gives better error messages
+
+ $cgi->param('amount') =~ /^\s*(\d+(\.\d{2})?)\s*$/
+ or die "Illegal amount: ". $cgi->param('amount'); #!!!
+ my $amount = $1;
+
+ my $payinfo = $cgi->param('payinfo');
+ $payinfo =~ s/\D//g;
+ $payinfo =~ /^(\d{13,16})$/
+ #or $error ||= $init_data->{msgcat}{invalid_card}; #. $self->payinfo;
+ or die "illegal card"; #!!!
+ $payinfo = $1;
+ validate($payinfo)
+ #or $error ||= $init_data->{msgcat}{invalid_card}; #. $self->payinfo;
+ or die "invalid card"; #!!!
+
+ if ( $cgi->param('card_type') ) {
+ cardtype($payinfo) eq $cgi->param('card_type')
+ #or $error ||= $init_data->{msgcat}{not_a}. $cgi->param('CARD_type');
+ or die "not a ". $cgi->param('card_type');
+ }
+
+ $cgi->param('paycvv') =~ /^\s*(.{0,4})\s*$/ or die "illegal CVV2";
+ my $paycvv = $1;
+
+ $cgi->param('month') =~ /^(\d{2})$/ or die "illegal month";
+ my $month = $1;
+ $cgi->param('year') =~ /^(\d{4})$/ or die "illegal year";
+ my $year = $1;
+
+ $cgi->param('payname') =~ /^(.{0,80})$/ or die "illegal payname";
+ my $payname = $1;
+
+ $cgi->param('address1') =~ /^(.{0,80})$/ or die "illegal address1";
+ my $address1 = $1;
+
+ $cgi->param('address2') =~ /^(.{0,80})$/ or die "illegal address2";
+ my $address2 = $1;
+
+ $cgi->param('city') =~ /^(.{0,80})$/ or die "illegal city";
+ my $city = $1;
+
+ $cgi->param('state') =~ /^(.{2})$/ or die "illegal state";
+ my $state = $1;
+
+ $cgi->param('zip') =~ /^(.{0,10})$/ or die "illegal zip";
+ my $zip = $1;
+
+ my $save = 0;
+ $save = 1 if $cgi->param('save');
+
+ my $auto = 0;
+ $auto = 1 if $cgi->param('auto');
+
+ $cgi->param('paybatch') =~ /^([\w\-\.]+)$/ or die "illegal paybatch";
+ my $paybatch = $1;
+
+ process_payment(
+ 'session_id' => $session_id,
+ 'payby' => 'CARD',
+ 'amount' => $amount,
+ 'payinfo' => $payinfo,
+ 'paycvv' => $paycvv,
+ 'month' => $month,
+ 'year' => $year,
+ 'payname' => $payname,
+ 'address1' => $address1,
+ 'address2' => $address2,
+ 'city' => $city,
+ 'state' => $state,
+ 'zip' => $zip,
+ 'save' => $save,
+ 'auto' => $auto,
+ 'paybatch' => $paybatch,
+ );
+
+}
+
+sub make_ach_payment {
+ payment_info( 'session_id' => $session_id );
+}
+
+sub ach_payment_results {
+
+ #we should only do basic checking here for DoS attacks and things
+ #that couldn't be constructed by the web form... let process_payment() do
+ #the rest, it gives better error messages
+
+ $cgi->param('amount') =~ /^\s*(\d+(\.\d{2})?)\s*$/
+ or die "illegal amount"; #!!!
+ my $amount = $1;
+
+ my $payinfo1 = $cgi->param('payinfo1');
+ $payinfo1=~ /^(\d+)$/
+ or die "illegal account"; #!!!
+ $payinfo1= $1;
+
+ my $payinfo2 = $cgi->param('payinfo2');
+ $payinfo2=~ /^(\d+)$/
+ or die "illegal ABA/routing code"; #!!!
+ $payinfo2= $1;
+
+ $cgi->param('payname') =~ /^(.{0,80})$/ or die "illegal payname";
+ my $payname = $1;
+
+ $cgi->param('paystate') =~ /^(.{0,2})$/ or die "illegal paystate";
+ my $paystate = $1;
+
+ $cgi->param('paytype') =~ /^(.{0,80})$/ or die "illegal paytype";
+ my $paytype = $1;
+
+ $cgi->param('ss') =~ /^(.{0,80})$/ or die "illegal ss";
+ my $ss = $1;
+
+ $cgi->param('stateid') =~ /^(.{0,80})$/ or die "illegal stateid";
+ my $stateid = $1;
+
+ $cgi->param('stateid_state') =~ /^(.{0,2})$/ or die "illegal stateid_state";
+ my $stateid_state = $1;
+
+ my $save = 0;
+ $save = 1 if $cgi->param('save');
+
+ my $auto = 0;
+ $auto = 1 if $cgi->param('auto');
+
+ $cgi->param('paybatch') =~ /^([\w\-\.]+)$/ or die "illegal paybatch";
+ my $paybatch = $1;
+
+ process_payment(
+ 'session_id' => $session_id,
+ 'payby' => 'CHEK',
+ 'amount' => $amount,
+ 'payinfo1' => $payinfo1,
+ 'payinfo2' => $payinfo2,
+ 'month' => '12',
+ 'year' => '2037',
+ 'payname' => $payname,
+ 'paytype' => $paytype,
+ 'paystate' => $paystate,
+ 'ss' => $ss,
+ 'stateid' => $stateid,
+ 'stateid_state' => $stateid_state,
+ 'save' => $save,
+ 'auto' => $auto,
+ 'paybatch' => $paybatch,
+ );
+
+}
+
+sub recharge_prepay {
+ customer_info( 'session_id' => $session_id );
+}
+
+sub recharge_results {
+
+ my $prepaid_cardnum = $cgi->param('prepaid_cardnum');
+ $prepaid_cardnum =~ s/\W//g;
+ $prepaid_cardnum =~ /^(\w*)$/ or die "illegal prepaid card number";
+ $prepaid_cardnum = $1;
+
+ process_prepay ( 'session_id' => $session_id,
+ 'prepaid_cardnum' => $prepaid_cardnum,
+ );
+}
+
+sub logout {
+ FS::SelfService::logout( 'session_id' => $session_id );
+}
+
+sub provision {
+ my $result = list_pkgs( 'session_id' => $session_id );
+ die $result->{'error'} if exists $result->{'error'} && $result->{'error'};
+ $result;
+}
+
+sub provision_svc {
+
+ my $result = part_svc_info(
+ 'session_id' => $session_id,
+ map { $_ => $cgi->param($_) } qw( pkgnum svcpart ),
+ );
+ die $result->{'error'} if exists $result->{'error'} && $result->{'error'};
+
+ $result->{'svcdb'} =~ /^svc_(.*)$/
+ #or return { 'error' => 'Unknown svcdb '. $result->{'svcdb'} };
+ or die 'Unknown svcdb '. $result->{'svcdb'};
+ $action .= "_$1";
+
+ $result;
+}
+
+sub process_svc_acct {
+
+ my $result = provision_acct (
+ 'session_id' => $session_id,
+ map { $_ => $cgi->param($_) } qw(
+ pkgnum svcpart username domsvc _password _password2 sec_phrase popnum )
+ );
+
+ if ( exists $result->{'error'} && $result->{'error'} ) {
+ #warn "$result $result->{'error'}";
+ $action = 'provision_svc_acct';
+ return {
+ $cgi->Vars,
+ %{ part_svc_info( 'session_id' => $session_id,
+ map { $_ => $cgi->param($_) } qw( pkgnum svcpart )
+ )
+ },
+ 'error' => $result->{'error'},
+ };
+ } else {
+ #warn "$result $result->{'error'}";
+ return $result;
+ }
+
+}
+
+sub process_svc_external {
+ provision_external (
+ 'session_id' => $session_id,
+ map { $_ => $cgi->param($_) } qw( pkgnum svcpart )
+ );
+}
+
+sub delete_svc {
+ unprovision_svc(
+ 'session_id' => $session_id,
+ 'svcnum' => $cgi->param('svcnum'),
+ );
+}
+
+sub view_usage {
+ list_svcs(
+ 'session_id' => $session_id,
+ 'svcdb' => 'svc_acct',
+ 'ncancelled' => 1,
+ );
+}
+
+sub view_usage_details {
+ list_svc_usage(
+ 'session_id' => $session_id,
+ 'svcnum' => $cgi->param('svcnum'),
+ 'beginning' => $cgi->param('beginning') || '',
+ 'ending' => $cgi->param('ending') || '',
+ );
+}
+
+sub view_support_details {
+ list_support_usage(
+ 'session_id' => $session_id,
+ 'svcnum' => $cgi->param('svcnum'),
+ 'beginning' => $cgi->param('beginning') || '',
+ 'ending' => $cgi->param('ending') || '',
+ );
+}
+
+sub change_password {
+ list_svcs(
+ 'session_id' => $session_id,
+ 'svcdb' => 'svc_acct',
+ );
+};
+
+sub process_change_password {
+
+ my $result = myaccount_passwd(
+ 'session_id' => $session_id,
+ map { $_ => $cgi->param($_) } qw( svcnum new_password new_password2 )
+ );
+
+ if ( exists $result->{'error'} && $result->{'error'} ) {
+
+ $action = 'change_password';
+ return {
+ $cgi->Vars,
+ %{ list_svcs( 'session_id' => $session_id,
+ 'svcdb' => 'svc_acct',
+ )
+ },
+ #'svcnum' => $cgi->param('svcnum'),
+ 'error' => $result->{'error'}
+ };
+
+ } else {
+
+ return $result;
+
+ }
+
+}
+
+#--
+
+sub do_template {
+ my $name = shift;
+ my $fill_in = shift;
+
+ $cgi->delete_all();
+ $fill_in->{'selfurl'} = $cgi->self_url;
+ $fill_in->{'cgi'} = \$cgi;
+
+ my $source = "$template_dir/$name.html";
+ #warn "creating template for $source\n";
+ my $template = new Text::Template( TYPE => 'FILE',
+ SOURCE => $source,
+ DELIMITERS => [ '<%=', '%>' ],
+ UNTAINT => 1,
+ )
+ or die $Text::Template::ERROR;
+
+ #warn "filling in $template with $fill_in\n";
+ print $cgi->header( '-expires' => 'now' ),
+ $template->fill_in( PACKAGE => 'FS::SelfService::_selfservicecgi',
+ HASH => $fill_in
+ );
+}
+
+#*FS::SelfService::_selfservicecgi::include = \&Text::Template::fill_in_file;
+
+package FS::SelfService::_selfservicecgi;
+
+#use FS::SelfService qw(regionselector expselect popselector);
+use HTML::Entities;
+use FS::SelfService qw(regionselector popselector domainselector);
+
+#false laziness w/agent.cgi
+sub include {
+ my $name = shift;
+ my $template = new Text::Template( TYPE => 'FILE',
+ SOURCE => "$main::template_dir/$name.html",
+ DELIMITERS => [ '<%=', '%>' ],
+ UNTAINT => 1,
+ )
+ or die $Text::Template::ERROR;
+
+ $template->fill_in( PACKAGE => 'FS::SelfService::_selfservicecgi',
+ #HASH => $fill_in
+ );
+
+}
+
diff --git a/fs_selfservice/FS-SelfService/cgi/signup-agentselect.html b/fs_selfservice/FS-SelfService/cgi/signup-agentselect.html
new file mode 100755
index 000000000..7851c5601
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/signup-agentselect.html
@@ -0,0 +1,195 @@
+<HTML><HEAD><TITLE>ISP Signup form</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=7>ISP Signup form</FONT><BR><BR>
+<FONT SIZE="+1" COLOR="#ff0000"><%= $error %></FONT>
+<FORM NAME="OneTrueForm" ACTION="<%= $self_url %>" METHOD=POST onSubmit="document.OneTrueForm.signup.disabled=true">
+<INPUT TYPE="hidden" NAME="magic" VALUE="process">
+<INPUT TYPE="hidden" NAME="ref" VALUE="<%= $referral_custnum %>">
+<INPUT TYPE="hidden" NAME="ss" VALUE="">
+Agent <SELECT NAME="agentnum">
+<%=
+ warn $init_data;
+ warn $init_data->{'agent'};
+ foreach my $agent ( @{$init_data->{'agent'}} ) {
+ $OUT .= '<OPTION VALUE="'. $agent->{'agentnum'}. '"';
+ $OUT .= ' SELECTED' if $agent->{'agentnum'} eq $agentnum;
+ $OUT .= '>'. $agent->{'agent'};
+ }
+%>
+</SELECT><BR><BR>
+Contact Information
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Contact name<BR>(last, first)</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="last" VALUE="<%= $last %>">,
+ <INPUT TYPE="text" NAME="first" VALUE="<%= $first %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Company</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="company" SIZE=70 VALUE="<%= $company %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Address</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address1" SIZE=70 VALUE="<%= $address1 %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">&nbsp;</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address2" SIZE=70 VALUE="<%= $address2 %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>City</TH>
+ <TD><INPUT TYPE="text" NAME="city" VALUE="<%= $city %>"></TD>
+ <TH ALIGN="right"><font color="#ff0000">*</font>State/Country</TH>
+ <TD>
+ <%=
+ ($county_html, $state_html, $country_html) =
+ regionselector( $county, $state, $country );
+
+ "$county_html $state_html";
+ %>
+ </TD>
+ <TH><font color="#ff0000">*</font>Zip</TH>
+ <TD><INPUT TYPE="text" NAME="zip" SIZE=10 VALUE="<%= $zip %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Country</TH>
+ <TD><%= $country_html %></TD>
+<TR>
+ <TD ALIGN="right">Day Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="daytime" VALUE="<%= $daytime %>" SIZE=18></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Night Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="night" VALUE="<%= $night %>" SIZE=18></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Fax</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="fax" VALUE="<%= $fax %>" SIZE=12></TD>
+</TR>
+</TABLE><font color="#ff0000">*</font> required fields<BR>
+<BR>Billing information<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR><TD>
+
+ <%=
+ $OUT .= '<INPUT TYPE="checkbox" NAME="invoicing_list_POST" VALUE="POST"';
+ my @invoicing_list = split(', ', $invoicing_list );
+ $OUT .= ' CHECKED'
+ if ! @invoicing_list || grep { $_ eq 'POST' } @invoicing_list;
+ $OUT .= '>';
+ %>
+
+ Postal mail invoice
+</TD></TR>
+<TR><TD>Email invoice <INPUT TYPE="text" NAME="invoicing_list" VALUE="<%= join(', ', grep { $_ ne 'POST' } split(', ', $invoicing_list ) ) %>">
+</TD></TR>
+<%= scalar(@payby) > 1 ? '<TR><TD>Billing type</TD></TR>' : '' %>
+</TABLE>
+<TABLE BGCOLOR="#c0c0c0" BORDER=1 WIDTH="100%">
+<TR>
+
+ <%=
+
+ my $cardselect = '<SELECT NAME="CARD_type"><OPTION></OPTION>';
+ my %types = (
+ 'VISA' => 'VISA card',
+ 'MasterCard' => 'MasterCard',
+ 'Discover' => 'Discover card',
+ 'American Express' => 'American Express card',
+ );
+ foreach ( keys %types ) {
+ $selected = $cgi->param('CARD_type') eq $types{$_} ? 'SELECTED' : '';
+ $cardselect .= qq!<OPTION $selected VALUE="$types{$_}">$_</OPTION>!;
+ }
+ $cardselect .= '</SELECT>';
+
+ my %payby = (
+ 'CARD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("CARD"). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="">!,
+ 'DCRD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("DCRD"). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="">!,
+ 'CHEK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="">!,
+ 'DCHK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="">!,
+ 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+ 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE=""><BR><font color="#ff0000">*</font>Exp !. expselect("BILL", "12-2037"). qq!<BR><font color="#ff0000">*</font>Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="Accounts Payable">!,
+ 'COMP' => qq!Complimentary<BR><font color="#ff0000">*</font>Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE=""><BR><font color="#ff0000">*</font>Exp !. expselect("COMP"),
+ 'PREPAY' => qq!Prepaid card<BR><font color="#ff0000">*</font><INPUT TYPE="text" NAME="PREPAY_payinfo" VALUE="" MAXLENGTH=80>!,
+ );
+
+ my( $account, $aba ) = split('@', $payinfo);
+ my %paybychecked = (
+ 'CARD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("CARD", $paydate). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="$payname">!,
+ 'DCRD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("DCRD", $paydate). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="$payname">!,
+ 'CHEK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="$account" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="$payname">!,
+ 'DCHK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="$account" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="$payname">!,
+ 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="$payinfo" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+ 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE="$payinfo"><BR><font color="#ff0000">*</font>Exp !. expselect("BILL", $paydate). qq!<BR><font color="#ff0000">*</font>Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="$payname">!,
+ 'COMP' => qq!Complimentary<BR><font color="#ff0000">*</font>Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE="$payinfo"><BR><font color="#ff0000">*</font>Exp !. expselect("COMP", $paydate),
+ 'PREPAY' => qq!Prepaid card<BR><font color="#ff0000">*</font><INPUT TYPE="text" NAME="PREPAY_payinfo" VALUE="$payinfo" MAXLENGTH=80>!,
+ );
+
+ for (@payby) {
+ if ( scalar(@payby) == 1) {
+ $OUT .= '<TD VALIGN=TOP>'.
+ qq!<INPUT TYPE="hidden" NAME="payby" VALUE="$_">!.
+ "$paybychecked{$_}</TD>";
+ } else {
+ $OUT .= qq!<TD VALIGN=TOP><INPUT TYPE="radio" NAME="payby" VALUE="$_"!;
+ if ($payby eq $_) {
+ $OUT .= qq! CHECKED> $paybychecked{$_}</TD>!;
+ } else {
+ $OUT .= qq!> $payby{$_}</TD>!;
+ }
+
+ }
+ }
+ %>
+
+</TR></TABLE><font color="#ff0000">*</font> required fields for each billing type
+<BR><BR>First package
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TD COLSPAN=2><SELECT NAME="pkgpart"><OPTION VALUE="">(none)
+
+ <%=
+ foreach my $package ( @{$packages} ) {
+ $OUT .= '<OPTION VALUE="'. $package->{'pkgpart'}. '"';
+ $OUT .= ' SELECTED' if $pkgpart && $package->{'pkgpart'} == $pkgpart;
+ $OUT .= '>'. $package->{'pkg'};
+ }
+ %>
+
+ </SELECT></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Username</TD>
+ <TD><INPUT TYPE="text" NAME="username" VALUE="<%= $username %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password" VALUE="<%= $password %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Re-enter Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password2" VALUE="<%= $password2 %>"></TD>
+</TR>
+<%=
+ if ( $init_data->{'security_phrase'} ) {
+ $OUT .= <<ENDOUT;
+<TR>
+ <TD ALIGN="right">Security Phrase</TD>
+ <TD><INPUT TYPE="text" NAME="sec_phrase" VALUE="$sec_phrase">
+ </TD>
+</TR>
+ENDOUT
+ } else {
+ $OUT .= '<INPUT TYPE="hidden" NAME="sec_phrase" VALUE="">';
+ }
+%>
+<%=
+ if ( scalar(@$pops) ) {
+ $OUT .= '<TR><TD ALIGN="right">Access number</TD><TD>'.
+ popselector($popnum). '</TD></TR>';
+ } else {
+ $OUT .= popselector($popnum);
+ }
+%>
+</TABLE>
+<BR><BR><INPUT TYPE="submit" NAME="signup" VALUE="Signup" >
+</FORM></BODY></HTML>
diff --git a/fs_selfservice/FS-SelfService/cgi/signup-alternate.html b/fs_selfservice/FS-SelfService/cgi/signup-alternate.html
new file mode 100755
index 000000000..490cefa5e
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/signup-alternate.html
@@ -0,0 +1,218 @@
+<HTML><HEAD><TITLE>ISP Signup form</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=7>ISP Signup form</FONT><BR><BR>
+<FONT SIZE="+1" COLOR="#ff0000"><%= $error %></FONT>
+<FORM NAME="dummy">
+<INPUT TYPE="hidden" NAME="magic" VALUE="process">
+<INPUT TYPE="hidden" NAME="ref" VALUE="<%= $referral_custnum %>">
+<INPUT TYPE="hidden" NAME="ss" VALUE="">
+<INPUT TYPE="hidden" NAME="agentnum" VALUE="3">
+Contact Information
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Contact name<BR>(last, first)</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="last" VALUE="<%= $last %>">,
+ <INPUT TYPE="text" NAME="first" VALUE="<%= $first %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Company</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="company" SIZE=70 VALUE="<%= $company %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Address</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address1" SIZE=70 VALUE="<%= $address1 %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">&nbsp;</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address2" SIZE=70 VALUE="<%= $address2 %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>City</TH>
+ <TD><INPUT TYPE="text" NAME="city" VALUE="<%= $city %>"></TD>
+ <TH ALIGN="right"><font color="#ff0000">*</font>State/Country</TH>
+ <TD><SELECT NAME="state" SIZE="1">
+
+ <%=
+ foreach ( @{$locales} ) {
+ my $value = $_->{'state'};
+ $value .= ' ('. $_->{'county'}. ')' if $_->{'county'};
+ $value .= ' / '. $_->{'country'};
+
+ $OUT .= qq(<OPTION VALUE="$value");
+ $OUT .= ' SELECTED' if ( $state eq $_->{'state'}
+ && $county eq $_->{'county'}
+ && $country eq $_->{'country'}
+ );
+ $OUT .= ">$value</OPTION>";
+ }
+ %>
+
+ </SELECT></TD>
+ <TH><font color="#ff0000">*</font>Zip</TH>
+ <TD><INPUT TYPE="text" NAME="zip" SIZE=10 VALUE="<%= $zip %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Day Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="daytime" VALUE="<%= $daytime %>" SIZE=18></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Night Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="night" VALUE="<%= $night %>" SIZE=18></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Fax</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="fax" VALUE="<%= $fax %>" SIZE=12></TD>
+</TR>
+</TABLE><font color="#ff0000">*</font> required fields<BR>
+
+<BR><BR>
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Username</TH>
+ <TD><INPUT TYPE="text" NAME="username" VALUE="<%= $username %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Password</TH>
+ <TD><INPUT TYPE="password" NAME="_password" VALUE="<%= $password %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Re-enter Password</TH>
+ <TD><INPUT TYPE="password" NAME="_password2" VALUE="<%= $password2 %>"></TD>
+</TR>
+
+<%= if ( $init_data->{'security_phrase'} ) {
+ <<ENDOUT;
+<TR>
+ <TD ALIGN="right">Security Phrase</TD>
+ <TD><INPUT TYPE="text" NAME="sec_phrase" VALUE="$sec_phrase">
+ </TD>
+</TR>
+ENDOUT
+ } else {
+ '<INPUT TYPE="hidden" NAME="sec_phrase" VALUE="">';
+ }
+%>
+
+<%= if ( scalar(@$pops) ) {
+ '<TR><TD ALIGN="right">Access number</TD><TD>'.
+ popselector($popnum). '</TD></TR>';
+ } else {
+ popselector($popnum);
+ }
+%>
+
+</TABLE><font color="#ff0000">*</font> required fields
+
+<BR><BR>First package
+
+ <%= use Tie::IxHash;
+ my %pkgpart2payby = map { $_->{pkgpart} => $_->{payby}[0] } @{$packages};
+ tie my %options, 'Tie::IxHash',
+ '' => '(none)',
+ map { $_->{pkgpart} => $_->{pkg} }
+ sort { $a->{recur} <=> $b->{recur} }
+ @{$packages}
+ ;
+
+ use HTML::Widgets::SelectLayers 0.02;
+ my @form_text = qw( magic ref ss agentnum
+ last first company address1 address2
+ city zip daytime night fax
+ username _password _password2 sec_phrase );
+ my @form_select = qw( state ); #county country
+ if ( scalar(@$pops) == 0 or scalar(@$pops) == 1 ) {
+ push @form_text, 'popnum',
+ } else {
+ push @form_select, 'popnum',
+ }
+ my $widget = new HTML::Widgets::SelectLayers(
+ options => \%options,
+ selected_layer => $pkgpart,
+ form_name => 'dummy',
+ form_action => $self_url,
+ form_text => \@form_text,
+ form_select => \@form_select,
+ layer_callback => sub {
+ my $layer = shift;
+ my $html = qq( <INPUT TYPE="hidden" NAME="pkgpart" VALUE="$layer">);
+
+ if ( $pkgpart2payby{$layer} eq 'BILL' ) {
+ $html .= <<ENDOUT;
+<INPUT TYPE="hidden" NAME="payby" VALUE="BILL">
+<INPUT TYPE="hidden" NAME="invoicing_list_POST" VALUE="">
+<INPUT TYPE="hidden" NAME="BILL_payinfo" VALUE="">
+<INPUT TYPE="hidden" NAME="BILL_month" VALUE="12">
+<INPUT TYPE="hidden" NAME="BILL_year" VALUE="2037">
+<INPUT TYPE="hidden" NAME="BILL_payname" VALUE="">
+<BR><BR><INPUT TYPE="submit" VALUE="Signup">
+ENDOUT
+ } elsif ( $pkgpart2payby{$layer} eq 'CARD' ) {
+ my $postal_checked = '';
+ my @invoicing_list = split(', ', $invoicing_list );
+ $postal_checked = 'CHECKED'
+ if ! @invoicing_list || grep { $_ eq 'POST' } @invoicing_list;
+
+ $invoicing_list= join(', ', grep { $_ ne 'POST' } @invoicing_list );
+
+ my $expselect = expselect("CARD", $paydate);
+
+ my $cardselect = '<SELECT NAME="CARD_type"><OPTION></OPTION>';
+ my %types = (
+ 'VISA' => 'VISA card',
+ 'MasterCard' => 'MasterCard',
+ 'Discover' => 'Discover card',
+ 'American Express' => 'American Express card',
+ );
+ foreach ( keys %types ) {
+ $selected =
+ $cgi->param('CARD_type') eq $types{$_} ? 'SELECTED' : '';
+ $cardselect .=
+ qq!<OPTION $selected VALUE="$types{$_}">$_</OPTION>!;
+ }
+ $cardselect .= '</SELECT>';
+
+ $html .= <<ENDOUT;
+<INPUT TYPE="hidden" NAME="payby" VALUE="CARD">
+<BR><BR>Billing information
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0>
+<INPUT TYPE="hidden" NAME="invoicing_list_POST" VALUE="">
+<TR>
+ <TD ALIGN="right">Email statement to </TD>
+ <TD><INPUT TYPE="text" NAME="invoicing_list" VALUE="$invoicing_list"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Credit card type</TH>
+ <TD>$cardselect</TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Card number</TH>
+ <TD><INPUT TYPE="text" NAME="CARD_payinfo" VALUE="$payinfo" MAXLENGTH=19></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>*</font>Exp</TH>
+ <TD>$expselect</TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Name on card</TH>
+ <TD><INPUT TYPE="text" NAME="CARD_payname" VALUE="$payname"></TD>
+</TR>
+</TABLE>
+<font color="#ff0000">*</font> required fields
+<BR><BR><INPUT TYPE="submit" VALUE="Signup">
+ENDOUT
+ } else {
+ $html = <<ENDOUT;
+<BR>Please select a package.<BR>
+ENDOUT
+
+ }
+
+ $html;
+
+ },
+ );
+
+ $widget->html;
+
+
+ %>
+</BODY></HTML>
diff --git a/fs_selfservice/FS-SelfService/cgi/signup-billaddress.html b/fs_selfservice/FS-SelfService/cgi/signup-billaddress.html
new file mode 100755
index 000000000..3cf9d2505
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/signup-billaddress.html
@@ -0,0 +1,307 @@
+<HTML><HEAD><TITLE>ISP Signup form</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8" onUnload="myclose()">
+<script language="JavaScript"><!--
+ var mywindow = -1;
+ function myopen(filename,windowname,properties) {
+ myclose();
+ mywindow = window.open(filename,windowname,properties);
+ }
+ function myclose() {
+ if ( mywindow != -1 )
+ mywindow.close();
+ mywindow = -1
+ }
+//--></script>
+<FONT SIZE=7>ISP Signup form</FONT><BR><BR>
+<FONT SIZE="+1" COLOR="#ff0000"><%= $error %></FONT>
+<FORM NAME="OneTrueForm" ACTION="<%= $self_url %>" METHOD=POST onSubmit="document.OneTrueForm.signup.disabled=true">
+<INPUT TYPE="hidden" NAME="magic" VALUE="process">
+<INPUT TYPE="hidden" NAME="ref" VALUE="<%= $referral_custnum %>">
+<INPUT TYPE="hidden" NAME="ss" VALUE="">
+Where did you hear about our service? <SELECT NAME="refnum">
+<%=
+ $OUT .= '<OPTION VALUE="">' unless $refnum;
+ foreach my $part_referral ( @{$init_data->{'part_referral'}} ) {
+ $OUT .= '<OPTION VALUE="'. $part_referral->{'refnum'}. '"';
+ $OUT .= ' SELECTED' if $part_referral->{'refnum'} eq $refnum;
+ $OUT .= '>'. $part_referral->{'referral'};
+ }
+%>
+</SELECT><BR><BR>
+Billing Address (where credit card statement is sent)
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Exact name on card<BR>(last, first)</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="last" VALUE="<%= $last %>" onChange="changed(this)">,
+ <INPUT TYPE="text" NAME="first" VALUE="<%= $first %>" onChange="changed(this)"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Company</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="company" SIZE=70 VALUE="<%= $company %>" onChange="changed(this)"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Address</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address1" SIZE=70 VALUE="<%= $address1 %>" onChange="changed(this)"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">&nbsp;</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address2" SIZE=70 VALUE="<%= $address2 %>" onChange="changed(this)"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>City</TH>
+ <TD><INPUT TYPE="text" NAME="city" VALUE="<%= $city %>" onChange="changed(this)"></TD>
+ <TH ALIGN="right"><font color="#ff0000">*</font>State/Country</TH>
+ <TD>
+ <%=
+ ($county_html, $state_html, $country_html) =
+ regionselector( $county, $state, $country, '', 'changed(this)' );
+
+ "$county_html $state_html";
+ %>
+ </TD>
+ <TH><font color="#ff0000">*</font>Zip</TH>
+ <TD><INPUT TYPE="text" NAME="zip" SIZE=10 VALUE="<%= $zip %>" onChange="changed(this)"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Country</TH>
+ <TD><%= $country_html %></TD>
+<TR>
+ <TD ALIGN="right">Day Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="daytime" VALUE="<%= $daytime %>" SIZE=18 onChange="changed(this)"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Night Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="night" VALUE="<%= $night %>" SIZE=18 onChange="changed(this)"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Fax</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="fax" VALUE="<%= $fax %>" SIZE=12 onChange="changed(this)"></TD>
+</TR>
+</TABLE>
+
+<SCRIPT>
+function changed(what) {
+ what.form.same.checked = false;
+}
+function samechanged(what) {
+ if ( what.checked ) {
+
+ <%= foreach (qw(
+ last first company address1 address2 city zip daytime night fax
+ )) {
+ $OUT .= "what.form.ship_$_.value = what.form.$_.value;\n";
+ }
+ %>
+
+ what.form.ship_country.selectedIndex = what.form.country.selectedIndex;
+ ship_country_changed(what.form.ship_country);
+ what.form.ship_state.selectedIndex = what.form.state.selectedIndex;
+ ship_state_changed(what.form.ship_state);
+ what.form.ship_county.selectedIndex = what.form.county.selectedIndex;
+ }
+}
+</SCRIPT>
+
+<BR><BR>
+Service Address
+(<INPUT TYPE="checkbox" NAME="same" VALUE="Y" onClick="samechanged(this)" <%= $same eq 'Y' ? 'CHECKED' : '' %>>same as billing address)<BR>
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Contact name<BR>(last, first)</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="ship_last" VALUE="<%= $ship_last %>" onChange="changed(this)">,
+ <INPUT TYPE="text" NAME="ship_first" VALUE="<%= $ship_first %>" onChange="changed(this)"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Company</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="ship_company" SIZE=70 VALUE="<%= $ship_company %>" onChange="changed(this)"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Address</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="ship_address1" SIZE=70 VALUE="<%= $ship_address1 %>" onChange="changed(this)"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">&nbsp;</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="ship_address2" SIZE=70 VALUE="<%= $ship_address2 %>" onChange="changed(this)"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>City</TH>
+ <TD><INPUT TYPE="text" NAME="ship_city" VALUE="<%= $ship_city %>" onChange="changed(this)"></TD>
+ <TH ALIGN="right"><font color="#ff0000">*</font>State/Country</TH>
+ <TD>
+ <%=
+ ($ship_county_html, $ship_state_html, $ship_country_html) =
+ regionselector( $ship_county,
+ $ship_state,
+ $ship_country,
+ 'ship_',
+ 'changed(this)',
+ );
+
+ "$ship_county_html $ship_state_html";
+ %>
+ </TD>
+ <TH><font color="#ff0000">*</font>Zip</TH>
+ <TD><INPUT TYPE="text" NAME="ship_zip" SIZE=10 VALUE="<%= $ship_zip %>" onChange="changed(this)"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Country</TH>
+ <TD><%= $ship_country_html %></TD>
+<TR>
+ <TD ALIGN="right">Day Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="ship_daytime" VALUE="<%= $ship_daytime %>" SIZE=18 onChange="changed(this)"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Night Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="ship_night" VALUE="<%= $ship_night %>" SIZE=18 onChange="changed(this)"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Fax</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="ship_fax" VALUE="<%= $ship_fax %>" SIZE=12 onChange="changed(this)"></TD>
+</TR>
+</TABLE>
+
+<font color="#ff0000">*</font> required fields<BR>
+
+<BR>Billing information<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR><TD>
+
+ <%=
+ $OUT .= '<INPUT TYPE="checkbox" NAME="invoicing_list_POST" VALUE="POST"';
+ my @invoicing_list = split(', ', $invoicing_list );
+ $OUT .= ' CHECKED'
+ if ! @invoicing_list || grep { $_ eq 'POST' } @invoicing_list;
+ $OUT .= '>';
+ %>
+
+ Postal mail invoice
+</TD></TR>
+<TR><TD>Email invoice <INPUT TYPE="text" NAME="invoicing_list" VALUE="<%= join(', ', grep { $_ ne 'POST' } split(', ', $invoicing_list ) ) %>">
+</TD></TR>
+<%= scalar(@payby) > 1 ? '<TR><TD>Billing type</TD></TR>' : '' %>
+</TABLE>
+<TABLE BGCOLOR="#c0c0c0" BORDER=1 WIDTH="100%">
+<TR>
+
+ <%=
+
+ my $cardselect = '<SELECT NAME="CARD_type"><OPTION></OPTION>';
+ my %types = (
+ 'VISA' => 'VISA card',
+ 'MasterCard' => 'MasterCard',
+ 'Discover' => 'Discover card',
+ 'American Express' => 'American Express card',
+ );
+ foreach ( keys %types ) {
+ $selected = $cgi->param('CARD_type') eq $types{$_} ? 'SELECTED' : '';
+ $cardselect .= qq!<OPTION $selected VALUE="$types{$_}">$_</OPTION>!;
+ }
+ $cardselect .= '</SELECT>';
+
+ my %payby = (
+ 'CARD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("CARD"), #. qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="">!,
+ 'DCRD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("DCRD"), #. qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="">!,
+ 'CHEK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="">!,
+ 'DCHK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="">!,
+ 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+ 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE=""><BR><font color="#ff0000">*</font>Exp !. expselect("BILL", "12-2037"). qq!<BR><font color="#ff0000">*</font>Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="Accounts Payable">!,
+ 'COMP' => qq!Complimentary<BR><font color="#ff0000">*</font>Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE=""><BR><font color="#ff0000">*</font>Exp !. expselect("COMP"),
+ 'PREPAY' => qq!Prepaid card<BR><font color="#ff0000">*</font><INPUT TYPE="text" NAME="PREPAY_payinfo" VALUE="" MAXLENGTH=80>!,
+ );
+
+ if ( $init_data->{'cvv_enabled'} ) {
+ foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5
+ $payby{$payby} .= qq!<BR>CVV2&nbsp;(<A HREF="javascript:myopen('cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>)&nbsp;<INPUT TYPE="text" NAME=${payby}_paycvv VALUE="" SIZE=4 MAXLENGTH=4>!;
+ }
+ }
+
+ my( $account, $aba ) = split('@', $payinfo);
+ my %paybychecked = (
+ 'CARD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("CARD", $paydate), #. qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="$payname">!,
+ 'DCRD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("DCRD", $paydate), #. qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="$payname">!,
+ 'CHEK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="$account" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="$payname">!,
+ 'DCHK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="$account" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="$payname">!,
+ 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="$payinfo" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+ 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE="$payinfo"><BR><font color="#ff0000">*</font>Exp !. expselect("BILL", $paydate). qq!<BR><font color="#ff0000">*</font>Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="$payname">!,
+ 'COMP' => qq!Complimentary<BR><font color="#ff0000">*</font>Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE="$payinfo"><BR><font color="#ff0000">*</font>Exp !. expselect("COMP", $paydate),
+ 'PREPAY' => qq!Prepaid card<BR><font color="#ff0000">*</font><INPUT TYPE="text" NAME="PREPAY_payinfo" VALUE="$payinfo" MAXLENGTH=80>!,
+ );
+
+ if ( $init_data->{'cvv_enabled'} ) {
+ foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5
+ $paybychecked{$payby} .= qq!<BR>CVV2&nbsp;(<A HREF="javascript:myopen('cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>)&nbsp;<INPUT TYPE="text" NAME=${payby}_paycvv VALUE="$paycvv" SIZE=4 MAXLENGTH=4>!;
+ }
+ }
+
+ for (@payby) {
+ if ( scalar(@payby) == 1) {
+ $OUT .= '<TD VALIGN=TOP>'.
+ qq!<INPUT TYPE="hidden" NAME="payby" VALUE="$_">!.
+ "$paybychecked{$_}</TD>";
+ } else {
+ $OUT .= qq!<TD VALIGN=TOP><INPUT TYPE="radio" NAME="payby" VALUE="$_"!;
+ if ($payby eq $_) {
+ $OUT .= qq! CHECKED> $paybychecked{$_}</TD>!;
+ } else {
+ $OUT .= qq!> $payby{$_}</TD>!;
+ }
+
+ }
+ }
+ %>
+
+</TR></TABLE><font color="#ff0000">*</font> required fields for each billing type
+<BR><BR>First package
+<INPUT TYPE="hidden" NAME="promo_code" VALUE="<%= $cgi->param('promo_code') %>">
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TD COLSPAN=2><SELECT NAME="pkgpart">
+
+ <%=
+ $OUT .= '<OPTION VALUE="">(none)' unless scalar(@$packages) == 1;
+ foreach my $package ( @{$packages} ) {
+ $OUT .= '<OPTION VALUE="'. $package->{'pkgpart'}. '"';
+ $OUT .= ' SELECTED'
+ if ( $pkgpart && $package->{'pkgpart'} == $pkgpart )
+ || scalar(@$packages) == 1;
+ $OUT .= '>'. $package->{'pkg'};
+ }
+ %>
+
+ </SELECT></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Username</TD>
+ <TD><INPUT TYPE="text" NAME="username" VALUE="<%= $username %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password" VALUE="<%= $password %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Re-enter Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password2" VALUE="<%= $password2 %>"></TD>
+</TR>
+<%=
+ if ( $init_data->{'security_phrase'} ) {
+ $OUT .= <<ENDOUT;
+<TR>
+ <TD ALIGN="right">Security Phrase</TD>
+ <TD><INPUT TYPE="text" NAME="sec_phrase" VALUE="$sec_phrase">
+ </TD>
+</TR>
+ENDOUT
+ } else {
+ $OUT .= '<INPUT TYPE="hidden" NAME="sec_phrase" VALUE="">';
+ }
+%>
+<%=
+ if ( scalar(@$pops) ) {
+ $OUT .= '<TR><TD ALIGN="right">Access number</TD><TD>'.
+ popselector($popnum). '</TD></TR>';
+ } else {
+ $OUT .= popselector($popnum);
+ }
+%>
+</TABLE>
+<BR><BR><INPUT TYPE="submit" NAME="signup" VALUE="Signup">
+</FORM></BODY></HTML>
diff --git a/fs_selfservice/FS-SelfService/cgi/signup-freeoption.html b/fs_selfservice/FS-SelfService/cgi/signup-freeoption.html
new file mode 100755
index 000000000..40ad03c0b
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/signup-freeoption.html
@@ -0,0 +1,262 @@
+<HTML><HEAD><TITLE>ISP Signup form</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8" onUnload="myclose()">
+<script language="JavaScript"><!--
+ var mywindow = -1;
+ function myopen(filename,windowname,properties) {
+ myclose();
+ mywindow = window.open(filename,windowname,properties);
+ }
+ function myclose() {
+ if ( mywindow != -1 )
+ mywindow.close();
+ mywindow = -1
+ }
+//--></script>
+<FONT SIZE=7>ISP Signup form</FONT><BR><BR>
+<FONT SIZE="+1" COLOR="#ff0000"><%= $error %></FONT>
+<FORM NAME="OneTrueForm" ACTION="<%= $self_url %>" METHOD=POST onSubmit="document.OneTrueForm.signup.disabled=true">
+<INPUT TYPE="hidden" NAME="magic" VALUE="process">
+<INPUT TYPE="hidden" NAME="ref" VALUE="<%= $referral_custnum %>">
+<INPUT TYPE="hidden" NAME="ss" VALUE="">
+Where did you hear about our service? <SELECT NAME="refnum">
+<%=
+ $OUT .= '<OPTION VALUE="">' unless $refnum;
+ foreach my $part_referral ( @{$init_data->{'part_referral'}} ) {
+ $OUT .= '<OPTION VALUE="'. $part_referral->{'refnum'}. '"';
+ $OUT .= ' SELECTED' if $part_referral->{'refnum'} eq $refnum;
+ $OUT .= '>'. $part_referral->{'referral'};
+ }
+%>
+</SELECT><BR><BR>
+Contact Information
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Contact name<BR>(last, first)</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="last" VALUE="<%= $last %>">,
+ <INPUT TYPE="text" NAME="first" VALUE="<%= $first %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Company</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="company" SIZE=70 VALUE="<%= $company %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Address</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address1" SIZE=70 VALUE="<%= $address1 %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">&nbsp;</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address2" SIZE=70 VALUE="<%= $address2 %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>City</TH>
+ <TD><INPUT TYPE="text" NAME="city" VALUE="<%= $city %>"></TD>
+ <TH ALIGN="right"><font color="#ff0000">*</font>State/Country</TH>
+ <TD>
+ <%=
+ ($county_html, $state_html, $country_html) =
+ regionselector( $county, $state, $country );
+
+ "$county_html $state_html";
+ %>
+ </TD>
+ <TH><font color="#ff0000">*</font>Zip</TH>
+ <TD><INPUT TYPE="text" NAME="zip" SIZE=10 VALUE="<%= $zip %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Country</TH>
+ <TD><%= $country_html %></TD>
+<TR>
+ <TD ALIGN="right">Day Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="daytime" VALUE="<%= $daytime %>" SIZE=18></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Night Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="night" VALUE="<%= $night %>" SIZE=18></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Fax</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="fax" VALUE="<%= $fax %>" SIZE=12></TD>
+</TR>
+</TABLE><font color="#ff0000">*</font> required fields<BR>
+<BR>
+<%=
+ my $first_payby = $packages->[0]{'payby'}[0];
+ unless ( grep { scalar( @{$_->{'payby'}} ) > 1
+ || $_->{'payby'}->[0] ne $first_payby
+ } @$packages
+ ) {
+ @payby = ( $first_payby );
+ }
+
+ unless ( scalar(@payby) == 1 && $payby[0] eq 'BILL' ) {
+
+ $OUT .= ' Billing information
+ <TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+ <TR><TD>
+ <INPUT TYPE="checkbox" NAME="invoicing_list_POST" VALUE="POST"';
+
+ my @invoicing_list = split(', ', $invoicing_list );
+
+ $OUT .= ' CHECKED'
+ if ! @invoicing_list || grep { $_ eq 'POST' } @invoicing_list;
+
+ $OUT .= '> Postal mail invoice
+ </TD></TR>
+ <TR><TD>Email invoice
+ <INPUT TYPE="text" NAME="invoicing_list" VALUE="'
+ .join(', ', grep { $_ ne 'POST' } split(', ', $invoicing_list ) ).
+ '"></TD></TR>';
+
+ $OUT .= '<TR><TD>Billing type</TD></TR>'
+ if scalar(@payby) > 1;
+
+ $OUT .= '</TABLE>';
+
+ } else {
+ $OUT .= '<INPUT TYPE="hidden" NAME="invoicing_list" VALUE="">
+ <INPUT TYPE="hidden" NAME="invoicing_list_POST" VALUE="">';
+ }
+
+%>
+
+<TABLE BGCOLOR="#c0c0c0" BORDER=1 WIDTH="100%">
+<TR>
+
+ <%=
+
+ my $cardselect = '<SELECT NAME="CARD_type"><OPTION></OPTION>';
+ my %types = (
+ 'VISA' => 'VISA card',
+ 'MasterCard' => 'MasterCard',
+ 'Discover' => 'Discover card',
+ 'American Express' => 'American Express card',
+ );
+ foreach ( keys %types ) {
+ $selected = $cgi->param('CARD_type') eq $types{$_} ? 'SELECTED' : '';
+ $cardselect .= qq!<OPTION $selected VALUE="$types{$_}">$_</OPTION>!;
+ }
+ $cardselect .= '</SELECT>';
+
+ my %payby = (
+ 'CARD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("CARD"). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="">!,
+ 'DCRD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("DCRD"). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="">!,
+ 'CHEK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="">!,
+ 'DCHK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="">!,
+ 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+ 'BILL' => <<'END',
+<INPUT TYPE="hidden" NAME="BILL_payinfo" VALUE="">
+<INPUT TYPE="hidden" NAME="BILL_month" VALUE="12">
+<INPUT TYPE="hidden" NAME="BILL_year" VALUE="2037">
+<INPUT TYPE="hidden" NAME="BILL_payname" VALUE="">
+END
+ 'COMP' => qq!Complimentary<BR><font color="#ff0000">*</font>Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE=""><BR><font color="#ff0000">*</font>Exp !. expselect("COMP"),
+ 'PREPAY' => qq!Prepaid card<BR><font color="#ff0000">*</font><INPUT TYPE="text" NAME="PREPAY_payinfo" VALUE="" MAXLENGTH=80>!,
+ );
+
+ if ( $init_data->{'cvv_enabled'} ) {
+ foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5
+ $payby{$payby} .= qq!<BR>CVV2&nbsp;(<A HREF="javascript:myopen('cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>)&nbsp;<INPUT TYPE="text" NAME=${payby}_paycvv VALUE="" SIZE=4 MAXLENGTH=4>!;
+ }
+ }
+
+ my( $account, $aba ) = split('@', $payinfo);
+ my %paybychecked = (
+ 'CARD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("CARD", $paydate). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="$payname">!,
+ 'DCRD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("DCRD", $paydate). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="$payname">!,
+ 'CHEK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="$account" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="$payname">!,
+ 'DCHK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="$account" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="$payname">!,
+ 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="$payinfo" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+ 'BILL' => <<'END',
+<INPUT TYPE="hidden" NAME="BILL_payinfo" VALUE="">
+<INPUT TYPE="hidden" NAME="BILL_month" VALUE="12">
+<INPUT TYPE="hidden" NAME="BILL_year" VALUE="2037">
+<INPUT TYPE="hidden" NAME="BILL_payname" VALUE="">
+END
+
+ 'COMP' => qq!Complimentary<BR><font color="#ff0000">*</font>Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE="$payinfo"><BR><font color="#ff0000">*</font>Exp !. expselect("COMP", $paydate),
+ 'PREPAY' => qq!Prepaid card<BR><font color="#ff0000">*</font><INPUT TYPE="text" NAME="PREPAY_payinfo" VALUE="$payinfo" MAXLENGTH=80>!,
+ );
+
+ if ( $init_data->{'cvv_enabled'} ) {
+ foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5
+ $paybychecked{$payby} .= qq!<BR>CVV2&nbsp;(<A HREF="javascript:myopen('cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>)&nbsp;<INPUT TYPE="text" NAME=${payby}_paycvv VALUE="$paycvv" SIZE=4 MAXLENGTH=4>!;
+ }
+ }
+
+ for (@payby) {
+ if ( scalar(@payby) == 1) {
+ $OUT .= '<TD VALIGN=TOP>'.
+ qq!<INPUT TYPE="hidden" NAME="payby" VALUE="$_">!.
+ "$paybychecked{$_}</TD>";
+ } else {
+ $OUT .= qq!<TD VALIGN=TOP><INPUT TYPE="radio" NAME="payby" VALUE="$_"!;
+ if ($payby eq $_) {
+ $OUT .= qq! CHECKED> $paybychecked{$_}</TD>!;
+ } else {
+ $OUT .= qq!> $payby{$_}</TD>!;
+ }
+
+ }
+ }
+ %>
+
+</TR></TABLE>
+<%= unless ( scalar(@payby) == 1 && $payby[0] eq 'BILL' ) {
+ $OUT .= '<font color="#ff0000">*</font> required fields for each billing type';
+ }
+ '';
+%>
+<BR><BR>First package
+<INPUT TYPE="hidden" NAME="promo_code" VALUE="<%= $cgi->param('promo_code') %>"><TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TD COLSPAN=2><SELECT NAME="pkgpart">
+
+ <%=
+ $OUT .= '<OPTION VALUE="">(none)' unless scalar(@$packages) == 1;
+ foreach my $package ( @{$packages} ) {
+ $OUT .= '<OPTION VALUE="'. $package->{'pkgpart'}. '"';
+ $OUT .= ' SELECTED'
+ if ( $pkgpart && $package->{'pkgpart'} == $pkgpart )
+ || scalar(@$packages) == 1;
+ $OUT .= '>'. $package->{'pkg'};
+ }
+ %>
+
+ </SELECT></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Username</TD>
+ <TD><INPUT TYPE="text" NAME="username" VALUE="<%= $username %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password" VALUE="<%= $password %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Re-enter Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password2" VALUE="<%= $password2 %>"></TD>
+</TR>
+<%=
+ if ( $init_data->{'security_phrase'} ) {
+ $OUT .= <<ENDOUT;
+<TR>
+ <TD ALIGN="right">Security Phrase</TD>
+ <TD><INPUT TYPE="text" NAME="sec_phrase" VALUE="$sec_phrase">
+ </TD>
+</TR>
+ENDOUT
+ } else {
+ $OUT .= '<INPUT TYPE="hidden" NAME="sec_phrase" VALUE="">';
+ }
+%>
+<%=
+ if ( scalar(@$pops) ) {
+ $OUT .= '<TR><TD ALIGN="right">Access number</TD><TD>'.
+ popselector($popnum). '</TD></TR>';
+ } else {
+ $OUT .= popselector($popnum);
+ }
+%>
+</TABLE>
+<BR><BR><INPUT TYPE="submit" NAME="signup" VALUE="Signup">
+</FORM></BODY></HTML>
diff --git a/fs_selfservice/FS-SelfService/cgi/signup-snarf.html b/fs_selfservice/FS-SelfService/cgi/signup-snarf.html
new file mode 100755
index 000000000..d167efbf9
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/signup-snarf.html
@@ -0,0 +1,228 @@
+<HTML><HEAD><TITLE>ISP Signup form</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8" onUnload="myclose()">
+<script language="JavaScript"><!--
+ var mywindow = -1;
+ function myopen(filename,windowname,properties) {
+ myclose();
+ mywindow = window.open(filename,windowname,properties);
+ }
+ function myclose() {
+ if ( mywindow != -1 )
+ mywindow.close();
+ mywindow = -1
+ }
+//--></script>
+<FONT SIZE=7>ISP Signup form</FONT><BR><BR>
+<FONT SIZE="+1" COLOR="#ff0000"><%= $error %></FONT>
+<FORM ACTION="<%= $self_url %>" METHOD=POST>
+<INPUT TYPE="hidden" NAME="magic" VALUE="process">
+<INPUT TYPE="hidden" NAME="ref" VALUE="<%= $referral_custnum %>">
+<INPUT TYPE="hidden" NAME="ss" VALUE="">
+Contact Information
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Contact name<BR>(last, first)</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="last" VALUE="<%= $last %>">,
+ <INPUT TYPE="text" NAME="first" VALUE="<%= $first %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Company</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="company" SIZE=70 VALUE="<%= $company %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Address</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address1" SIZE=70 VALUE="<%= $address1 %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">&nbsp;</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address2" SIZE=70 VALUE="<%= $address2 %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>City</TH>
+ <TD><INPUT TYPE="text" NAME="city" VALUE="<%= $city %>"></TD>
+ <TH ALIGN="right"><font color="#ff0000">*</font>State/Country</TH>
+ <TD>
+ <%=
+ ($county_html, $state_html, $country_html) =
+ regionselector( $county, $state, $country );
+
+ "$county_html $state_html";
+ %>
+ </TD>
+ <TH><font color="#ff0000">*</font>Zip</TH>
+ <TD><INPUT TYPE="text" NAME="zip" SIZE=10 VALUE="<%= $zip %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Country</TH>
+ <TD><%= $country_html %></TD>
+<TR>
+ <TD ALIGN="right">Day Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="daytime" VALUE="<%= $daytime %>" SIZE=18></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Night Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="night" VALUE="<%= $night %>" SIZE=18></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Fax</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="fax" VALUE="<%= $fax %>" SIZE=12></TD>
+</TR>
+</TABLE><font color="#ff0000">*</font> required fields<BR>
+<BR>Billing information<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR><TD>
+
+ <%=
+ $OUT .= '<INPUT TYPE="checkbox" NAME="invoicing_list_POST" VALUE="POST"';
+ my @invoicing_list = split(', ', $invoicing_list );
+ $OUT .= ' CHECKED'
+ if ! @invoicing_list || grep { $_ eq 'POST' } @invoicing_list;
+ $OUT .= '>';
+ %>
+
+ Postal mail invoice
+</TD></TR>
+<TR><TD>Email invoice <INPUT TYPE="text" NAME="invoicing_list" VALUE="<%= join(', ', grep { $_ ne 'POST' } split(', ', $invoicing_list ) ) %>">
+</TD></TR>
+<%= scalar(@payby) > 1 ? '<TR><TD>Billing type</TD></TR>' : '' %>
+</TABLE>
+<TABLE BGCOLOR="#c0c0c0" BORDER=1 WIDTH="100%">
+<TR>
+
+ <%=
+
+ my $cardselect = '<SELECT NAME="CARD_type"><OPTION></OPTION>';
+ my %types = (
+ 'VISA' => 'VISA card',
+ 'MasterCard' => 'MasterCard',
+ 'Discover' => 'Discover card',
+ 'American Express' => 'American Express card',
+ );
+ foreach ( keys %types ) {
+ $selected = $cgi->param('CARD_type') eq $types{$_} ? 'SELECTED' : '';
+ $cardselect .= qq!<OPTION $selected VALUE="$types{$_}">$_</OPTION>!;
+ }
+ $cardselect .= '</SELECT>';
+
+ my %payby = (
+ 'CARD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("CARD"). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="">!,
+ 'DCRD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("DCRD"). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="">!,
+ 'CHEK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="">!,
+ 'DCHK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="">!,
+ 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+ 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE=""><BR><font color="#ff0000">*</font>Exp !. expselect("BILL", "12-2037"). qq!<BR><font color="#ff0000">*</font>Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="Accounts Payable">!,
+ 'COMP' => qq!Complimentary<BR><font color="#ff0000">*</font>Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE=""><BR><font color="#ff0000">*</font>Exp !. expselect("COMP"),
+ 'PREPAY' => qq!Prepaid card<BR><font color="#ff0000">*</font><INPUT TYPE="text" NAME="PREPAY_payinfo" VALUE="" MAXLENGTH=80>!,
+ );
+
+ if ( $init_data->{'cvv_enabled'} ) {
+ foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5
+ $payby{$payby} .= qq!<BR>CVV2&nbsp;(<A HREF="javascript:myopen('cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>)&nbsp;<INPUT TYPE="text" NAME=${payby}_paycvv VALUE="" SIZE=4 MAXLENGTH=4>!;
+ }
+ }
+
+ my( $account, $aba ) = split('@', $payinfo);
+ my %paybychecked = (
+ 'CARD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("CARD", $paydate). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="$payname">!,
+ 'DCRD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("DCRD", $paydate). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="$payname">!,
+ 'CHEK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="$account" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="$payname">!,
+ 'DCHK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="$account" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="$payname">!,
+ 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="$payinfo" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+ 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE="$payinfo"><BR><font color="#ff0000">*</font>Exp !. expselect("BILL", $paydate). qq!<BR><font color="#ff0000">*</font>Attention<BR><INPUT TYPE="text" NAME="BILL_payname" VALUE="$payname">!,
+ 'COMP' => qq!Complimentary<BR><font color="#ff0000">*</font>Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE="$payinfo"><BR><font color="#ff0000">*</font>Exp !. expselect("COMP", $paydate),
+ 'PREPAY' => qq!Prepaid card<BR><font color="#ff0000">*</font><INPUT TYPE="text" NAME="PREPAY_payinfo" VALUE="$payinfo" MAXLENGTH=80>!,
+ );
+
+ if ( $init_data->{'cvv_enabled'} ) {
+ foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5
+ $paybychecked{$payby} .= qq!<BR>CVV2&nbsp;(<A HREF="javascript:myopen('cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>)&nbsp;<INPUT TYPE="text" NAME=${payby}_paycvv VALUE="$paycvv" SIZE=4 MAXLENGTH=4>!;
+ }
+ }
+
+ for (@payby) {
+ if ( scalar(@payby) == 1) {
+ $OUT .= '<TD VALIGN=TOP>'.
+ qq!<INPUT TYPE="hidden" NAME="payby" VALUE="$_">!.
+ "$paybychecked{$_}</TD>";
+ } else {
+ $OUT .= qq!<TD VALIGN=TOP><INPUT TYPE="radio" NAME="payby" VALUE="$_"!;
+ if ($payby eq $_) {
+ $OUT .= qq! CHECKED> $paybychecked{$_}</TD>!;
+ } else {
+ $OUT .= qq!> $payby{$_}</TD>!;
+ }
+
+ }
+ }
+ %>
+
+</TR></TABLE><font color="#ff0000">*</font> required fields for each billing type
+<BR><BR>First package
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TD COLSPAN=2><SELECT NAME="pkgpart"><OPTION VALUE="">(none)
+
+ <%=
+ foreach my $package ( @{$packages} ) {
+ $OUT .= '<OPTION VALUE="'. $package->{'pkgpart'}. '"';
+ $OUT .= ' SELECTED' if $pkgpart && $package->{'pkgpart'} == $pkgpart;
+ $OUT .= '>'. $package->{'pkg'};
+ }
+ %>
+
+ </SELECT></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Username</TD>
+ <TD><INPUT TYPE="text" NAME="username" VALUE="<%= $username %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password" VALUE="<%= $password %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Re-enter Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password2" VALUE="<%= $password2 %>"></TD>
+</TR>
+<%=
+ if ( $init_data->{'security_phrase'} ) {
+ $OUT .= <<ENDOUT;
+<TR>
+ <TD ALIGN="right">Security Phrase</TD>
+ <TD><INPUT TYPE="text" NAME="sec_phrase" VALUE="$sec_phrase">
+ </TD>
+</TR>
+ENDOUT
+ } else {
+ $OUT .= '<INPUT TYPE="hidden" NAME="sec_phrase" VALUE="">';
+ }
+%>
+<%=
+ if ( scalar(@$pops) ) {
+ $OUT .= '<TR><TD ALIGN="right">Access number</TD><TD>'.
+ popselector($popnum). '</TD></TR>';
+ } else {
+ $OUT .= popselector($popnum);
+ }
+%>
+</TABLE>
+<BR><BR>Enter up to ten external accounts from which to retrieve email
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TH ALIGN="left">Mail server</TH>
+ <TH ALIGN="left">Username</TH>
+ <TH ALIGN="left">Password</TH>
+</TR>
+<%=
+ for my $num ( 1..10 ) {
+ no strict 'vars';
+ $OUT .= qq!<TR><TD><INPUT TYPE="text" NAME="snarf_machine$num" VALUE="${"snarf_machine$num"}"></TD>!.
+ qq!<INPUT TYPE="hidden" NAME="snarf_protocol$num" VALUE="pop3">!.
+ qq!<TD><INPUT TYPE="text" NAME="snarf_username$num" VALUE="${"snarf_username$num"}"></TD>!.
+ qq!<TD><INPUT TYPE="password" NAME="snarf_password$num" VALUE="${"snarf_password$num"}"></TD>!.
+ qq!</TR>!;
+ }
+%>
+</TABLE>
+
+<BR><BR><INPUT TYPE="submit" VALUE="Signup">
+</FORM></BODY></HTML>
diff --git a/fs_selfservice/FS-SelfService/cgi/signup.cgi b/fs_selfservice/FS-SelfService/cgi/signup.cgi
new file mode 100755
index 000000000..47857f0a7
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/signup.cgi
@@ -0,0 +1,387 @@
+#!/usr/bin/perl -T
+#!/usr/bin/perl -Tw
+
+use strict;
+use vars qw( @payby $cgi $init_data
+ $self_url $error $agentnum
+
+ $ieak_file $ieak_template
+ $signup_html $signup_template
+ $success_html $success_template
+ $decline_html $decline_template
+ );
+
+use subs qw( print_form print_okay print_decline
+ success_default decline_default
+ );
+use CGI;
+#use CGI::Carp qw(fatalsToBrowser);
+use Text::Template;
+use Business::CreditCard;
+use HTTP::BrowserDetect;
+use FS::SelfService qw( signup_info new_customer );
+
+#acceptable payment methods
+#
+#@payby = qw( CARD BILL COMP );
+#@payby = qw( CARD BILL );
+#@payby = qw( CARD );
+@payby = qw( CARD PREPAY );
+
+$ieak_file = '/usr/local/freeside/ieak.template';
+$signup_html = -e 'signup.html'
+ ? 'signup.html'
+ : '/usr/local/freeside/signup.html';
+$success_html = -e 'success.html'
+ ? 'success.html'
+ : '/usr/local/freeside/success.html';
+$decline_html = -e 'decline.html'
+ ? 'decline.html'
+ : '/usr/local/freeside/decline.html';
+
+
+if ( -e $ieak_file ) {
+ my $ieak_txt = Text::Template::_load_text($ieak_file)
+ or die $Text::Template::ERROR;
+ $ieak_txt =~ /^(.*)$/s; #untaint the template source - it's trusted
+ $ieak_txt = $1;
+ $ieak_txt =~ s/\r//g; # don't double \r on old templates
+ $ieak_txt =~ s/\n/\r\n/g;
+ $ieak_template = new Text::Template ( TYPE => 'STRING', SOURCE => $ieak_txt )
+ or die $Text::Template::ERROR;
+} else {
+ $ieak_template = '';
+}
+
+$agentnum = '';
+if ( -e $signup_html ) {
+ my $signup_txt = Text::Template::_load_text($signup_html)
+ or die $Text::Template::ERROR;
+ $signup_txt =~ /^(.*)$/s; #untaint the template source - it's trusted
+ $signup_txt = $1;
+ $signup_template = new Text::Template ( TYPE => 'STRING',
+ SOURCE => $signup_txt,
+ DELIMITERS => [ '<%=', '%>' ]
+ )
+ or die $Text::Template::ERROR;
+ if ( $signup_txt =~
+ /<\s*INPUT TYPE="?hidden"?\s+NAME="?agentnum"?\s+VALUE="?(\d+)"?\s*\/?\s*>/si
+ ) {
+ $agentnum = $1;
+ }
+} else {
+ #too much maintenance hassle to keep in this file
+ die "can't find ./signup.html or /usr/local/freeside/signup.html";
+ #$signup_template = new Text::Template ( TYPE => 'STRING',
+ # SOURCE => &signup_default,
+ # DELIMITERS => [ '<%=', '%>' ]
+ # )
+ # or die $Text::Template::ERROR;
+}
+
+if ( -e $success_html ) {
+ my $success_txt = Text::Template::_load_text($success_html)
+ or die $Text::Template::ERROR;
+ $success_txt =~ /^(.*)$/s; #untaint the template source - it's trusted
+ $success_txt = $1;
+ $success_template = new Text::Template ( TYPE => 'STRING',
+ SOURCE => $success_txt,
+ DELIMITERS => [ '<%=', '%>' ],
+ )
+ or die $Text::Template::ERROR;
+} else {
+ $success_template = new Text::Template ( TYPE => 'STRING',
+ SOURCE => &success_default,
+ DELIMITERS => [ '<%=', '%>' ],
+ )
+ or die $Text::Template::ERROR;
+}
+
+if ( -e $decline_html ) {
+ my $decline_txt = Text::Template::_load_text($decline_html)
+ or die $Text::Template::ERROR;
+ $decline_txt =~ /^(.*)$/s; #untaint the template source - it's trusted
+ $decline_txt = $1;
+ $decline_template = new Text::Template ( TYPE => 'STRING',
+ SOURCE => $decline_txt,
+ DELIMITERS => [ '<%=', '%>' ],
+ )
+ or die $Text::Template::ERROR;
+} else {
+ $decline_template = new Text::Template ( TYPE => 'STRING',
+ SOURCE => &decline_default,
+ DELIMITERS => [ '<%=', '%>' ],
+ )
+ or die $Text::Template::ERROR;
+}
+
+$cgi = new CGI;
+
+$init_data = signup_info( 'agentnum' => $agentnum,
+ 'promo_code' => scalar($cgi->param('promo_code')),
+ 'reg_code' => uc(scalar($cgi->param('reg_code'))),
+ );
+
+if ( ( defined($cgi->param('magic')) && $cgi->param('magic') eq 'process' )
+ || ( defined($cgi->param('action')) && $cgi->param('action') eq 'process_signup' )
+ ) {
+
+ $error = '';
+
+ $cgi->param('agentnum', $agentnum) if $agentnum;
+ $cgi->param('reg_code', uc(scalar($cgi->param('reg_code'))) );
+
+ #false laziness w/agent.cgi, identical except for agentnum
+ my $payby = $cgi->param('payby');
+ if ( $payby eq 'CHEK' || $payby eq 'DCHK' ) {
+ #$payinfo = join('@', map { $cgi->param( $payby. "_payinfo$_" ) } (1,2) );
+ $cgi->param('payinfo' => $cgi->param($payby. '_payinfo1'). '@'.
+ $cgi->param($payby. '_payinfo2')
+ );
+ } else {
+ $cgi->param('payinfo' => $cgi->param( $payby. '_payinfo' ) );
+ }
+ $cgi->param('paydate' => $cgi->param( $payby. '_month' ). '-'.
+ $cgi->param( $payby. '_year' )
+ );
+ $cgi->param('payname' => $cgi->param( $payby. '_payname' ) );
+ $cgi->param('paycvv' => defined $cgi->param( $payby. '_paycvv' )
+ ? $cgi->param( $payby. '_paycvv' )
+ : ''
+ );
+ $cgi->param('paytype' => defined $cgi->param( $payby. '_paytype' )
+ ? $cgi->param( $payby. '_paytype' )
+ : ''
+ );
+ $cgi->param('paystate' => defined $cgi->param( $payby. '_paystate' )
+ ? $cgi->param( $payby. '_paystate' )
+ : ''
+ );
+
+ if ( $cgi->param('invoicing_list') ) {
+ $cgi->param('invoicing_list' => $cgi->param('invoicing_list'). ', POST')
+ if $cgi->param('invoicing_list_POST');
+ } else {
+ $cgi->param('invoicing_list' => 'POST' );
+ }
+
+ #if ( $svc_x eq 'svc_acct' ) {
+ if ( $cgi->param('_password') ne $cgi->param('_password2') ) {
+ $error = $init_data->{msgcat}{passwords_dont_match}; #msgcat
+ $cgi->param('_password', '');
+ $cgi->param('_password2', '');
+ }
+
+ if ( $payby =~ /^(CARD|DCRD)$/ && $cgi->param('CARD_type') ) {
+ my $payinfo = $cgi->param('payinfo');
+ $payinfo =~ s/\D//g;
+
+ $payinfo =~ /^(\d{13,16})$/
+ or $error ||= $init_data->{msgcat}{invalid_card}; #. $self->payinfo;
+ $payinfo = $1;
+ validate($payinfo)
+ or $error ||= $init_data->{msgcat}{invalid_card}; #. $self->payinfo;
+ cardtype($payinfo) eq $cgi->param('CARD_type')
+ or $error ||= $init_data->{msgcat}{not_a}. $cgi->param('CARD_type');
+ }
+
+ if ($init_data->{emailinvoiceonly} && (length $cgi->param('invoicing_list') < 1)) {
+ $error ||= $init_data->{msgcat}{illegal_or_empty_text};
+ }
+
+ my $rv = '';
+ unless ( $error ) {
+ $rv = new_customer( {
+ ( map { $_ => scalar($cgi->param($_)) }
+ qw( last first ss company
+ address1 address2 city county state zip country
+ daytime night fax stateid stateid_state
+
+ ship_last ship_first ship_company
+ ship_address1 ship_address2 ship_city ship_county ship_state
+ ship_zip ship_country
+ ship_daytime ship_night ship_fax
+
+ payby payinfo paycvv paydate payname paystate paytype
+ invoicing_list referral_custnum promo_code reg_code
+ pkgpart refnum agentnum
+ username sec_phrase _password popnum
+ countrycode phonenum sip_password pin
+ ),
+ grep { /^snarf_/ } $cgi->param
+ ),
+ 'payip' => $cgi->remote_host(),
+ } );
+ $error = $rv->{'error'};
+ }
+ #eslaf
+
+ if ( $error eq '_decline' ) {
+ print_decline();
+ } elsif ( $error ) {
+ #fudge the snarf info
+ no strict 'refs';
+ ${$_} = $cgi->param($_) foreach grep { /^snarf_/ } $cgi->param;
+ print_form();
+ } else {
+ print_okay(
+ 'pkgpart' => scalar($cgi->param('pkgpart')),
+ %$rv,
+ );
+ }
+
+} else {
+ $error = '';
+ print_form;
+}
+
+sub print_form {
+
+ $error = "Error: $error" if $error;
+
+ my $r = {
+ $cgi->Vars,
+ %{$init_data},
+ 'error' => $error,
+ };
+
+ $r->{pkgpart} ||= $r->{default_pkgpart};
+
+ $r->{referral_custnum} = $r->{'ref'};
+ #$cgi->delete('ref');
+ #$cgi->delete('init_popstate');
+ $r->{self_url} = $cgi->self_url;
+
+ print $cgi->header( '-expires' => 'now' ),
+ $signup_template->fill_in( PACKAGE => 'FS::SelfService::_signupcgi',
+ HASH => $r
+ );
+}
+
+sub print_decline {
+ print $cgi->header( '-expires' => 'now' ),
+ $decline_template->fill_in();
+}
+
+sub print_okay {
+ my %param = @_;
+ my $user_agent = new HTTP::BrowserDetect $ENV{HTTP_USER_AGENT};
+
+ my( $username, $password ) = ( '', '' );
+ my( $countrycode, $phonenum, $sip_password, $pin ) = ( '', '', '', '' );
+
+ my $svc_x = $param{signup_service} || 'svc_acct'; #just in case
+ if ( $svc_x eq 'svc_acct' ) {
+
+ $cgi->param('username') =~ /^(.+)$/
+ or die "fatal: invalid username got past FS::SelfService::new_customer";
+ $username = $1;
+ $cgi->param('_password') =~ /^(.+)$/
+ or die "fatal: invalid password got past FS::SelfService::new_customer";
+ $password = $1;
+
+ } elsif ( $svc_x eq 'svc_phone' ) {
+
+ $countrycode = $param{countrycode};
+ $phonenum = $param{phonenum};
+ $sip_password = $param{sip_password};
+ $pin = $param{pin};
+
+ } else {
+ die "unknown signup service $svc_x";
+ }
+
+ ( $cgi->param('first'). ' '. $cgi->param('last') ) =~ /^(.*)$/
+ or die "fatal: invalid email_name got past FS::SelfService::new_customer";
+ my $email_name = $1; #global for template
+
+ #my %pop = ();
+ my %popnum2pop = ();
+ foreach ( @{ $init_data->{'svc_acct_pop'} } ) {
+ #push @{ $pop{ $_->{state} }->{ $_->{ac} } }, $_;
+ $popnum2pop{$_->{popnum}} = $_;
+ }
+
+ my( $ac, $exch, $loc);
+ my $pop = $popnum2pop{$cgi->param('popnum')};
+ #or die "fatal: invalid popnum got past FS::SelfService::new_customer";
+ if ( $pop ) {
+ ( $ac, $exch, $loc ) = ( $pop->{'ac'}, $pop->{'exch'}, $pop->{'loc'} );
+ } else {
+ ( $ac, $exch, $loc ) = ( '', '', ''); #presumably you're not using them.
+ }
+
+ #global for template
+ my $part_pkg = ( grep { $_->{'pkgpart'} eq $param{'pkgpart'} }
+ @{ $init_data->{'part_pkg'} }
+ )[0];
+ my $pkg = $part_pkg->{'pkg'};
+
+ if ( $ieak_template && $user_agent->windows && $user_agent->ie ) {
+
+ #send an IEAK config
+ print $cgi->header('application/x-Internet-signup'),
+ $ieak_template->fill_in();
+
+ } else { #send a simple confirmation
+
+ print $cgi->header( '-expires' => 'now' ),
+ $success_template->fill_in( HASH => {
+
+ email_name => $email_name,
+ pkg => $pkg,
+ part_pkg => \$part_pkg,
+
+ signup_service => $svc_x,
+
+ #for svc_acct
+ username => $username,
+ password => $password,
+ _password => $password,
+ ac => $ac, #for dialup POP
+ exch => $exch, #
+ loc => $loc, #
+
+ #for svc_phone
+ countrycode => $countrycode,
+ phonenum => $phonenum,
+ sip_password => $sip_password,
+ pin => $pin,
+
+ });
+ }
+
+}
+
+sub success_default { #html to use if you don't specify a success file
+ <<'END';
+<HTML><HEAD><TITLE>Signup successful</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=7>Signup successful</FONT><BR><BR>
+Thanks for signing up!
+<BR><BR>
+Signup information for <%= $email_name %>:
+<BR><BR>
+Username: <%= $username %><BR>
+Password: <%= $password %><BR>
+Access number: (<%= $ac %>) / <%= $exch %> - <%= $local %><BR>
+Package: <%= $pkg %><BR>
+</BODY></HTML>
+END
+}
+
+sub decline_default { #html to use if there is a decline
+ <<'END';
+<HTML><HEAD><TITLE>Processing error</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=7>Processing error</FONT><BR><BR>
+There has been an error processing your account. Please contact customer
+support.
+</BODY></HTML>
+END
+}
+
+# subs for the templates...
+
+package FS::SelfService::_signupcgi;
+use HTML::Entities;
+use FS::SelfService qw(regionselector expselect popselector didselector);
+
diff --git a/fs_selfservice/FS-SelfService/cgi/signup.html b/fs_selfservice/FS-SelfService/cgi/signup.html
new file mode 100755
index 000000000..1b97121c6
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/signup.html
@@ -0,0 +1,424 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+<HEAD>
+ <TITLE><%= $agent || ( $signup_service eq 'svc_phone' ? 'ITSP' : 'ISP' ) %> Signup form</TITLE>
+ <%= $head %>
+</HEAD>
+<BODY BGCOLOR="<%= $body_bgcolor || '#e8e8e8' %>" onUnload="myclose()">
+
+<script type="text/javascript">
+ var mywindow = -1;
+ function myopen(filename,windowname,properties) {
+ myclose();
+ mywindow = window.open(filename,windowname,properties);
+ }
+ function myclose() {
+ if ( mywindow != -1 )
+ mywindow.close();
+ mywindow = -1
+ }
+</script>
+
+<%= $OUT .= $body_header
+ || '<FONT SIZE=7>'.
+ ( $agent || ( $signup_service eq 'svc_phone' ? 'ITSP' : 'ISP' ) ).
+ ' Signup form</FONT><BR><BR>';
+%>
+
+<FONT SIZE="+1" COLOR="#ff0000"><%= $error %></FONT>
+
+<FORM NAME="OneTrueForm" ACTION="<%= $self_url %>" METHOD=POST onSubmit="document.OneTrueForm.signup.disabled=true">
+<INPUT TYPE="hidden" NAME="session" VALUE="<%= $session_id %>">
+<INPUT TYPE="hidden" NAME="action" VALUE="process_signup">
+<INPUT TYPE="hidden" NAME="referral_custnum" VALUE="<%= $referral_custnum %>">
+<INPUT TYPE="hidden" NAME="ss" VALUE="">
+<input type="hidden" name="payby">
+<%=
+ $OUT = join("\n",map { my $method = $_ ; map { qq|<input type="hidden" name="${method}_$_" />| } qw / payinfo payinfo1 payinfo2 payname paystate paytype paycvv month year type / } @payby);
+%>
+
+<%=
+ $OUT = join("\n", map { qq|<input type="hidden" name="$_" />| } qw / promo_code reg_code pkgpart username _password _password2 sec_phrase popnum countrycode phonenum sip_password pin / );
+%>
+
+Where did you hear about our service? <SELECT NAME="refnum">
+<%=
+ $OUT .= '<OPTION VALUE="">' unless $refnum;
+ foreach my $part_referral ( @part_referral ) {
+ $OUT .= '<OPTION VALUE="'. $part_referral->{'refnum'}. '"';
+ $OUT .= ' SELECTED' if $part_referral->{'refnum'} eq $refnum;
+ $OUT .= '>'. $part_referral->{'referral'};
+ }
+%>
+</SELECT><BR><BR>
+Contact Information
+<TABLE BGCOLOR="<%= $box_bgcolor || '#c0c0c0' %>" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Contact name<BR>(last, first)</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="last" VALUE="<%= $last %>">,
+ <INPUT TYPE="text" NAME="first" VALUE="<%= $first %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Company</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="company" SIZE=70 VALUE="<%= $company %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Address</TH>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address1" SIZE=70 VALUE="<%= $address1 %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">&nbsp;</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="address2" SIZE=70 VALUE="<%= $address2 %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>City</TH>
+ <TD><INPUT TYPE="text" NAME="city" VALUE="<%= $city %>"></TD>
+ <TH ALIGN="right"><font color="#ff0000">*</font>State/Country</TH>
+ <TD>
+ <%=
+ ($county_html, $state_html, $country_html) =
+ regionselector( {
+ selected_county => $county,
+ selected_state => $state,
+ selected_country => $country,
+ default_state => $statedefault,
+ default_country => $countrydefault,
+ locales => \@cust_main_county,
+ } );
+
+ "$county_html $state_html";
+ %>
+ </TD>
+ <TH><font color="#ff0000">*</font>Zip</TH>
+ <TD><INPUT TYPE="text" NAME="zip" SIZE=10 VALUE="<%= $zip %>"></TD>
+</TR>
+<TR>
+ <TH ALIGN="right"><font color="#ff0000">*</font>Country</TH>
+ <TD><%= $country_html %></TD>
+<TR>
+ <TD ALIGN="right">Day Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="daytime" VALUE="<%= $daytime %>" SIZE=18></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Night Phone</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="night" VALUE="<%= $night %>" SIZE=18></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Fax</TD>
+ <TD COLSPAN=5><INPUT TYPE="text" NAME="fax" VALUE="<%= $fax %>" SIZE=12></TD>
+</TR>
+<%=
+ $OUT = '';
+ if ( $stateid_enabled ) {
+ my ($county_html, $state_html, $country_html) =
+ regionselector( {
+ prefix => 'stateid_',
+ default_state => $statedefault,
+ default_country => $countrydefault,
+ locales => \@cust_main_county,
+ } );
+ $OUT .= qq!<TR><TD ALIGN="right">!. $label{stateid}.'</TD>';
+ $OUT .= qq!<TD><INPUT TYPE="text" NAME="stateid" VALUE="$stateid" SIZE=12></TD>!;
+ $OUT .= qq!<TD ALIGN="right">!. $label{stateid_state} .'</TD>';
+ $OUT .="<TD COLSPAN=3>$county_html $state_html</TD></TR>";
+ }
+%>
+</TABLE><font color="#ff0000">*</font> required fields<BR>
+<BR>Billing information<TABLE BGCOLOR="<%= $box_bgcolor || '#c0c0c0' %>" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR><TD>
+
+ <%=
+ $OUT ='';
+ unless ( $emailinvoiceonly ) {
+ $OUT .= '<INPUT TYPE="checkbox" NAME="invoicing_list_POST" VALUE="POST"';
+ my @invoicing_list = split(', ', $invoicing_list );
+ $OUT .= ' CHECKED'
+ if ! @invoicing_list || grep { $_ eq 'POST' } @invoicing_list;
+ $OUT .= '> Postal mail invoice'; }
+ %>
+
+
+</TD></TR>
+<TR><TD><%= $OUT = ( $emailinvoiceonly ? q|<font color="#ff0000">*</font>| : q|| ) %> Email invoice <INPUT TYPE="text" NAME="invoicing_list" VALUE="<%= join(', ', grep { $_ ne 'POST' } split(', ', $invoicing_list ) ) %>">
+</TD></TR>
+<%= ( scalar(@payby) > 1 or 1 ) ? '<TR><TD>Billing type ' : '' %>
+<!--</TABLE>
+<TABLE BGCOLOR="#c0c0c0" BORDER=1 WIDTH="100%">
+<TR>-->
+
+ <%=
+
+ my $cardselect = '<SELECT NAME="CARD_type"><OPTION></OPTION>';
+ foreach ( keys %card_types ) {
+ $selected = $CARD_type eq $card_types{$_} ? 'SELECTED' : '';
+ $cardselect .= qq!<OPTION $selected VALUE="$card_types{$_}">$_</OPTION>!;
+ }
+ $cardselect .= '</SELECT>';
+
+ my %payby = (
+ 'CARD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="CARD_payinfo" VALUE="" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("CARD"). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="CARD_payname" VALUE="">!,
+ 'DCRD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("DCRD"). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="">!,
+ 'CHEK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="" MAXLENGTH=10><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9> Type <SELECT NAME="CHEK_paytype">!. join('', map {qq!<OPTION VALUE="$_">$_</OPTION>!} @paytypes). qq!</SELECT><BR>{$r}Bank State <INPUT TYPE="text" NAME="CHEK_paystate" VALUE="" SIZE=5 MAXLENGTH=4><INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="">!,
+ 'DCHK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="" MAXLENGTH=10> Type <SELECT NAME="DCHK_paytype">!. join('', map {qq!<OPTION VALUE="$_">$_</OPTION>!} @paytypes). qq!</SELECT><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="" SIZE=10 MAXLENGTH=9><BR>{$r}Bank State <INPUT TYPE="text" NAME="DCHK_paystate" VALUE="" SIZE=5 MAXLENGTH=4><INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="">!,
+ 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" NAME="LECB_payinfo" VALUE="" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+ 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE=""><BR><INPUT TYPE="hidden" NAME="BILL_month" VALUE="12"><INPUT TYPE="hidden" NAME="BILL_year" VALUE="2037">Attention<INPUT TYPE="text" NAME="BILL_payname" VALUE="Accounts Payable">!,
+ 'COMP' => qq!Complimentary<BR><font color="#ff0000">*</font>Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE=""><BR><font color="#ff0000">*</font>Exp !. expselect("COMP"),
+ 'PREPAY' => qq!Prepaid card<BR><font color="#ff0000">*</font><INPUT TYPE="text" NAME="PREPAY_payinfo" VALUE="" MAXLENGTH=80>!,
+ );
+
+ if ( $cvv_enabled ) {
+ foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5
+ $payby{$payby} .= qq!<TR><TD ALIGN="right">CVV2&nbsp;(<A HREF="javascript:myopen('cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>)</TD><TD><INPUT TYPE="text" NAME=${payby}_paycvv VALUE="" SIZE=4 MAXLENGTH=4></TD></TR>!;
+ }
+ }
+ if ( $paystate_enabled ) {
+ foreach my $payby ( grep { exists $payby{$_} } qw(CHEK DCHK) ) {
+ my ($county_html, $state_html, $country_html) =
+ regionselector( {
+ prefix => "${payby}_pay",
+ default_state => $statedefault,
+ default_country => $countrydefault,
+ locales => \@cust_main_county,
+ } );
+ $payby{$payby} .= "<BR>${r}Bank state $county_html $state_html";
+ }
+ }
+
+ my( $account, $aba ) = split('@', $payinfo);
+ my %paybychecked = (
+ 'CARD' => '<TABLE BGCOLOR="'. ( $box_bgcolor || '#c0c0c0' ). qq!" BORDER=0 CELLSPACING=0 WIDTH="100%"><TR><TD ALIGN="right"><font color="#ff0000">*</font> Card type</TD><TD>$cardselect</TD></TR><TR><TD ALIGN="right"><font color="#ff0000">*</font> Card number</TD><TD><INPUT TYPE="text" NAME="CARD_payinfo" VALUE="$payinfo" MAXLENGTH=19></TD></TR><TR><TD ALIGN="right"><font color="#ff0000">*</font> Expration</TD><TD>!. expselect("CARD", $paydate). qq!</TD></TR><TR><TD ALIGN="right"><font color="#ff0000">*</font> Name on card</TD><TD><INPUT TYPE="text" NAME="CARD_payname" VALUE="$payname"></TD></TR>!,
+ 'DCRD' => qq!Credit card<BR><font color="#ff0000">*</font>$cardselect<INPUT TYPE="text" NAME="DCRD_payinfo" VALUE="$payinfo" MAXLENGTH=19><BR><font color="#ff0000">*</font>Exp !. expselect("DCRD", $paydate). qq!<BR><font color="#ff0000">*</font>Name on card<BR><INPUT TYPE="text" NAME="DCRD_payname" VALUE="$payname">!,
+ 'CHEK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="CHEK_payinfo1" VALUE="$account" MAXLENGTH=10> Type <SELECT NAME="CHEK_paytype">!. join('', map {qq!<OPTION VALUE="$_"!.($paytype eq $_ ? 'SELECTED' : '').">$_</OPTION>"} @paytypes). qq!</SELECT><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="CHEK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="CHEK_month" VALUE="12"><INPUT TYPE="hidden" NAME="CHEK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="CHEK_payname" VALUE="$payname">!,
+ 'DCHK' => qq!Electronic check<BR>${r}Account number <INPUT TYPE="text" NAME="DCHK_payinfo1" VALUE="$account" MAXLENGTH=10> Type <SELECT NAME="DCHK_paytype">!. join('', map {qq!<OPTION VALUE="$_"!.($paytype eq $_ ? 'SELECTED' : '').">$_</OPTION>"} @paytypes). qq!</SELECT><BR>${r}ABA/Routing code <INPUT TYPE="text" NAME="DCHK_payinfo2" VALUE="$aba" SIZE=10 MAXLENGTH=9><INPUT TYPE="hidden" NAME="DCHK_month" VALUE="12"><INPUT TYPE="hidden" NAME="DCHK_year" VALUE="2037"><BR>${r}Bank name <INPUT TYPE="text" NAME="DCHK_payname" VALUE="">!,
+ 'LECB' => qq!Phone bill billing<BR>${r}Phone number <INPUT TYPE="text" BANE="LECB_payinfo" VALUE="$payinfo" MAXLENGTH=15 SIZE=16><INPUT TYPE="hidden" NAME="LECB_month" VALUE="12"><INPUT TYPE="hidden" NAME="LECB_year" VALUE="2037"><INPUT TYPE="hidden" NAME="LECB_payname" VALUE="">!,
+ 'BILL' => qq!Billing<BR>P.O. <INPUT TYPE="text" NAME="BILL_payinfo" VALUE="$payinfo"><BR><INPUT TYPE="hidden" NAME="BILL_month" VALUE="12"><INPUT TYPE="hidden" NAME="BILL_year" VALUE="2037">Attention<INPUT TYPE="text" NAME="BILL_payname" VALUE="$payname">!,
+ 'COMP' => qq!Complimentary<BR><font color="#ff0000">*</font>Approved by<INPUT TYPE="text" NAME="COMP_payinfo" VALUE="$payinfo"><BR><font color="#ff0000">*</font>Exp !. expselect("COMP", $paydate),
+ 'PREPAY' => qq!Prepaid card<BR><font color="#ff0000">*</font><INPUT TYPE="text" NAME="PREPAY_payinfo" VALUE="$payinfo" MAXLENGTH=80>!,
+ );
+
+ if ( $cvv_enabled ) {
+ foreach my $payby ( grep { exists $payby{$_} } qw(CARD DCRD) ) { #1.4/1.5
+ $paybychecked{$payby} .= qq!<TR><TD ALIGN="right">CVV2&nbsp;(<A HREF="javascript:myopen('cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>)</TD><TD><INPUT TYPE="text" NAME=${payby}_paycvv VALUE="$paycvv" SIZE=4 MAXLENGTH=4></TD></TR>!;
+ }
+ }
+ if ( $paystate_enabled ) {
+ foreach my $payby ( grep { exists $payby{$_} } qw(CHEK DCHK) ) {
+ my ($county_html, $state_html, $country_html) =
+ regionselector( {
+ prefix => "${payby}_pay",
+ selected_county => $county,
+ selected_state => $state,
+ selected_country => $country,
+ default_state => $statedefault,
+ default_country => $countrydefault,
+ locales => \@cust_main_county,
+ } );
+ $paybychecked{$payby} .= "<BR>${r}Bank state $county_html $state_html";
+ }
+ }
+
+use Tie::IxHash;
+use HTML::Widgets::SelectLayers;
+
+ my %payby_index = ( 'CARD' => qq/Credit Card/,
+ 'DCRD' => qq/Credit Card/,
+ 'CHEK' => qq/Check/,
+ 'DCHK' => qq/Check/,
+ 'LECB' => qq/Phone Bill Billing/,
+ 'BILL' => qq/Billing/,
+ 'COMP' => qq/Complimentary/,
+ 'PREPAY' => qq/Prepaid Card/,
+ );
+
+
+tie my %options, 'Tie::IxHash', ();
+
+foreach my $payby_option ( @payby ) {
+ $options{$payby_option} = $payby_index{$payby_option};
+}
+
+my $selected_layer = ( grep { $_ eq 'CARD' } @payby ) ? 'CARD' : $payby[0];
+
+HTML::Widgets::SelectLayers->new(
+ options => \%options,
+ selected_layer => $selected_layer,
+ form_name => 'dummy',
+ html_between => '</td></tr></table>',
+ form_action => 'dummy.cgi',
+ layer_callback => sub { my $layer = shift; return $paybychecked{$layer}. '</TABLE>'; },
+)->html;
+
+
+ %>
+
+</TR></TABLE><font color="#ff0000">*</font> required fields
+<FORM name="signup_form" action="<%= $self_url %>" METHOD="POST" onsubmit="return fixup_form();"><BR><BR>First package
+<INPUT TYPE="hidden" NAME="promo_code" VALUE="<%= $promo_code %>">
+<INPUT TYPE="hidden" NAME="reg_code" VALUE="<%= $reg_code %>">
+<TABLE BGCOLOR="<%= $box_bgcolor || '#c0c0c0' %>" BORDER=0 CELLSPACING=0 WIDTH="100%">
+<TR>
+ <TD COLSPAN=2><SELECT NAME="pkgpart">
+
+ <%=
+ $OUT .= '<OPTION VALUE="">(none)'
+ unless scalar(@part_pkg) == 1 or $default_pkgpart;
+ foreach my $part_pkg ( @part_pkg ) {
+ $OUT .= '<OPTION VALUE="'. $part_pkg->{'pkgpart'}. '"';
+ $OUT .= ' SELECTED' if $pkgpart && $part_pkg->{'pkgpart'} == $pkgpart;
+ $OUT .= '>'. $part_pkg->{'pkg'};
+ }
+ %>
+
+ </SELECT></TD>
+</TR>
+<%=
+ if ( $signup_service eq 'svc_phone' ) {
+
+ $OUT .= '<TR><TD ALIGN="right">Phone number</TD><TD>'.
+ didselector( 'field' => 'phonenum',
+ 'svcpart' => $default_svcpart,
+ ).
+ '</TD></TR>';
+
+ $OUT .= <<ENDOUT;
+<TR>
+ <TD ALIGN="right">Voicemail PIN</TD>
+ <TD><INPUT TYPE="pin" NAME="pin" VALUE="$pin"></TD>
+</TR>
+ENDOUT
+
+ } else {
+
+ $OUT .= <<ENDOUT;
+<TR>
+ <TD ALIGN="right">Username</TD>
+ <TD><INPUT TYPE="text" NAME="username" VALUE="$username"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password" VALUE="$_password"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Re-enter Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password2" VALUE="$_password2"></TD>
+</TR>
+ENDOUT
+
+ if ( $security_phrase ) {
+ $OUT .= <<SECPHRASE;
+<TR>
+ <TD ALIGN="right">Security Phrase</TD>
+ <TD><INPUT TYPE="text" NAME="sec_phrase" VALUE="$sec_phrase">
+ </TD>
+</TR>
+SECPHRASE
+ } else {
+ $OUT .= '<INPUT TYPE="hidden" NAME="sec_phrase" VALUE="">';
+ }
+
+ }
+
+ if ( @svc_acct_pop ) {
+ $OUT .= '<TR><TD ALIGN="right">Access number</TD><TD>'.
+ popselector( 'popnum' => $popnum,
+ 'pops' => \@svc_acct_pop,
+ 'init_popstate' => $init_popstate,
+ 'popac' => $popac,
+ 'acstate' => $acstate,
+ ).
+ '</TD></TR>';
+ } else {
+ $OUT .= popselector(popnum=>$popnum, pops=>\@svc_acct_pop);
+ }
+
+%>
+
+</TABLE>
+
+<%=
+if ( @optional_packages ) {
+ my @html;
+ foreach my $ii ( 0 .. $#optional_packages) {
+ my $friendly_index = $ii + 1;
+ if ($optional_packages[$ii]) {
+ push @html, qq|<BR>Optional Package #$friendly_index <br />|,'<table bgcolor="#c0c0c0"><tr><td>';
+
+ push @html, qq|<select name="optional_package${ii}">|;
+ push @html, qq|<option value="none"></option>|;
+ push @html, map { qq|<option value="$_->{pkgpart}">$_->{pkg}</option>| } @{$optional_packages[$ii]};
+ push @html, q|</select>|;
+
+ push @html, '</td></tr></table>';
+ }
+ $OUT = join("\n", @html);
+ }
+} else {
+$OUT = ''
+}
+%>
+
+<BR><INPUT TYPE="submit" NAME="signup" VALUE="Signup">
+<script language="JavaScript">
+
+function fixup_form() {
+
+ // copy payment method data up to OneTrueForm
+
+ var payment_method_elements = new Array( 'payinfo', 'payinfo1', 'payinfo2', 'payname', 'paycvv' , 'paystate', 'paytype', 'month', 'year','type' );
+ var payment_method_form_name = document.OneTrueForm.select.options[document.OneTrueForm.select.selectedIndex].value;
+ document.OneTrueForm.elements['payby'].value = payment_method_form_name;
+ var payment_method_form = document.forms[payment_method_form_name];
+
+ for ( ii = 0 ; ii < payment_method_elements.length ; ii++ ) {
+ var true_element_name = payment_method_form_name + '_' + payment_method_elements[ii];
+ copyelement ( payment_method_form.elements[true_element_name],
+ document.OneTrueForm.elements[true_element_name] );
+ }
+
+ // Copy signup details to OneTrueForm
+
+ var signup_elements = new Array (
+ 'promo_code', 'reg_code', 'pkgpart',
+ 'username', '_password', '_password2', 'sec_phrase', 'popnum',
+ 'countrycode', 'phonenum', 'sip_password', 'pin'
+ );
+
+ for ( ii = 0 ; ii < signup_elements.length ; ii ++ ) {
+ copyelement ( document.signup_form.elements[signup_elements[ii]],
+ document.OneTrueForm.elements[signup_elements[ii]]);
+ }
+
+ document.OneTrueForm.submit();
+ return false;
+}
+
+function copyelement(from, to) {
+// alert ( from + ' ' + to );
+
+ if ( from == undefined ) {
+ to.value = '';
+ } else {
+ if ( from.type == 'select-one' ) {
+ to.value = from.options[from.selectedIndex].value;
+ } else if ( from.type == 'checkbox' ) {
+ if ( from.checked ) {
+ to.value = from.value;
+ } else {
+ to.value = '';
+ }
+ } else {
+ if ( from.value == undefined ) {
+ to.value = '';
+ } else {
+ to.value = from.value;
+ }
+ }
+// alert(from.name + " (" + from.type + "): " + to.name + " => " + to.value);
+ }
+}
+
+</script>
+</FORM>
+<%= $OUT .= $body_footer %>
+</BODY>
+</HTML>
diff --git a/fs_selfservice/FS-SelfService/cgi/stateselect.html b/fs_selfservice/FS-SelfService/cgi/stateselect.html
new file mode 100644
index 000000000..ba55bff74
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/stateselect.html
@@ -0,0 +1,134 @@
+<HTML><HEAD><TITLE>ISP Signup</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=7>ISP Signup - state selection</FONT><BR><BR>
+<SCRIPT>
+function gotoURL(object) {
+ window.location.href = object.options[object.selectedIndex].value;
+}
+</SCRIPT>
+<FORM>
+Select your state from the map or dropdown:
+<MAP NAME=usmap>
+<area shape=poly COORDS="264,157,286,155,292,193,276,195,270,199,264,157" href="signup.cgi?init_popstate=AL">
+<area shape=poly COORDS="28,197,46,185,72,199,72,241,88,243,102,261,92,263,70,241,42,243,28,257,12,259,34,243,20,233,16,223,34,215,22,207,30,205,28,197" href="../states/Alaska.html">
+<area shape=poly COORDS="70,137,106,137,100,189,84,187,60,173,70,133,70,137,70,137" href="signup.cgi?init_popstate=AZ">
+<area shape=poly COORDS="250,153,242,179,220,177,218,171,216,145,252,143,250,155,250,153" href="signup.cgi?init_popstate=AR">
+<area shape=poly COORDS="10,79,38,81,30,109,62,151,56,173,40,169,20,145,4,101,10,75,26,79,10,79,10,79" href="signup.cgi?init_popstate=CA">
+<area shape=poly COORDS="108,103,158,107,154,141,104,137,110,101,128,103,108,103" href="signup.cgi?init_popstate=CO">
+<area shape=poly COORDS="374,107,405,105,405,123,372,125,374,107" href="signup.cgi?init_popstate=CT">
+<area shape=poly COORDS="370,143,402,145,405,157,362,157,370,143" href="signup.cgi?init_popstate=DE">
+<area shape=poly COORDS="275,193,325,187,327,197,341,219,341,233,335,237,317,215,315,205,307,195,293,203,275,193" href="signup.cgi?init_popstate=FL">
+<area shape=poly COORDS="297,153,283,155,297,191,321,189,321,169,297,153" href="signup.cgi?init_popstate=GA">
+<area shape=poly COORDS="98,233,142,263,156,251,162,239,164,229,136,231,94,221,100,235,98,233" href="signup.cgi?init_popstate=HI">
+<area shape=poly COORDS="68,21,76,21,72,35,80,47,80,55,84,65,100,69,94,93,56,83,66,51,70,19,68,21" href="signup.cgi?init_popstate=ID">
+<area shape=poly COORDS="242,91,258,89,266,123,256,139,234,109,248,87,242,91" href="signup.cgi?init_popstate=IL">
+<area shape=poly COORDS="261,95,265,123,265,131,285,117,277,91,261,95" href="signup.cgi?init_popstate=IN">
+<area shape=poly COORDS="198,87,206,111,232,109,240,99,240,91,232,79,198,87" href="signup.cgi?init_popstate=IA">
+<area shape=poly COORDS="158,111,158,135,214,139,214,127,208,113,158,111" href="signup.cgi?init_popstate=KS">
+<area shape=poly COORDS="263,133,275,129,289,115,303,121,307,129,299,135,251,141,269,131,263,133" href="signup.cgi?init_popstate=KY">
+<area shape=poly COORDS="222,179,246,179,244,197,258,193,262,213,226,209,224,177,222,179" href="signup.cgi?init_popstate=LA">
+<area shape=poly COORDS="363,37,373,59,373,47,387,31,377,9,365,15,363,37" href="signup.cgi?init_popstate=ME">
+<area shape=poly COORDS="376,159,405,159,405,175,374,177,376,159" href="signup.cgi?init_popstate=MD">
+<area shape=poly COORDS="378,74,380,88,404,88,404,72,378,74" href="signup.cgi?init_popstate=MA">
+<area shape=poly COORDS="265,73,269,83,265,93,293,91,295,71,281,53,271,53,267,69,265,73,265,73" href="signup.cgi?init_popstate=MI">
+<area shape=poly COORDS="194,31,222,33,242,35,224,51,222,63,222,73,234,79,196,85,194,31" href="signup.cgi?init_popstate=MN">
+<area shape=poly COORDS="265,159,271,199,257,201,259,195,241,197,251,155,265,159" href="signup.cgi?init_popstate=MS">
+<area shape=poly COORDS="206,113,234,111,256,139,248,147,214,145,208,111,206,113" href="signup.cgi?init_popstate=MO">
+<area shape=poly COORDS="78,23,148,31,146,67,84,63,78,35,80,19,78,23" href="signup.cgi?init_popstate=MT">
+<area shape=poly COORDS="146,85,148,103,158,105,164,109,206,109,198,85,144,87,146,85" href="signup.cgi?init_popstate=NE">
+<area shape=poly COORDS="40,83,76,87,64,151,32,109,40,83,40,83" href="signup.cgi?init_popstate=NV">
+<area shape=poly COORDS="298,11,330,9,330,25,298,25,298,11" href="signup.cgi?init_popstate=NH">
+<area shape=poly COORDS="372,127,404,125,405,141,368,139,376,125,372,127" href="signup.cgi?init_popstate=NJ">
+<area shape=poly COORDS="106,137,100,191,122,187,148,187,150,139,106,137,106,137" href="signup.cgi?init_popstate=NM">
+<area shape=poly COORDS="313,79,331,63,337,45,349,45,359,65,357,79,345,65,315,77,313,79,313,79" href="signup.cgi?init_popstate=NY">
+<area shape=poly COORDS="309,137,295,151,319,149,337,153,357,131,351,129,309,137,309,137" href="signup.cgi?init_popstate=NC">
+<area shape=poly COORDS="146,31,148,57,198,57,190,31,146,31,146,31" href="signup.cgi?init_popstate=ND">
+<area shape=poly COORDS="281,93,285,113,299,121,311,101,309,85,299,93,281,93,281,93" href="signup.cgi?init_popstate=OH">
+<area shape=poly COORDS="148,145,174,145,174,163,218,171,216,143,150,139,150,145,156,143,148,145,148,145" href="signup.cgi?init_popstate=OK">
+<area shape=poly COORDS="20,41,8,73,16,77,22,77,28,77,36,79,42,81,48,83,56,83,66,49,20,41,20,41" href="signup.cgi?init_popstate=OR">
+<area shape=poly COORDS="309,83,345,71,351,93,313,105,309,83,309,83" href="signup.cgi?init_popstate=PA">
+<area shape=poly COORDS="376,93,405,93,405,107,376,105,376,93" href="signup.cgi?init_popstate=RI">
+<area shape=poly COORDS="301,155,321,149,337,155,325,175,301,157,301,155,301,155" href="signup.cgi?init_popstate=SC">
+<area shape=poly COORDS="146,59,198,61,198,83,146,83,148,57,146,59,146,59" href="signup.cgi?init_popstate=SD">
+<area shape=poly COORDS="255,145,251,157,297,153,311,133,255,145,255,145" href="signup.cgi?init_popstate=TN">
+<area shape=poly COORDS="150,145,172,145,174,167,198,173,218,173,228,207,204,221,198,231,202,247,180,241,154,207,146,219,120,189,154,189,152,145,150,145,150,145" href="signup.cgi?init_popstate=TX">
+<area shape=poly COORDS="78,89,96,91,96,103,110,103,106,135,70,133,78,89,78,89" href="signup.cgi?init_popstate=UT">
+<area shape=poly COORDS="298,29,332,29,332,47,294,45,298,29" href="signup.cgi?init_popstate=VT">
+<area shape=poly COORDS="307,127,297,137,351,127,349,113,341,111,341,105,329,107,315,131,307,127,307,127" href="signup.cgi?init_popstate=VA">
+<area shape=poly COORDS="32,13,68,19,64,47,20,39,20,13,30,19,32,13,32,13" href="signup.cgi?init_popstate=WA">
+<area shape=poly COORDS="303,119,313,129,329,103,311,105,299,121,313,127,303,119,303,119" href="signup.cgi?init_popstate=WV">
+<area shape=poly COORDS="228,51,256,55,254,89,238,89,234,77,224,71,230,49,236,53,228,51,228,51" href="signup.cgi?init_popstate=WI">
+<area shape=poly COORDS="146,71,144,103,96,99,102,63,148,69,146,71,146,71" href="signup.cgi?init_popstate=WY">
+</MAP>
+<IMG SRC="map.gif" usemap=#usmap WIDTH=405 HEIGHT=270 border=0><BR>
+<SELECT NAME="init_popstate" onChange="gotoURL(this.form.init_popstate)">
+<OPTION VALUE="stateselect.html"></OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=AL">Alabama</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=AK">Alaska</OPTION>
+<!--<OPTION VALUE="signup.cgi?init_popstate=AS">American Samoa</OPTION>-->
+<OPTION VALUE="signup.cgi?init_popstate=AZ">Arizona</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=AR">Arkansas</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=CA">California</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=CO">Colorado</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=CT">Connecticut</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=DE">Delaware</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=DC">District of Columbia</OPTION>
+<!--<OPTION VALUE="signup.cgi?init_popstate=FM">Federated States of Micronesia</OPTION>-->
+<OPTION VALUE="signup.cgi?init_popstate=FL">Florida</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=GA">Georgia</OPTION>
+<!--<OPTION VALUE="signup.cgi?init_popstate=GU">Guam</OPTION>-->
+<OPTION VALUE="signup.cgi?init_popstate=HI">Hawaii</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=ID">Idaho</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=IL">Illinois</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=IN">Indiana</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=IA">Iowa</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=KS">Kansas</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=KY">Kentucky</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=LA">Louisiana</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=ME">Maine</OPTION>
+<!--<OPTION VALUE="signup.cgi?init_popstate=MH">Marshall Islands</OPTION>-->
+<OPTION VALUE="signup.cgi?init_popstate=MD">Maryland</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=MA">Massachusetts</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=MI">Michigan</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=MN">Minnesota</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=MS">Mississippi</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=MO">Missouri</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=MT">Montana</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=NE">Nebraska</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=NV">Nevada</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=NH">New Hampshire</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=NJ">New Jersey</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=NM">New Mexico</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=NY">New York</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=NC">North Carolina</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=ND">North Dakota</OPTION>
+<!--<OPTION VALUE="signup.cgi?init_popstate=MP">Northern Mariana Islands</OPTION>-->
+<OPTION VALUE="signup.cgi?init_popstate=OH">Ohio</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=OK">Oklahoma</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=OR">Oregon</OPTION>
+<!--<OPTION VALUE="signup.cgi?init_popstate=PW">Palau</OPTION>-->
+<OPTION VALUE="signup.cgi?init_popstate=PA">Pennsylvania</OPTION>
+<!--<OPTION VALUE="signup.cgi?init_popstate=PR">Puerto Rico</OPTION>-->
+<OPTION VALUE="signup.cgi?init_popstate=RI">Rhode Island</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=SC">South Carolina</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=SD">South Dakota</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=TN">Tennessee</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=TX">Texas</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=UT">Utah</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=VT">Vermont</OPTION>
+<!--<OPTION VALUE="signup.cgi?init_popstate=VI">Virgin Islands</OPTION>-->
+<OPTION VALUE="signup.cgi?init_popstate=VA">Virginia</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=WA">Washington</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=WV">West Virginia</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=WI">Wisconsin</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=WY">Wyoming</OPTION>
+<!--<OPTION VALUE="signup.cgi?init_popstate=AE">Armed Forces Africa</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=AA">Armed Forces Americas</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=AE">Armed Forces Canada</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=AE">Armed Forces Europe</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=AE">Armed Forces Middle East</OPTION>
+<OPTION VALUE="signup.cgi?init_popstate=AP">Armed Forces Pacific</OPTION>
+-->
+</SELECT>
+</FORM>
+</BODY>
+</HTML>
diff --git a/fs_selfservice/FS-SelfService/cgi/success-delayed.html b/fs_selfservice/FS-SelfService/cgi/success-delayed.html
new file mode 100644
index 000000000..5eeed5957
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/success-delayed.html
@@ -0,0 +1,16 @@
+<HTML><HEAD><TITLE>Signup successful</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=7>Signup successful</FONT><BR><BR>
+Thanks for signing up!
+<BR><BR>
+Signup information for <%= $email_name %>:
+<BR><BR>
+Username: <%= $username %><BR>
+Password: <%= $password %><BR>
+Access number: (<%= $ac %>) / <%= $exch %> - <%= $local %><BR>
+Package: <%= $pkg %><BR>
+Charge: <%= sprintf('$%.2f', $part_pkg->{'options'}->{'setup_fee'}) %><BR>
+In <%= $part_pkg->{'options'}->{'free_days'} %> days you will be charged
+ <%= sprintf('$%.2f', $part_pkg->{'options'}->{'recur_fee'}) %>
+and <%= $part_pkg->{'freq_pretty'} %> thereafter.<BR>
+
+</BODY></HTML>
diff --git a/fs_selfservice/FS-SelfService/cgi/success.html b/fs_selfservice/FS-SelfService/cgi/success.html
new file mode 100644
index 000000000..92185c3cd
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/success.html
@@ -0,0 +1,41 @@
+<HTML>
+
+<HEAD>
+ <TITLE>Signup successful</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#e8e8e8">
+
+<FONT SIZE=7>Signup successful</FONT><BR><BR>
+
+Thanks for signing up! Save this information for future reference.
+<BR><BR>
+
+Signup information for <%= $email_name %>:
+<BR><BR>
+
+<%=
+ if ($signup_service eq 'svc_acct' || !$signup_service ) { #just in case
+ $OUT .= <<END
+ Username: $username<BR>
+ Password: $password><BR>
+ Access number: ($ac) / $exch - $local <BR>
+END
+ } elsif ( $signup_service eq 'svc_phone' ) {
+ $OUT .= <<END
+ <!-- Countrycode: $countrycode <BR>-->
+ Phone number: $phonenum<BR>
+ SIP Server: itsp.sip.server.name<BR>
+ SIP Login: $phonenum<BR>
+ SIP Password: $sip_password<BR>
+ Voicemail PIN: $pin<BR>
+END
+ } else {
+ die "unknown signup service $signup_service";
+ }
+%>
+
+ Package: <%= $pkg %><BR>
+
+</BODY>
+</HTML>
diff --git a/fs_selfservice/FS-SelfService/cgi/svc_acct.html b/fs_selfservice/FS-SelfService/cgi/svc_acct.html
new file mode 100644
index 000000000..00244386b
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/svc_acct.html
@@ -0,0 +1,58 @@
+<FONT SIZE=4>Setup <%= $svc %></FONT><BR><BR>
+
+<%= if ( $error ) {
+ $OUT .= qq!<FONT SIZE="+1" COLOR="#ff0000">Error setting up $svc: $error!.
+ '</FONT><BR><BR>';
+} ''; %>
+<FORM ACTION="<%= $selfurl %>" METHOD=POST>
+<INPUT TYPE="hidden" NAME="session" VALUE="<%= $session_id %>">
+<INPUT TYPE="hidden" NAME="action" VALUE="process_svc_acct">
+<INPUT TYPE="hidden" NAME="custnum" VALUE="<%= $custnum %>">
+<INPUT TYPE="hidden" NAME="pkgnum" VALUE="<%= $pkgnum %>">
+<INPUT TYPE="hidden" NAME="svcpart" VALUE="<%= $svcpart %>">
+<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=2 BGCOLOR="#cccccc">
+<TR>
+ <TD ALIGN="right">Username</TD>
+ <TD><INPUT TYPE="text" NAME="username" VALUE="<%= $username %>"></TD>
+</TR>
+<%=
+ $OUT .= domainselector(pkgnum=>$pkgnum, svcpart=>$svcpart);
+%>
+<TR>
+ <TD ALIGN="right">Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password" VALUE="<%= $_password %>"></TD>
+</TR>
+<TR>
+ <TD ALIGN="right">Re-enter Password</TD>
+ <TD><INPUT TYPE="password" NAME="_password2" VALUE="<%= $_password2 %>"></TD>
+</TR>
+<%=
+ if ( $security_phrase ) {
+ $OUT .= <<ENDOUT;
+<TR>
+ <TD ALIGN="right">Security Phrase</TD>
+ <TD><INPUT TYPE="text" NAME="sec_phrase" VALUE="$sec_phrase">
+ </TD>
+</TR>
+ENDOUT
+ } else {
+ $OUT .= '<INPUT TYPE="hidden" NAME="sec_phrase" VALUE="">';
+ }
+%>
+<%=
+ if ( @svc_acct_pop ) {
+ $OUT .= '<TR><TD ALIGN="right">Access number</TD><TD>'.
+ popselector( 'popnum' => $popnum,
+ 'pops' => \@svc_acct_pop,
+ 'init_popstate' => $init_popstate,
+ 'popac' => $popac,
+ 'acstate' => $acstate,
+ ).
+ '</TD></TR>';
+ } else {
+ $OUT .= popselector(popnum=>$popnum, pops=>\@svc_acct_pop);
+ }
+%>
+</TABLE>
+<INPUT TYPE="submit" VALUE="Setup">
+</FORM>
diff --git a/fs_selfservice/FS-SelfService/cgi/view_customer.html b/fs_selfservice/FS-SelfService/cgi/view_customer.html
new file mode 100644
index 000000000..5bfb9b6fd
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/view_customer.html
@@ -0,0 +1,24 @@
+<HTML><HEAD><TITLE>Reseller</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>Reseller</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<TABLE BORDER=0 CELLPADDING=4><TR>
+<%= include('agent_menu') %>
+<TD VALIGN="top">
+
+<%= $message
+ ? "<FONT SIZE=\"+2\"><B>$message</B></FONT><BR><BR>"
+ : ''
+%>
+
+<%= $small_custview %>
+
+<BR>
+
+<TABLE BORDER=0 CELLPADDING=4><TR>
+<%= include('agent_customer_menu') %>
+<TD VALIGN="top">
+
+</TD></TR></TABLE>
+
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/view_invoice.html b/fs_selfservice/FS-SelfService/cgi/view_invoice.html
new file mode 100644
index 000000000..8fa5fb7dc
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/view_invoice.html
@@ -0,0 +1,10 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+
+<%= $invoice_html %>
+
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/view_support_details.html b/fs_selfservice/FS-SelfService/cgi/view_support_details.html
new file mode 100644
index 000000000..ea218749c
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/view_support_details.html
@@ -0,0 +1,78 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+
+<FONT SIZE=4>Support usage details for
+<%= Date::Format::time2str('%b&nbsp;%o&nbsp;%Y', $beginning) %> -
+<%= Date::Format::time2str('%b&nbsp;%o&nbsp;%Y', $ending) %>
+</FONT><BR><BR>
+
+<%= if ( $error ) {
+ $OUT .= qq!<FONT SIZE="+1" COLOR="#ff0000">$error</FONT><BR><BR>!;
+} ''; %>
+
+<TABLE WIDTH="100%">
+ <TR>
+ <TD WIDTH="50%">
+<%= if ($previous < $beginning) {
+ $OUT .= qq!<A HREF="${url}view_support_details;svcnum=$svcnum;beginning=!;
+ $OUT .= qq!$previous;ending=$beginning">Previous period</A>!;
+ }else{
+ '';
+ } %>
+ </TD>
+ <TD WIDTH="50%" ALIGN="right">
+<%= if ($next > $ending) {
+ $OUT .= qq!<A HREF="${url}view_support_details;svcnum=$svcnum;beginning=!;
+ $OUT .= qq!$ending;ending=$next">Next period</A>!;
+ }else{
+ '';
+ }%>
+ </TD>
+ </TR>
+</TABLE>
+<TABLE BGCOLOR="#cccccc">
+ <TR>
+ <TH ALIGN="left">Ticket</TH>
+ <TH ALIGN="center">Subject</TH>
+ <TH ALIGN="center">Staff</TH>
+ <TH ALIGN="center">Date</TH>
+ <TH ALIGN="center">Status</TH>
+ <TH ALIGN="right">Time</TH>
+ </TR>
+<%= my $total = 0;
+ foreach my $usage ( @usage ) {
+ $OUT .= '<TR><TD ALIGN="left">';
+ $OUT .= $usage->{'ticketid'};
+ $OUT .= '</TD><TD ALIGN="right">';
+ $OUT .= $usage->{'subject'};
+ $OUT .= '</TD><TD ALIGN="right">';
+ $OUT .= $usage->{'creator'};
+ $OUT .= '</TD><TD ALIGN="left">';
+ $OUT .= Date::Format::time2str('%T%P %a&nbsp;%b&nbsp;%o&nbsp;%Y', $usage->{'_date'});
+ $OUT .= '</TD><TD ALIGN="right">';
+ $OUT .= $usage->{'status'};
+ $OUT .= '</TD><TD ALIGN="right">';
+ my $duration = $usage->{'support'};
+ $total += $usage->{'support'};
+ my $h = int($duration/3600);
+ my $m = sprintf("%02d", int(($duration % 3600) / 60));
+ my $s = sprintf("%02d", $duration % 60);
+ $OUT .= $usage->{'support'} < 0 ? '-' : '';
+ $OUT .= "$h:$m:$s";
+ $OUT .= '</TD></TR>';
+ }
+ my $h = int($total/3600);
+ my $m = sprintf("%02d", int(($total % 3600) / 60));
+ my $s = sprintf("%02d", $total % 60);
+ $OUT .= qq!<TR><TD COLSPAN="5"></TD><TD ALIGN="right"><HR></TD></TR>!;
+ $OUT .= qq!<TR><TD COLSPAN="5"></TD><TD ALIGN="right">$h:$m:$s</TD></TR>!;
+ %>
+
+</TABLE>
+<BR>
+
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/view_usage.html b/fs_selfservice/FS-SelfService/cgi/view_usage.html
new file mode 100644
index 000000000..b78f9975b
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/view_usage.html
@@ -0,0 +1,58 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+
+<FONT SIZE=4>Service usage</FONT><BR><BR>
+
+<%= if ( $error ) {
+ $OUT .= qq!<FONT SIZE="+1" COLOR="#ff0000">$error</FONT><BR><BR>!;
+} ''; %>
+
+<TABLE BGCOLOR="#cccccc">
+ <TR>
+ <TH ALIGN="left">Account</TH>
+ <TH ALIGN="right">Time remaining</TH>
+ <TH ALIGN="right">Upload remaining</TH>
+ <TH ALIGN="right">Download remaining</TH>
+ <TH ALIGN="right">Total remaining</TH>
+ </TR>
+<%= foreach my $svc ( @svcs ) {
+ my $link = "${url}view_usage_details;".
+ "svcnum=$svc->{'svcnum'};beginning=0;ending=0";
+ $OUT .= '<TR><TD>';
+ $OUT .= qq!<A HREF="$link">!. $svc->{'label'}. ': '. $svc->{'value'}.'</A>';
+ $OUT .= '</TD><TD ALIGN="right">';
+ $OUT .= $svc->{'seconds'};
+ $OUT .= '</TD><TD ALIGN="right">';
+ $OUT .= $svc->{'upbytes'};
+ $OUT .= '</TD><TD ALIGN="right">';
+ $OUT .= $svc->{'downbytes'};
+ $OUT .= '</TD><TD ALIGN="right">';
+ $OUT .= $svc->{'totalbytes'};
+ $OUT .= '</TD></TR>';
+ if ( $svc->{'recharge_amount'} ) {
+ my $link = "${url}process_order_recharge;".
+ "svcnum=$svc->{'svcnum'}";
+ $OUT .= '<TR><TD ALIGN="right">';
+ $OUT .= qq!<A HREF="$link">!.'Recharge for $';
+ $OUT .= $svc->{'recharge_amount'} . '</A> with';
+ $OUT .= '</TD><TD ALIGN="right">';
+ $OUT .= $svc->{'recharge_seconds'} if $svc->{'recharge_seconds'};
+ $OUT .= '</TD><TD ALIGN="right">';
+ $OUT .= $svc->{'recharge_upbytes'} if $svc->{'recharge_upbytes'};
+ $OUT .= '</TD><TD ALIGN="right">';
+ $OUT .= $svc->{'recharge_downbytes'} if $svc->{'recharge_downbytes'};
+ $OUT .= '</TD><TD ALIGN="right">';
+ $OUT .= $svc->{'recharge_totalbytes'} if $svc->{'recharge_totalbytes'};
+ $OUT .= '</TD></TR>';
+ }
+ } %>
+
+</TABLE>
+<BR>
+
+</TD></TR></TABLE>
+
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/view_usage_details.html b/fs_selfservice/FS-SelfService/cgi/view_usage_details.html
new file mode 100644
index 000000000..6bac7487c
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/view_usage_details.html
@@ -0,0 +1,84 @@
+<HTML><HEAD><TITLE>MyAccount</TITLE></HEAD>
+<BODY BGCOLOR="#eeeeee"><FONT SIZE=5>MyAccount</FONT><BR><BR>
+<%= $url = "$selfurl?session=$session_id;action="; ''; %>
+<%= include('myaccount_menu') %>
+<TD VALIGN="top">
+
+<FONT SIZE=4>Service usage details for
+<%= Date::Format::time2str('%b&nbsp;%o&nbsp;%Y', $beginning) %> -
+<%= Date::Format::time2str('%b&nbsp;%o&nbsp;%Y', $ending) %>
+</FONT><BR><BR>
+
+<%= if ( $error ) {
+ $OUT .= qq!<FONT SIZE="+1" COLOR="#ff0000">$error</FONT><BR><BR>!;
+} ''; %>
+
+<TABLE WIDTH="100%">
+ <TR>
+ <TD WIDTH="50%">
+<%= if ($previous < $beginning) {
+ $OUT .= qq!<A HREF="${url}view_usage_details;svcnum=$svcnum;beginning=!;
+ $OUT .= qq!$previous;ending=$beginning">Previous period</A>!;
+ }else{
+ '';
+ } %>
+ </TD>
+ <TD WIDTH="50%" ALIGN="right">
+<%= if ($next > $ending) {
+ $OUT .= qq!<A HREF="${url}view_usage_details;svcnum=$svcnum;beginning=!;
+ $OUT .= qq!$ending;ending=$next">Next period</A>!;
+ }else{
+ '';
+ }%>
+ </TD>
+ </TR>
+</TABLE>
+<TABLE BGCOLOR="#cccccc">
+ <TR>
+ <TH ALIGN="left">Account</TH>
+ <TH ALIGN="right">Start Time</TH>
+ <TH ALIGN="right">Duration</TH>
+ <TH ALIGN="right">Upload</TH>
+ <TH ALIGN="right">Download</TH>
+ </TR>
+<%= my $total = 0;
+ my $utotal = 0;
+ my $dtotal = 0;
+ foreach my $usage ( @usage ) {
+ $OUT .= '<TR><TD>';
+ $OUT .= $usage->{'username'};
+ $OUT .= '</TD><TD ALIGN="right">';
+ $OUT .= Date::Format::time2str('%T%P %a&nbsp;%b&nbsp;%o&nbsp;%Y', $usage->{'acctstarttime'});
+ $OUT .= '</TD><TD ALIGN="right">';
+ my $duration = $usage->{'acctstoptime'} - $usage->{'acctstarttime'};
+ $total += $duration;
+ my $h = int($duration/3600);
+ my $m = sprintf("%02d", int(($duration % 3600) / 60));
+ my $s = sprintf("%02d", $duration % 60);
+ $OUT .= "$h:$m:$s";
+ $OUT .= '</TD><TD ALIGN="right">';
+ $OUT .= Number::Format::format_bytes($usage->{'acctinputoctets'}, precision => 2);
+ $utotal += $usage->{'acctinputoctets'};
+ $OUT .= '</TD><TD ALIGN="right">';
+ $OUT .= Number::Format::format_bytes($usage->{'acctoutputoctets'}, precision => 2);
+ $dtotal += $usage->{'acctoutputoctets'};
+ $OUT .= '</TD></TR>';
+ }
+ my $h = int($total/3600);
+ my $m = sprintf("%02d", int(($total % 3600) / 60));
+ my $s = sprintf("%02d", $total % 60);
+ $OUT .= qq!<TR><TD></TD><TD></TD>!;
+ $OUT .= qq!<TD ALIGN="right"><HR></TD>! x 3;
+ $OUT .= qq!</TR>!;
+ $OUT .= qq!<TR><TD></TD><TD></TD><TD ALIGN="right">$h:$m:$s</TD>!;
+ $OUT .= qq!<TD ALIGN="right">!;
+ $OUT .= Number::Format::format_bytes($utotal, precision => 2). qq!</TD>!;
+ $OUT .= qq!<TD ALIGN="right">!;
+ $OUT .= Number::Format::format_bytes($dtotal, precision => 2). qq!</TD>!;
+ $OUT .= qq!</TR>!; %>
+
+</TABLE>
+<BR>
+
+</TD></TR></TABLE>
+<%= include('footer') %>
diff --git a/fs_selfservice/FS-SelfService/cgi/xmlrpc.cgi b/fs_selfservice/FS-SelfService/cgi/xmlrpc.cgi
new file mode 100644
index 000000000..559ae04d8
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/xmlrpc.cgi
@@ -0,0 +1,18 @@
+#!/usr/bin/perl -Tw
+
+use strict;
+use XMLRPC::Transport::HTTP;
+use XMLRPC::Lite; # for XMLRPC::Serializer
+use FS::SelfService::XMLRPC;
+
+my %typelookup = (
+ base64 => [10, sub {$_[0] =~ /[^\x09\x0a\x0d\x20-\x7f]/}, 'as_base64'],
+ dateTime => [35, sub {$_[0] =~ /^\d{8}T\d\d:\d\d:\d\d$/}, 'as_dateTime'],
+ string => [40, sub {1}, 'as_string'],
+);
+my $serializer = new XMLRPC::Serializer(typelookup => \%typelookup);
+
+XMLRPC::Transport::HTTP::CGI->dispatch_to('FS::SelfService::XMLRPC')
+ ->serializer($serializer)
+ ->handle;
+
diff --git a/fs_selfservice/FS-SelfService/freeside-selfservice-clientd b/fs_selfservice/FS-SelfService/freeside-selfservice-clientd
new file mode 100644
index 000000000..bdc8e1547
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/freeside-selfservice-clientd
@@ -0,0 +1,272 @@
+#!/usr/bin/perl -w
+#
+# freeside-selfservice-clientd
+#
+# This is run REMOTELY over ssh by freeside-selfservice-server
+
+use strict;
+use subs qw(spawn logmsg lock_write unlock_write);
+use Fcntl qw(:flock);
+use POSIX qw(:sys_wait_h);
+use Socket;
+use Storable 2.09 qw(nstore_fd fd_retrieve);
+use IO::Handle qw(_IONBF);
+use IO::Select;
+use IO::File;
+
+#STDOUT->setbuf('');
+
+my $tag = scalar(@ARGV) ? '.'.shift : '';
+
+use vars qw( $Debug );
+$Debug = 2; #2 will turn on child logging
+ #3 will log packet contents,#including passwords
+ #4 will log receipts of all packets from server including
+ # keepalives (big!)
+
+my $socket = "/usr/local/freeside/selfservice_socket$tag";
+my $pid_file = "$socket.pid";
+
+my $log_file = "/usr/local/freeside/selfservice$tag.log";
+
+my $lock_file = "/usr/local/freeside/selfservice$tag.writelock";
+
+#my $me = '[client]';
+
+$|=1;
+
+$SIG{__WARN__} = \&_logmsg;
+
+#read data to be cached or something
+#warn "$me Reading init data\n" if $Debug;
+#my $signup_init =
+
+warn "Creating $lock_file\n" if $Debug;
+open(LOCKFILE,">$lock_file") or die "can't open $lock_file: $!";
+close LOCKFILE;
+
+warn "Creating $socket\n" if $Debug;
+my $uaddr = sockaddr_un($socket);
+my $proto = getprotobyname('tcp');
+socket(Server,PF_UNIX,SOCK_STREAM,0) or die "socket: $!";
+unlink($socket);
+bind(Server, $uaddr) or die "bind: $!";
+listen(Server,SOMAXCONN) or die "listen: $!";
+
+if ( -e $pid_file ) {
+ open(PIDFILE,"<$pid_file");
+ my $old_pid = <PIDFILE>;
+ close PIDFILE;
+ if ( $old_pid =~ /^(\d+)$/ ) {
+ kill 'TERM', $1;
+ }
+}
+open(PIDFILE,">$pid_file");
+print PIDFILE "$$\n";
+close PIDFILE;
+
+#my $waitedpid;
+#sub REAPER { $waitedpid = wait; $SIG{CHLD} = \&REAPER; }
+#$SIG{CHLD} = \&REAPER;
+
+warn "enabling keep alives\n" if $Debug;
+nstore_fd( { _packet => '_enable_keepalive' } , \*STDOUT );
+
+warn "entering main loop\n" if $Debug;
+
+my %kids;
+
+my $s = new IO::Select;
+$s->add(\*STDIN);
+$s->add(\*Server);
+
+#for ( $waitedpid = 0;
+# accept(Client,Server) || $waitedpid;
+# $waitedpid = 0, close Client)
+#{
+# next if $waitedpid;
+
+#$SIG{PIPE} = sub { warn "SIGPIPE received" };
+#$SIG{CHLD} = sub { warn "SIGCHLD received" };
+
+#sub REAPER { warn "SIGCHLD received"; my $pid = wait; $SIG{CHLD} = \&REAPER; }
+#sub REAPER { my $pid = wait; $SIG{CHLD} = \&REAPER; }
+#sub REAPER { my $pid = wait; delete $kids{$pid}; $SIG{CHLD} = \&REAPER; }
+#$SIG{CHLD} = \&REAPER;
+
+my $undisp = 0;
+while (1) {
+
+ &reap_kids;
+
+ warn "waiting for connection\n" if $Debug && !$undisp;
+
+ #my @handles = $s->can_read();
+ my @handles = $s->can_read(5);
+ $undisp = !scalar(@handles);
+ foreach my $handle ( @handles ) {
+
+ if ( $handle == \*STDIN ) {
+
+ warn "receiving packet from server\n" if $Debug > 3;
+
+ my $packet = fd_retrieve(\*STDIN);
+ my $token = $packet->{'_token'};
+
+ if ( $token eq '_keepalive' ) {
+ $undisp = 1;
+ next;
+ }
+
+ warn "received packet from server with token $token\n".
+ ( $Debug > 2
+ ? join('', map { " $_=>$packet->{$_}\n" } keys %$packet )
+ : '' )
+ if $Debug;
+
+ if ( exists($kids{$token}) ) {
+ warn "sending return packet to $token via $kids{$token}\n"
+ if $Debug;
+ nstore_fd($packet, $kids{$token});
+ warn "flushing to $token\n" if $Debug;
+ until ( $kids{$token}->flush ) {
+ warn "WARNING: error flushing: $!";
+ sleep 1;
+ }
+ #no close or delete here - will block waiting for child
+ warn "done with $token\n" if $Debug;
+ } else {
+ warn "WARNING: unknown token $token, discarding message";
+ }
+
+ } elsif ( $handle == \*Server ) {
+
+ until ( accept(Client, Server) ) {
+ warn "WARNING: accept failed: $!";
+ next;
+ }
+
+ warn "received local connection; forking\n" if $Debug;
+
+ spawn sub { #child
+ warn "[child-$$] reading packet from local client" if $Debug > 1;
+ my $packet = fd_retrieve(\*Client);
+ warn "[child-$$] packet received:\n".
+ join('', map { " $_=>$packet->{$_}\n" } keys %$packet )
+ if $Debug > 2;
+ my $command = $packet->{'command'};
+ #handle some commands weirdly?
+ $packet->{_token}=$$;
+
+ warn "[child-$$] locking write stream\n" if $Debug > 1;
+ lock_write;
+
+ warn "[child-$$] sending packet to remote server\n" if $Debug > 1;
+ nstore_fd($packet, \*STDOUT) or die "FATAL: can't send response: $!";
+
+ warn "[child-$$] flushing write stream\n" if $Debug > 1;
+ STDOUT->flush or die "FATAL: can't flush: $!";
+
+ warn "[child-$$] releasing write lock\n" if $Debug > 1;
+ unlock_write;
+
+ warn "[child-$$] closing write stream\n" if $Debug > 1;
+ close STDOUT or die "FATAL: can't close write stream: $!"; #??!
+
+ warn "[child-$$] waiting for response from parent\n" if $Debug > 1;
+ my $w = new IO::Select;
+ $w->add(\*STDIN);
+ until ( $w->can_read ) {
+ warn "[child-$$] WARNING: interrupted select: $!\n";
+ }
+ my $rv = fd_retrieve(\*STDIN);
+
+ #close STDIN;
+
+ warn "[child-$$] sending response to local client" if $Debug > 1;
+ nstore_fd($rv, \*Client);
+ Client->flush or die "FATAL: can't flush to local client: $!";
+ close Client or die "FATAL: can't close connection to local client: $!";
+
+ warn "[child-$$] child exiting" if $Debug > 1;
+ exit;
+
+ }; #eo child
+
+ #close Client;
+
+ } else {
+ die "wtf? $handle";
+ }
+
+ }
+
+}
+
+sub reap_kids {
+ #warn "reaping kids\n";
+ foreach my $pid ( keys %kids ) {
+ my $kid = waitpid($pid, WNOHANG);
+ if ( $kid > 0 ) {
+ close $kids{$kid};
+ delete $kids{$kid};
+ }
+ }
+ #warn "done reaping\n";
+}
+
+sub spawn {
+ my $coderef = shift;
+
+ unless (@_ == 0 && $coderef && ref($coderef) eq 'CODE') {
+ use Carp;
+ confess "usage: spawn CODEREF";
+ }
+
+ my $pid;
+ #if (!defined($pid = fork)) {
+ my $kid = new IO::Handle;
+ if (!defined($pid = open($kid, '|-'))) {
+ warn "WARNING: cannot fork: $!";
+ return;
+ } elsif ($pid) {
+ warn "begat $pid" if $Debug;
+ $kids{$pid} = $kid;
+ #$kids{$pid}->autoflush;
+ return; # I'm the parent
+ }
+ # else I'm the child -- go spawn
+
+# open(STDIN, "<&Client") || die "can't dup client to stdin";
+# open(STDOUT, ">&Client") || die "can't dup client to stdout";
+# open(STDERR, ">&STDOUT") || die "can't dup stdout to stderr";
+ exit &$coderef();
+}
+
+sub _logmsg {
+ chomp( my $msg = shift );
+ my $log = new IO::File ">>$log_file";
+ die "can't open $log_file: $!" unless defined($log);
+ flock($log, LOCK_EX);
+ seek($log, 0, 2);
+ print $log "[client] [". scalar(localtime). "] [$$] $msg\n";
+ flock($log, LOCK_UN);
+ close $log;
+}
+
+sub lock_write {
+ #broken on freebsd?
+ #flock(STDOUT, LOCK_EX) or die "FATAL: can't lock write stream: $!";
+
+ #open a new one for each kid to get a unique lock
+ open(LOCKFILE,">$lock_file") or die "can't open $lock_file: $!";
+
+ flock(LOCKFILE, LOCK_EX) or die "FATAL: can't lock $lock_file: $!";
+}
+
+sub unlock_write {
+ #broken on freebsd?
+ #flock(STDOUT, LOCK_UN) or die "FATAL: can't release write lock: $!";
+
+ flock(LOCKFILE, LOCK_UN) or die "FATAL: can't unlock $lock_file: $!";
+}
diff --git a/fs_selfservice/FS-SelfService/freeside-selfservice-xmlrpc-server b/fs_selfservice/FS-SelfService/freeside-selfservice-xmlrpc-server
new file mode 100644
index 000000000..bd4f83b3c
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/freeside-selfservice-xmlrpc-server
@@ -0,0 +1,59 @@
+#!/usr/bin/perl -w
+#
+# freeside-selfservice-xmlrpc-server
+#
+
+use strict;
+use Fcntl qw(:flock);
+use POSIX;
+use Getopt::Std;
+use XMLRPC::Transport::HTTP;
+use XMLRPC::Lite; # for XMLRPC::Serializer;
+use FS::SelfService::XMLRPC;
+
+use vars qw( $opt_p $opt_d );
+use vars qw( $DEBUG );
+
+getopts("p:d");
+$DEBUG = $opt_d;
+my $tag = $opt_p ? ':'.$opt_p : '';
+
+my %typelookup = (
+ base64 => [10, sub {$_[0] =~ /[^\x09\x0a\x0d\x20-\x7f]/}, 'as_base64'],
+ dateTime => [35, sub {$_[0] =~ /^\d{8}T\d\d:\d\d:\d\d$/}, 'as_dateTime'],
+ string => [40, sub {1}, 'as_string'],
+);
+my $serializer = new XMLRPC::Serializer(typelookup => \%typelookup);
+
+my $log_file = "/usr/local/freeside/selfservice.xmlrpc$tag.log";
+
+my $pid = fork;
+defined($pid) or die "Can't fork to start: $!";
+print "Started daemon with pid $pid\n" if $pid;
+exit if $pid;
+
+POSIX::setsid();
+open STDIN, "/dev/null" or die "Can't get rid of STDIN";
+open STDOUT, ">/dev/null" or die "Can't get rid of STDOUT";
+open STDERR, ">&STDOUT" or die "Can't get rid of STDERR";
+
+$SIG{__WARN__} = \&_logmsg;
+$SIG{__DIE__} = sub { &_logmsg(@_); exit };
+
+my $daemon = XMLRPC::Transport::HTTP::Daemon
+ ->new(LocalPort => $opt_p ? $opt_p : 8080)
+ ->dispatch_to('FS::SelfService::XMLRPC')
+ ->serializer($serializer);
+
+warn "Handling request at ", $daemon->url, "\n";
+$daemon->handle;
+
+sub _logmsg {
+ chomp( my $msg = shift );
+ my $log = new IO::File ">>$log_file";
+ flock($log, LOCK_EX);
+ seek($log, 0, 2);
+ print $log "[". scalar(localtime). "] [$$] $msg\n";
+ flock($log, LOCK_UN);
+ close $log;
+}
diff --git a/fs_selfservice/FS-SelfService/ieak.template b/fs_selfservice/FS-SelfService/ieak.template
new file mode 100755
index 000000000..52edaa951
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/ieak.template
@@ -0,0 +1,40 @@
+[Entry]
+Entry_Name = The Internet
+[Phone]
+Dial_As_Is=no
+Phone_Number = { $exch. $loc }
+Area_Code = { $ac }
+Country_Code = 1
+Country_Id = 1
+[Server]
+Type = PPP
+SW_Compress = Yes
+PW_Encrypt = Yes
+Negotiate_TCP/IP = Yes
+Disable_LCP = No
+[TCP/IP]
+Specify_IP_Address = No
+Specity_Server_Address = No
+IP_Header_Compress = Yes
+Gateway_On_Remote = Yes
+[User]
+Name = { $username }
+Password = { $password }
+Display_Password = Yes
+[Internet_Mail]
+Email_Name = { $email_name }
+Email_Address = { $username }\@domain.tld
+POP_Server = mail.domain.tld
+POP_Server_Port_Number = 110
+POP_Login_Name = { $username }
+POP_Login_Password = { $password }
+SMTP_Server = mail.domain.tld
+SMTP_Server_Port_Number = 25
+Install_Mail = 1
+[Internet_News]
+NNTP_Server = news.domain.tld
+NNTP_Server_Port_Number = 119
+Logon_Required = No
+Install_News = 1
+[Branding]
+Window_Title = The Internet
diff --git a/fs_selfservice/FS-SelfService/test.pl b/fs_selfservice/FS-SelfService/test.pl
new file mode 100644
index 000000000..7468ea471
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/test.pl
@@ -0,0 +1,17 @@
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl test.pl'
+
+#########################
+
+# change 'tests => 1' to 'tests => last_test_to_print';
+
+use Test;
+BEGIN { plan tests => 1 };
+use FS::SelfService;
+ok(1); # If we made it this far, we're ok.
+
+#########################
+
+# Insert your test code below, the Test module is use()ed here so read
+# its man page ( perldoc Test ) for help writing this test script.
+
diff --git a/fs_selfservice/fri/CHANGE.log b/fs_selfservice/fri/CHANGE.log
new file mode 100644
index 000000000..f25712b80
--- /dev/null
+++ b/fs_selfservice/fri/CHANGE.log
@@ -0,0 +1,271 @@
+
+
+Change log - 05/02/2006
+
+ * update of french translation (submitted by Xavier Ourcière)
+
+Change log - 04/28/2006
+
+ * changed PEAR portability flags to try and fix a bug a user is having (maybe a buggy or old version of PEAR on users machine)
+ * fixed no voicemail message to be more intuitive
+ * fixed ajax bug
+ * fixed German i18n translation bug (requested by Wanninger)
+ * fixed settings recording format bug
+ * fixed settings call forward bug
+
+Change log - 04/10/2006
+
+ * added autoplay of recordings (requested by Robert LaPoint)
+ * refactored the response from the asterisk manager interface so do not always have to strip off "value:" from the response
+
+Change log - 04/04/2006
+
+ * abstracted the doc_root (PHP_SELF) to a variable to handle cases where it is not set properly (requested by Diego Iastrubni)
+ * removed error message about user voicemail directory (submitted by Diego Iastrubni)
+ * added feature to login to allow voicemail include files with wildcards (submitted by Diego Iastrubni)
+ * made voicemail password length message more accurate and descriptive on settings page (submitte by Robert Colbert)
+ * added outbound caller id record matching for call monitor page for results returned to individual users (requested by Robert LaPoint)
+ * fixed AJAX bug that kept giving javascript errors. Now form, pass, and parse a full xml doc
+ * fixed bug in description of dial code in help settings page (submitte by Robert Colbert)
+ * fixed bug to disable AJAX if using a browser that does not support AJAX
+ * updated Italian Translation (contributed by Francesco Romano: alteclab.it)
+
+Change log - 03/31/2006
+
+ * updated Spanish Translation (contributed by Antonio Cano damas: igestec.com)
+
+Change log - 03/29/2006
+
+ * added support for voicemail.conf include files (requested by Diego Iastrubni)
+ * updated database connection to support sqlite (and other databases using a connect file) (requested by Diego Iastrubni)
+
+Change log - 03/28/2006
+
+ * updated for PHP5 support
+ * fixed bug in AJAX javascript (fix submitted by Mahmud Fatafta - voicemetro.com)
+
+Change log - 03/23/2006
+
+ * remove variable references in function calls for PHP5 support (PHP4 supports, PHP5 does not, go figure)
+
+Change log - 03/18/2006
+
+ * fixed setting page voicemail options bug (submitted by Dave Vaughn: techcompinc.com)
+ * fixed settings page record settings FreePBX version bug (submitted by Luca Pandolfini)
+
+Change log - 03/13/2006
+
+ * added navigation menus to ajax update
+ * changed voicemail password on settings page so it can be variable length (submitted by vgster)
+ * fixed bug with settings page check boxes
+
+Change log - 03/09/2006
+
+ * fixed bug in error reporting for asterisk config files or recording file directories missing
+ * fixed bug for voicemail message move to perserve permissions, group, and user
+ * fixed bug in .inc and .conf file security (submitted by Diego Iastrubni, François Harvey: securiweb.net, and Adam Gray: novacoast.com)
+
+Change log - 03/07/2006
+
+ * added ajax seemless page refresh to callmonitor and voicemail
+ * added recording playback encryption (requested by François Harvey: securiweb.net)
+ * added ajax page refresh for voicemail and callmonitor (will seemlessly update page realtime)
+ * fixed bug in file permissions when a voicemail was moved (submitted by ?)
+
+Change log - 02/22/2006
+
+ * added filter to not load code not needed if a module is not loaded (submitted by Diego Iastrubni)
+ * refactored asterisk manager interface class to not require password lookup in common and asi files
+ * fixed module admin bug (submitted by serger)
+
+Change log - 02/14/2006
+
+ * added callmonitor duration filter to filter out short length calls (sponsored by John Cardner, Phonoscope, Inc)
+
+Change log - 02/09/2006
+
+ * added voicemail email and pager settings
+ * more rework of callmonitor recording match to handle large volumes of recordings (sponsored by John Cardner, Phonoscope, Inc)
+
+Change log - 02/07/2006
+
+ * added check for PHP PEAR installation
+ * added check for proper communication with the Asterisk Manager
+ * fixed class coding standard (ie ClassName)
+ * fixed method coding standard (ie methodName)
+ * fixed variable coding standard (ie variable_name)
+ * fixed constant coding standard (ie CONSTANT_NAME)
+ * added config option for voicemail password length (submitted by Chuck Bunn)
+ - set with $SETTINGS_VOICEMAIL_PASSWORD_LENGTH in /includes/main.conf
+ * added voicemail audio format admin option in settings page (submitted by Chuck Bunn)
+ - set with $ARI_VOICEMAIL_AUDIO_FORMAT_DEFAULT in /includes/main.conf
+ * fixed bug to separate voicemail password set in settings page (submitted by Chuck Bunn)
+
+Change log - 02/05/2006
+
+ * added call forward setting
+ * added Hebrew Translation (submitted by Diego Iastrubni)
+ * fixed i18n translation best practices and bugs (submitted by Diego Iastrubni)
+ * fixed voicemail message move bug (submitted by Steve Davies)
+ * fixed voicemail folder creation permissions issue (submitted by Steve Davies)
+
+Change log - 01/31/2006
+
+ * added help page
+ * added file lookup limiting code to prevent hanging when extremely large numbers of files are found in a directory
+ * added database type global variable
+
+Change log - 01/26/2006
+
+ * added php 4 or later version checking
+ * fixed php pre 4.3 version compatability
+ * fixed buy in call manager file matching recursively searching directories (submitted by Adrian Carter)
+
+Change log - 01/20/2006
+
+ * added call monitor aggressive matching option
+
+Change log - 01/18/2006
+
+ * added Hungarian Translation (submitted by Diego Imre Csaba Varasdy)
+ * fixed bug for Asterisk Manager change in Asterisk 1.2
+
+Change log - 01/12/2006
+
+ * added column sort to voicemail page (requested by Diego Elias Sofronas)
+ * added column sort to call monitor page (requested by Elias Sofronas)
+ * added i18n lang select to login page (requested by Diego Iastrubni)
+
+Change log - 12/09/2005
+
+ * another fix to the on-demand call monitor recordings (submitted by Blake Krone)
+
+Change log - 12/09/2005
+
+ * fix to recognize on-demand call monitor recordings (identified as auto-...) (submitted by Francesco Romano, Antonio Cano Damas, and Jason P. Meyer)
+ * added German Translation (submitted by Till Stoermer)
+
+Change log - 12/07/2005
+
+ * fixed search bug (submitted by Francesco Romano)
+ * fixed formating bugs
+
+Change log - 12/01/2005
+
+ * fix delete, move_to, and forward_to voicemail buttons for i18n translations
+ * fix delete call monitor button for i18n translations
+ * fix call monitor file matching problem if call time is a second or two later than time recorded in database log (submitted by Will Prater, Steve D, and others)
+ * changed to get call recording settings from asterisk and not the mysql database to support ARI standalone
+ * fix i18n for recording popup (submitted by Antonio Cano Damas)
+ * added search for voicemail
+ * added class to handle Asterisk Manager Interface (phpagi-asmanager.php would need error handling added)
+ * moved i18n language functions to own file so can support i18n in recording popup
+ * added Italian (submitted by Francesco Romano)
+ * updated Spanish translation (submitted by Antonio Cano Damas)
+ * fixed bugs in standalone code (sponsored by Hugh Buitano and also submitted by John Biundo)
+ * fixed logo (submitted by John Biundo)
+ * cleaned up css for misc/audio.php
+
+Change log - 11/17/2005
+
+ * added protocol multi-config_file (iax,sip,zap) support (sponsored by Hugh Buitano, Infosecure Systems)
+ * add global variables for asterisk and asteriskcdr database hosts and names (sponsored by Hugh Buitano, Infosecure Systems)
+ * added French translation (submitted by Joachim Buron-Pilatre, Phileas Com)
+ * fixed bug (submitted by Joachim Buron-Pilatre, Phileas Com)
+
+Change log - 11/13/2005
+
+ * refactored login context support
+ * added voicemail context support (submitted by Todd Courtnage)
+ * fixed voicemail sub nav folders to allow i18n translation (submitted by Elias Sofronas)
+ * fixed voicemail finding messages in different contexts (sponsored by Brian Connelly, Connelly Management)
+
+Change log - 11/09/2005
+
+ * fixed utf-8 translation in Greek (submitted by Elias Sofronas)
+ * added admin only access to specific modules (submitted by Julian J. M.)
+ * rework handler module code so that each module is only build one time
+ * added download message link on recording playback popup (sponsored by John Cardner, Phonoscope, Inc)
+ * converted i18n translation to utf-8 (submitted by Niklas Larsson and Elias Sofronas)
+ * fix more bugs in i18n translation (submitted by Niklas Larsson)
+ * fixed security bug that allowed access to all files (Edwin Eefting, syn-3.nl)
+
+Change log - 11/04/2005
+
+ * fixed bug to reload asterisk voicemail after voicemail password setting change (submitted by Jason Becker)
+
+Change log - 11/03/2005
+
+ * Highlight which voicemail sub-folder in use (submitted by Elias Sofronas)
+ * set default i18n page (suggested by Niklas Larsson)
+ * admin only account for call monitor (submitted by Julian J. M.)
+ * enhanced pattern matching call monitor unique id from database (submitted by Julian J. M.)
+ * updated Spanish translation (submitted by Diego Iastrubni)
+ * added Swedish translation (submitted by Niklas Larsson)
+ * added Greek translation (submitted by Elias Sofronas)
+ * fixed bug in call recording settings method (changed in AMP 1.10.009)
+ * fix bugs in i18n translation (submitted by Niklas Larsson)
+ - buttons, left menus, select all | none, Call Monitor (heading), Login page.
+
+Change log - 10/21/2005
+
+ * fixed bug in voicemail navigation (submitted by Elias Sofronas)
+ * added version cleanup
+ * added Spanish translation (submitted by Susana Castillo)
+ * added Portuguese translation (submitted by Alejandro Duplat)
+ * added admin setting for call recording
+
+Change log - 09/30/2005
+
+ * added i18n language support
+ * fixed bug if no folder or extension was selected and "move_to" or
+ "forward_to" clicked (bug submitted by Elias Sofronas)
+ * converted modules to a OO plugin architecture
+ * added version to footer
+ * add theme customization
+ * added recording type support (.WAV, .GSM) on settings page
+ * fixed bug to find call recording files better (patch submitted by Mark Voevodin)
+ * fixed bug for navigation and search controls to link to correct folder (bug submitted by Elias Sofronas)
+ * added voicemail password change to settings page
+ * added call monitor delete recording functionality (does not delete database entry)
+ * added call recording settings on settings page
+
+Change log - 09/15/2005
+
+ * added settings page
+ * added call monitor record options on settings page
+ * fixed bug to view src and dst calls in call monitor when restricted (submitted by Elias Sofronas and Thomas Stalder)
+
+Change log - 08/25/2005
+
+ * added SIP authentication login (this does not allow voicemail access)
+ * added persistent passwords (cookies)
+ * added encryption for cookies
+
+Change log - 08/23/2005
+
+ * Fixed $_SESSION['user'] bug conflict with AMP
+ -> changed to $_SESSION['ari_user']
+ * Fixed recording file lookup bug.
+
+Change log - 08/16/2005
+
+ * Fixed formating bug in css
+ * Added multipath to call monitor recordings
+ - set with $asterisk_callmonitor_path in /includes/main.conf
+ * added authentication
+ - use voicemail password
+ - access mailbox voicemail
+ - access call monitor for mailbox
+ - use AMP password
+ - access call monitor for all users
+ - config to allow voicemail to have call monitor access to all users
+ * voicemail access
+ - search of mailbox
+ - easy to delete voicemail interface
+ - move voicemail interface
+ - forward voicemail interface
+
+
+
+ \ No newline at end of file
diff --git a/fs_selfservice/fri/LICENSE.txt b/fs_selfservice/fri/LICENSE.txt
new file mode 100644
index 000000000..c09b19cdd
--- /dev/null
+++ b/fs_selfservice/fri/LICENSE.txt
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/fs_selfservice/fri/README.txt b/fs_selfservice/fri/README.txt
new file mode 100644
index 000000000..2e3b9088f
--- /dev/null
+++ b/fs_selfservice/fri/README.txt
@@ -0,0 +1,123 @@
+Developed by Dan Littlejohn of Littlejohn Consulting.
+ www.littlejohnconsulting.com
+
+Released under the GPL.
+
+Send bug reports, requests to dan@littlejohnconsulting.com
+
++++
+
+Misc notes
+
+ARI Project Page
+ www.littlejohnconsulting.com?q=ari
+
+Coding standard
+ * class - CamelCase (ie ClassName)
+ * method camelCase (ie methodName)
+ * variable underscore (ie variable_name)
+ * constant UNDERSCORE (ie CONSTANT_NAME)
+
+Requirements
+ PHP4 (but PHP5 is not yet supported)
+ PHP PEAR
+ asterisk 1.2 or later
+ apache or apache2
+ asterisk manager - at a mininum need command access
+
+security
+ for security all the files in ./recordings/include should be locked down in the web browser
+ so they cannot be viewed.
+
+voicemail email links - For those who would like to include a link to ARI in the voicemail email and set the correct login (mailbox) you can do so as:
+
+ http://< ip address >/recordings/index.php?login=< login >
+
+ replace
+ < ip address > with the server dns or ip
+ < login > with the login or mailbox
+
++++
+
+Module API
+
+odules can be added or removed from ARI.
+
+API
+
+must include these methods.
+
+rank - weights were the module menu item will appear in the navigation window
+init - initialize the module. Database access should first appear here and not in the constructor
+navMenu - side navigation menu item
+display - main module page content
+
+example
+
+<?php
+
+/**
+ * @file
+ * Functions for the interface to the help page
+ */
+
+/**
+ * Class for new_module
+ */
+class NewModule {
+
+ /*
+ * rank (for prioritizing modules)
+ */
+ function rank() {
+
+ $rank = 50;
+ return $rank;
+ }
+
+ /*
+ * init
+ */
+ function init() {
+ }
+
+ /*
+ * Adds menu item to nav menu
+ *
+ * @param $args
+ * Common arguments
+ */
+ function navMenu($args) {
+
+ // put if statement in return string, because do not know $logout until page is built
+ $ret .= "
+ <?php if ($logout !='') { ?>
+ <p><small><small><a href='" . $_SERVER['PHP_SELF'] . "?m=NewModule&f=display'>" . _("new_module") . "</a></small></small></p>
+ <?php } ?>";
+
+ return $ret;
+ }
+
+ /*
+ * Displays stats page
+ *
+ * @param $args
+ * Common arguments
+ */
+ function display($args) {
+
+ // build page content
+ $ret .= checkErrorMessage();
+
+ $ret .= $display->displayHeaderText("new_module");
+ $ret .= $display->displayLine();
+
+ return $ret;
+ }
+
+}
+
+
+?>
+
+
diff --git a/fs_selfservice/fri/includes/ajax.php b/fs_selfservice/fri/includes/ajax.php
new file mode 100644
index 000000000..fc7961b08
--- /dev/null
+++ b/fs_selfservice/fri/includes/ajax.php
@@ -0,0 +1,132 @@
+<?php
+
+/*
+ * AJAX page update script
+ */
+function ajaxRefreshScript($args) {
+
+ global $AJAX_PAGE_REFRESH_TIME;
+
+ $url_args = "?ajax_refresh=1&";
+ foreach($args as $key => $value) {
+ $url_args .= $key . "=" . $value . "&";
+ }
+ $url_args = substr($url_args, 0,strlen($url_args)-1);
+
+ $ret = "
+ <script type='text/javascript' language='javascript'>
+
+ var http_request = false;
+
+ function makeRequest(url, parameters) {
+
+ http_request = false;
+
+ if (window.XMLHttpRequest) { // Mozilla, Safari,...
+ http_request = new XMLHttpRequest();
+ if (http_request.overrideMimeType) {
+ http_request.overrideMimeType('text/xml');
+ }
+ }
+ else if (window.ActiveXObject) { // IE
+ try {
+ http_request = new ActiveXObject('Msxml2.XMLHTTP');
+ }
+ catch (e) {
+ try {
+ http_request = new ActiveXObject('Microsoft.XMLHTTP');
+ }
+ catch (e) {}
+ }
+ }
+ if (!http_request) {
+ return false;
+ }
+ http_request.onreadystatechange = alertContents;
+ http_request.open('GET', url + parameters, true);
+ http_request.send(null);
+ }
+
+ function alertContents() {
+
+ if (!http_request) {
+ return;
+ }
+
+ if (http_request.readyState == 4) {
+ if (http_request.status == 200) {
+
+ var result = http_request.responseXML;
+ if (!result.documentElement && http_request.responseStream) {
+ result.load(http_request.responseStream);
+ }
+
+ var response = http_request.responseXML.documentElement;
+
+ var nav_menu = '';
+ if (response.getElementsByTagName('nav_menu')[0]) {
+ nav_menu = response.getElementsByTagName('nav_menu')[0].firstChild.data;
+ }
+ var nav_submenu = '';
+ if (response.getElementsByTagName('nav_submenu')[0]) {
+ nav_submenu = response.getElementsByTagName('nav_submenu')[0].firstChild.data;
+ }
+ var content = '';
+ if (response.getElementsByTagName('content')[0]) {
+ content = response.getElementsByTagName('content')[0].firstChild.data;
+ }
+
+ if (nav_menu) {
+ document.getElementById('nav_menu').innerHTML = '';
+ document.getElementById('nav_menu').innerHTML = nav_menu;
+ }
+ if (nav_submenu) {
+ document.getElementById('nav_submenu').innerHTML = '';
+ document.getElementById('nav_submenu').innerHTML = nav_submenu;
+ }
+ if (content) {
+ document.getElementById('content').innerHTML = '';
+ document.getElementById('content').innerHTML = content;
+ }
+ }
+ }
+ }
+
+ function updatePage() {
+ makeRequest('" . $_SESSION['ARI_ROOT'] . "', '" . $url_args . "');
+ }
+
+ // refresh time in 'minutes:seconds' (0 to inifinity) : (0 to 59)
+ var refresh_time='" . $AJAX_PAGE_REFRESH_TIME . "';
+
+ if (document.images){
+ var limit=refresh_time.split(\":\");
+ limit=limit[0]*60+limit[1]*1;
+ var current = limit;
+ }
+
+ function beginRefresh(){
+
+ if (!document.images) {
+ return;
+ }
+ if (current==1) {
+ updatePage();
+ current = limit;
+ }
+ else {
+ current-=1;
+ }
+
+ setTimeout(\"beginRefresh()\",1000);
+ }
+
+ window.onload=beginRefresh;
+
+ </script>";
+
+ return $ret;
+}
+
+
+?> \ No newline at end of file
diff --git a/fs_selfservice/fri/includes/asi.php b/fs_selfservice/fri/includes/asi.php
new file mode 100644
index 000000000..62f221e2f
--- /dev/null
+++ b/fs_selfservice/fri/includes/asi.php
@@ -0,0 +1,156 @@
+<?php
+
+/**
+ * @file
+ * Asterisk manager interface for access to asterisk api (astdb)
+ */
+
+/**
+ * Asterisk Manager Interface
+ */
+class AsteriskManagerInterface {
+
+ var $socket;
+
+ /**
+ * constructor
+ */
+ function AsteriskManagerInterface() {
+ }
+
+ /*
+ * Reloads Asterisk Configuration
+ *
+ * @param $username
+ * asterisk manager interface username
+ * @param $password
+ * asterisk manager interface password
+ */
+ function connect($host,$username,$password) {
+
+ // connect
+ $fp = fsockopen($host, 5038, $errno, $errstr, 10);
+ if (!$fp) {
+ return FALSE;
+ }
+ else {
+ $buffer='';
+ if(version_compare(phpversion(), '4.3', '>=')) {
+ stream_set_timeout($fp, 5);
+ }
+ else {
+ socket_set_timeout($fp, 5);
+ }
+ $buffer = fgets($fp);
+ if (!preg_match('/Asterisk Call Manager/i', $buffer)) {
+ $_SESSION['ari_error'] = _("Asterisk Call Manager not responding") . "<br />\n";
+ return FALSE;
+ }
+ else {
+ $out="Action: Login\r\nUsername: ".$username."\r\nSecret: ".$password."\r\n\r\n";
+ fwrite($fp,$out);
+ $buffer=fgets($fp);
+ if ($buffer!="Response: Success\r\n") {
+ $_SESSION['ari_error'] = _("Asterisk authentication failed:") . "<br />" . $buffer . "<br />\n";
+ return FALSE;
+ }
+ else {
+ $buffers=fgets($fp); // get rid of Message: Authentication accepted
+
+ // connected
+ $this->socket = $fp;
+ }
+ }
+ }
+ return TRUE;
+ }
+
+ /*
+ * Reloads Asterisk Configuration
+ */
+ function disconnect() {
+
+ if ($this->socket) {
+ fclose($this->socket);
+ }
+ }
+
+ /*
+ * Reloads Asterisk Configuration
+ *
+ * @param $command
+ * Command to be sent to the asterisk manager interface
+ * @return $ret
+ * response from asterisk manager interface
+ */
+ function command($command) {
+
+ $response = '';
+
+ fwrite($this->socket,$command);
+
+ $count = 0;
+ while (($buffer = fgets($this->socket)) && (!preg_match('/Response: Follows/i', $buffer))) {
+
+ if ($count>100) {
+ $_SESSION['ari_error'] = _("Asterisk command not understood") . "<br />" . $buffer . "<br />\n";
+ return FALSE;
+ }
+ $count++;
+ }
+
+ $count = 0;
+ while (($buffer = fgets($this->socket)) && (!preg_match('/END COMMAND/i', $buffer))) {
+
+ if (preg_match('/Value/',$buffer)) {
+ $parts = split(' ',trim($buffer));
+ $response = $parts[1];
+ }
+
+ if ($count>100) {
+ $_SESSION['ari_error'] = _("Asterisk command not understood") . "<br />" . $buffer . "<br />\n";
+ return;
+ }
+ $count++;
+ }
+
+ return $response;
+ }
+
+ function command2($command) {
+
+ $response = '';
+
+ fwrite($this->socket,$command);
+
+ $count = 0;
+ while (($buffer = fgets($this->socket)) && (!preg_match('/Response: Follows/i', $buffer))) {
+
+ if ($count>100) {
+ $_SESSION['ari_error'] = _("Asterisk command not understood") . "<br />" . $buffer . "<br />\n";
+ return FALSE;
+ }
+ $count++;
+ }
+
+ $count = 0;
+ while (($buffer = fgets($this->socket)) && (!preg_match('/END COMMAND/i', $buffer))) {
+
+ if (preg_match('/Value:/',$buffer)) {
+ $parts = split('Value:',trim($buffer));
+ $response = $parts[1];
+ }
+ if ($count>100) {
+ $_SESSION['ari_error'] = _("Asterisk command not understood") . "<br />" . $buffer . "<br />\n";
+ return;
+ }
+ $count++;
+ }
+
+ return $response;
+ }
+
+}
+
+
+?> \ No newline at end of file
diff --git a/fs_selfservice/fri/includes/bootstrap.php b/fs_selfservice/fri/includes/bootstrap.php
new file mode 100644
index 000000000..a01a2f5c8
--- /dev/null
+++ b/fs_selfservice/fri/includes/bootstrap.php
@@ -0,0 +1,315 @@
+<?php
+
+/**
+ * @file
+ * Functions that need to be loaded on every request.
+ */
+
+/**
+ * Sets doc root
+ */
+function setARIRoot() {
+
+ $found = 0;
+ if (isset($_SERVER['PHP_SELF'])) {
+ if ($_SERVER['PHP_SELF']!='') {
+ $_SESSION['ARI_ROOT'] = $_SERVER['PHP_SELF'];
+ }
+ }
+
+ if (!$found) {
+ $_SESSION['ARI_ROOT'] = "index.php";
+ }
+}
+
+/**
+ * Return a arguments.
+ *
+ * @param $args
+ * The name of the array being acted upon.
+ * @param $name
+ * The name of the variable to return.
+ * @return
+ * The value of the variable.
+ */
+function getArgument($args, $name) {
+
+ return isset($args[$name]) ? $args[$name] : '';
+}
+
+/*
+ * Gets top level directory names
+ *
+ * @param $path
+ * directory to search
+ * @param $filter
+ * string to use as a filter to match files to return
+ * @return $directories
+ * directories found
+ */
+function getDirectories($path,$filter) {
+
+ $directories = array();
+
+ if (is_dir($path)) {
+
+ $dh = opendir($path);
+ while (false!== ($item = readdir($dh))) {
+ if($item!="." && $item!="..") {
+
+ $path = fixPathSlash($path);
+ $directory = $path;
+ $directory = appendPath($directory,$item);
+
+ if (is_dir($directory)) {
+
+ $found = 0;
+ if ($filter) {
+ if (strpos($directory,$filter)) {
+ $found = 1;
+ }
+ } else {
+ $found = 1;
+ }
+ if ($found) {
+ $directories[count($directories) + 1] = $directory;
+ }
+ }
+ }
+ }
+ }
+
+ return $directories;
+}
+
+/*
+ * Gets file names recursively 6 folders deep
+ *
+ * @param $path
+ * directory to search
+ * @param $filter
+ * string to use as a filter to match files to return
+ * @param $recursive_max
+ * max number of sub folders to search
+ * @param $recursive_count
+ * current sub folder count
+ * @return $files
+ * files found
+ */
+function getFiles($path,$filter,$recursive_max,$recursive_count) {
+
+ $files = array();
+
+ if (@is_dir($path) && @is_readable($path)) {
+ $dh = opendir($path);
+ while (false!== ($item = readdir($dh))) {
+ if($item[0]!=".") {
+
+ $path = fixPathSlash($path);
+ $msg_path = appendPath($path,$item);
+
+ $fileCount++;
+ if ($fileCount>3000) {
+ $_SESSION['ari_error']
+ .= _("To many files in $msg_path Not all files processed") . "<br>";
+ return;
+ }
+
+ if ($recursive_count<$recursive_max && is_dir($msg_path)) {
+
+ $dirCount++;
+ if ($dirCount>10) {
+ $_SESSION['ari_error']
+ .= sprintf(_("To many directories in %s Not all files processed"),$msg_path) . "<br>";
+ return;
+ }
+
+ $count = $recursive_count + 1;
+ $path_files = getFiles($msg_path,$filter,$recursive_max,$count);
+ $files = array_merge($files,$path_files);
+ }
+ else {
+ $found = 0;
+ if ($filter) {
+ if (strpos($msg_path,$filter)) {
+ $found = 1;
+ }
+ } else {
+ $found = 1;
+ }
+ if ($found) {
+ $files[count($files) + 1] = $msg_path;
+ }
+ }
+ }
+ }
+ }
+
+ return $files;
+}
+
+/* Utilities */
+
+/**
+ * Fixes the path for a trailing slash
+ *
+ * @param $path
+ * path to append
+ * @return $ret
+ * path to returned
+ */
+function fixPathSlash($path) {
+
+ $ret = $path;
+
+ $slash = '';
+ if (!preg_match('/\/$/',$path)) {
+ $slash = '/';
+ }
+ $ret .= $slash;
+
+ return $ret;
+}
+
+/**
+ * Appends folder to end of path
+ *
+ * @param $path
+ * path to append
+ * @param $folder
+ * folder to append to path
+ * @return $ret
+ * path to returned
+ */
+function appendPath($path,$folder) {
+
+ $ret = $path;
+
+ $m = '';
+ if (!preg_match('/\/$/',$path)) {
+ $m = '/';
+ }
+ $ret .= $m . $folder;
+
+ return $ret;
+}
+
+/**
+ * Get Date format
+ *
+ * @param $timestamp
+ * timestamp to be converted
+ */
+function getDateFormat($timestamp) {
+ return date('Y-m-d', $timestamp);
+}
+
+/**
+ * Get time format
+ *
+ * @param $timestamp
+ * timestamp to be converted
+ */
+function getTimeFormat($timestamp) {
+ return date('G:i:s', $timestamp);
+}
+
+/* */
+
+/**
+ * Checks ARI dependencies
+ */
+function checkDependencies() {
+
+ // check for PHP
+ if (!version_compare(phpversion(), '4.3', '>=')) {
+ echo _("ARI requires a version of PHP 4.3 or later");
+ exit();
+ }
+
+ // check for PEAR
+ $include_path = ini_get('include_path');
+ $buf = split(':|,',$include_path);
+
+ $found = 0;
+ foreach ($buf as $path) {
+ $path = fixPathSlash($path);
+ $pear_check_path = $path . "DB.php";
+ if (is_file($pear_check_path)) {
+ $found = 1;
+ break;
+ }
+ }
+
+ if (!$found) {
+ echo _("PHP PEAR must be installed. Visit http://pear.php.net for help with installation.");
+ exit();
+ }
+}
+
+/**
+ * Starts the session
+ */
+function startARISession() {
+
+ if (!isset($_SESSION['ari_user']) ) {
+
+ // start a new session for the user
+ ini_set('session.name', 'ARI'); // prevent session name clashes
+ ini_set('session.gc_maxlifetime', '3900'); // make the session timeout a long time
+ set_time_limit(360);
+ session_start();
+ }
+}
+
+/**
+ * Bootstrap
+ *
+ * Loads critical variables needed for every page request
+ *
+ */
+function bootstrap() {
+
+ // set error reporting
+ error_reporting (E_ALL & ~ E_NOTICE);
+}
+
+/**
+ * Set HTTP headers in preparation for a page response.
+ *
+ * TODO: Figure out caching
+ */
+function ariPageHeader() {
+
+ bootstrap();
+}
+
+/**
+ * Perform end-of-request tasks.
+ *
+ * This function sets the page cache if appropriate, and allows modules to
+ * react to the closing of the page by calling hook_exit().
+ */
+function ariPageFooter() {
+
+}
+
+/**
+ * Includes and run functions
+ */
+
+include_once("./includes/lang.php");
+$language = new Language();
+$language->set();
+
+checkDependencies();
+startARISession();
+setARIRoot();
+
+include_once("./includes/main.conf.php");
+include_once("./version.php");
+include_once("./includes/crypt.php");
+include_once("./includes/login.php");
+
+
+?>
diff --git a/fs_selfservice/fri/includes/common.php b/fs_selfservice/fri/includes/common.php
new file mode 100644
index 000000000..87f202638
--- /dev/null
+++ b/fs_selfservice/fri/includes/common.php
@@ -0,0 +1,434 @@
+<?php
+
+/**
+ * @file
+ * common functions - core handler
+ */
+
+/*
+ * Checks if user is set and sets
+ */
+function checkErrorMessage() {
+
+ if ($_SESSION['ari_error']) {
+ $ret .= "<div class='error'>
+ " . $_SESSION['ari_error'] . "
+ </div>
+ <br>";
+ unset($_SESSION['ari_error']);
+ }
+
+ return $ret;
+}
+
+/*
+ * Checks modules directory, and configuration, and loaded modules
+ */
+function loadModules() {
+
+ global $ARI_ADMIN_MODULES;
+ global $ARI_DISABLED_MODULES;
+
+ global $loaded_modules;
+
+ $modules_path = "./modules";
+ if (is_dir($modules_path)) {
+
+ $filter = ".module";
+ $recursive_max = 1;
+ $recursive_count = 0;
+ $files = getFiles($modules_path,$filter,$recursive_max,$recursive_count);
+
+ foreach($files as $key => $path) {
+
+ // build module object
+ include_once($path);
+ $path_parts = pathinfo($path);
+ list($name,$ext) = split("\.",$path_parts['basename']);
+
+ // check for module and get rank
+ if (class_exists($name)) {
+
+ $module = new $name();
+
+ // check if admin module
+ $found = 0;
+ if ($ARI_ADMIN_MODULES) {
+ $admin_modules = split(',',$ARI_ADMIN_MODULES);
+ foreach ($admin_modules as $key => $value) {
+ if ($name==$value) {
+ $found = 1;
+ break;
+ }
+ }
+ }
+
+ // check if disabled module
+ $disabled = 0;
+ if ($ARI_DISABLED_MODULES) {
+ $disabled_modules = split(',',$ARI_DISABLED_MODULES);
+ foreach ($disabled_modules as $key => $value) {
+ if ($name==$value) {
+ $disabled = 1;
+ break;
+ }
+ }
+ }
+
+ // if not admin module or admin user add to module name to array
+ if (!$disabled && (!$found || $_SESSION['ari_user']['admin'])) {
+ $loaded_modules[$name] = $module;
+ }
+ }
+ }
+ }
+ else {
+ $_SESSION['ari_error'] = _("$path not a directory or not readable");
+ }
+}
+
+/**
+ * Builds database connections
+ */
+function databaseLogon() {
+
+ global $STANDALONE;
+
+ global $ASTERISKMGR_DBHOST;
+
+ global $AMP_FUNCTIONS_FILES;
+ global $AMPORTAL_CONF_FILE;
+
+ global $LEGACY_AMP_DBENGINE;
+ global $LEGACY_AMP_DBFILE;
+ global $LEGACY_AMP_DBHOST;
+ global $LEGACY_AMP_DBNAME;
+
+ global $ASTERISKCDR_DBENGINE;
+ global $ASTERISKCDR_DBFILE;
+ global $ASTERISKCDR_DBHOST;
+ global $ASTERISKCDR_DBNAME;
+
+ global $ARI_DISABLED_MODULES;
+
+ global $loaded_modules;
+
+ // This variable is a global in the FreePBX function.inc.php but needs to be
+ // declared here or the is not seen when parse_amprotaconf() is eventually called
+ // ?php bug?
+ //
+ global $amp_conf_defaults;
+
+ // get user
+ if ($STANDALONE['use']) {
+
+ $mgrhost = $ASTERISKMGR_DBHOST;
+ $mgruser = $STANDALONE['asterisk_mgruser'];
+ $mgrpass = $STANDALONE['asterisk_mgrpass'];
+
+ $asteriskcdr_dbengine = $ASTERISKCDR_DBENGINE;
+ $asteriskcdr_dbfile = $ASTERISKCDR_DBFILE;
+ $asteriskcdr_dbuser = $STANDALONE['asteriskcdr_dbuser'];
+ $asteriskcdr_dbpass = $STANDALONE['asteriskcdr_dbpass'];
+ $asteriskcdr_dbhost = $ASTERISKCDR_DBHOST;
+ $asteriskcdr_dbname = $ASTERISKCDR_DBNAME;
+ }
+ else {
+
+ $include = 0;
+ $files = split(';',$AMP_FUNCTIONS_FILES);
+ foreach ($files as $file) {
+ if (is_file($file)) {
+ include_once($file);
+ $include = 1;
+ }
+ }
+
+ if ($include) {
+ $amp_conf = parse_amportal_conf($AMPORTAL_CONF_FILE);
+
+ $mgrhost = $ASTERISKMGR_DBHOST;
+ $mgruser = $amp_conf['AMPMGRUSER'];
+ $mgrpass = $amp_conf['AMPMGRPASS'];
+
+ $amp_dbengine = isset($amp_conf["AMPDBENGINE"]) ? $amp_conf["AMPDBENGINE"] : $LEGACY_AMP_DBENGINE;
+ $amp_dbfile = isset($amp_conf["AMPDBFILE"]) ? $amp_conf["AMPDBFILE"] : $LEGACY_AMP_DBFILE;
+ $amp_dbuser = $amp_conf["AMPDBUSER"];
+ $amp_dbpass = $amp_conf["AMPDBPASS"];
+ $amp_dbhost = isset($amp_conf["AMPDBHOST"]) ? $amp_conf["AMPDBHOST"] : $LEGACY_AMP_DBHOST;
+ $amp_dbname = isset($amp_conf["AMPDBNAME"]) ? $amp_conf["AMPDBNAME"] : $LEGACY_AMP_DBNAME;
+
+ $asteriskcdr_dbengine = $ASTERISKCDR_DBENGINE;
+ $asteriskcdr_dbfile = $ASTERISKCDR_DBFILE;
+ $asteriskcdr_dbuser = $amp_conf["AMPDBUSER"];
+ $asteriskcdr_dbpass = $amp_conf["AMPDBPASS"];
+ $asteriskcdr_dbhost = $ASTERISKCDR_DBHOST;
+ $asteriskcdr_dbhost = isset($amp_conf["AMPDBHOST"]) ? $amp_conf["AMPDBHOST"] : $ASTERISKCDR_DBHOST;
+ $asteriskcdr_dbname = $ASTERISKCDR_DBNAME;
+
+ unset($amp_conf);
+ }
+ }
+
+ // asterisk manager interface (berkeley database I think)
+ global $asterisk_manager_interface;
+ $asterisk_manager_interface = new AsteriskManagerInterface();
+
+ $success = $asterisk_manager_interface->Connect($mgrhost,$mgruser,$mgrpass);
+ if (!$success) {
+ $_SESSION['ari_error'] =
+ _("ARI does not appear to have access to the Asterisk Manager.") . " ($errno)<br>" .
+ _("Check the ARI 'main.conf.php' configuration file to set the Asterisk Manager Account.") . "<br>" .
+ _("Check /etc/asterisk/manager.conf for a proper Asterisk Manager Account") . "<br>" .
+ _("make sure [general] enabled = yes and a 'permit=' line for localhost or the webserver.");
+ return FALSE;
+ }
+
+ // pear interface databases
+ $db = new Database();
+
+ // AMP asterisk database
+ if (!$STANDALONE['use']) {
+ $_SESSION['dbh_asterisk'] = $db->logon($amp_dbengine,
+ $amp_dbfile,
+ $amp_dbuser,
+ $amp_dbpass,
+ $amp_dbhost,
+ $amp_dbname);
+ if (!isset($_SESSION['dbh_asterisk'])) {
+ $_SESSION['ari_error'] .= _("Cannot connect to the $amp_dbname database") . "<br>" .
+ _("Check AMP installation, asterisk, and ARI main.conf");
+ return FALSE;
+ }
+ }
+
+ // cdr database
+ if (in_array('callmonitor',array_keys($loaded_modules))) {
+ $_SESSION['dbh_cdr'] = $db->logon($asteriskcdr_dbengine,
+ $asteriskcdr_dbfile,
+ $asteriskcdr_dbuser,
+ $asteriskcdr_dbpass,
+ $asteriskcdr_dbhost,
+ $asteriskcdr_dbname);
+ if (!isset($_SESSION['dbh_cdr'])) {
+ $_SESSION['ari_error'] .= sprintf(_("Cannot connect to the $asteriskcdr_dbname database"),$asteriskcdr_dbname) . "<br>" .
+ _("Check AMP installation, asterisk, and ARI main.conf");
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ * Logout if needed for any databases
+ */
+function databaseLogoff() {
+
+ global $asterisk_manager_interface;
+
+ $asterisk_manager_interface->Disconnect();
+}
+
+/*
+ * Checks if user is set and sets
+ */
+function loginBlock() {
+
+ $login = new Login();
+
+ if (isset($_REQUEST['logout'])) {
+ $login->Unauth();
+ }
+
+ if (!isset($_SESSION['ari_user'])) {
+ $login->Auth();
+
+ }
+
+ if (!isset($_SESSION['ari_user'])) {
+
+ // login form
+ $ret .= $login->GetForm();
+
+ return $ret;
+ }
+}
+
+/*
+ * Main handler for website
+ */
+function handleBlock() {
+
+ global $ARI_NO_LOGIN;
+
+ global $loaded_modules;
+
+ // check errors here and in login block
+ $content .= checkErrorMessage();
+
+ // check logout
+ if ($_SESSION['ari_user'] && !$ARI_NO_LOGIN) {
+ $logout = 1;
+ }
+
+ // if nothing set goto user default page
+ if (!isset($_REQUEST['m'])) {
+ $_REQUEST['m'] = $_SESSION['ari_user']['default_page'];
+ }
+ // if not function specified then use display page function
+ if (!isset($_REQUEST['f'])) {
+ $_REQUEST['f'] = 'display';
+ }
+
+ $m = $_REQUEST['m']; // module
+ $f = $_REQUEST['f']; // function
+ $a = $_REQUEST['a']; // action
+
+ // set arguments
+ $args = array();
+ foreach($_REQUEST as $key => $value) {
+ $args[$key] = $value;
+ }
+
+ // set rank
+ $ranked_modules = array();
+ foreach ($loaded_modules as $module) {
+
+ $module_methods = get_class_methods($module); // note that PHP4 returns all lowercase
+ while (list($index, $value) = each($module_methods)) {
+ $module_methods[strtolower($index)] = strtolower($value);
+ }
+ reset($module_methods);
+
+ $rank = 99999;
+ $rank_function = "rank";
+ if (in_array(strtolower($rank_function), $module_methods)) {
+ $rank = $module->$rank_function();
+ }
+
+ $ranked_modules[$rank] = $module;
+ }
+ ksort($ranked_modules);
+
+ // process modules
+ foreach ($ranked_modules as $module) {
+
+ // process module
+ $name = get_class($module); // note PHP4 returns all lowercase
+ $module_methods = get_class_methods($module); // note PHP4 returns all lowercase
+ while (list($index, $value) = each($module_methods)) {
+ $module_methods[strtolower($index)] = strtolower($value);
+ }
+ reset($module_methods);
+
+ // init module
+ $module->init();
+
+ // add nav menu items
+ $nav_menu_function = "navMenu";
+ if (in_array(strtolower($nav_menu_function), $module_methods)) {
+ $nav_menu .= $module->$nav_menu_function($args);
+ }
+
+ if (strtolower($m)==strtolower($name)) {
+
+ // build sub menu
+ $subnav_menu_function = "navSubMenu";
+ if (in_array(strtolower($subnav_menu_function), $module_methods)) {
+ $subnav_menu .= $module->$subnav_menu_function($args);
+ }
+
+ // execute function (usually to build content)
+ if (in_array(strtolower($f), $module_methods)) {
+ $content .= $module->$f($args);
+ }
+ }
+ }
+
+ // add logout link
+ if ($logout != '') {
+ $nav_menu .= "<p><small><small><a href='" . $_SESSION['ARI_ROOT'] . "?logout=1'>" . _("Logout") . "</a></small></small></p>";
+ }
+
+ // error message if no content
+ if (!$content) {
+ $content .= _("Page Not Found.");
+ }
+
+ return array($nav_menu,$subnav_menu,$content);
+}
+
+/*
+ * Main handler for website
+ */
+function handler() {
+
+ global $ARI_VERSION;
+
+ // version
+ $ari_version = $ARI_VERSION;
+
+ // check error
+ $error = $_SESSION['ari_error'];
+
+ // load modules
+ loadModules();
+
+ // login to database
+ $success = databaseLogon();
+ if ($success) {
+
+ // check if login is needed
+ $content = loginBlock();
+ if (!isset($content)) {
+ list($nav_menu,$subnav_menu,$content) = handleBlock();
+ }
+ }
+ else {
+
+ $display = new Display();
+
+ $content .= $display->displayHeaderText("ARI");
+ $content .= $display->displayLine();
+ $content .= checkErrorMessage();
+ }
+
+ // log off any databases needed
+ databaseLogoff();
+
+ // check for ajax request and refresh or if not build the page
+ if (isset($_REQUEST['ajax_refresh']) ) {
+
+ echo "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
+ <response>
+ <nav_menu><![CDATA[" . $nav_menu . "]]></nav_menu>
+ <subnav_menu><![CDATA[" . $subnav_menu . "]]></subnav_menu>
+ <content><![CDATA[" . $content . "]]></content>
+ </response>";
+ }
+ else {
+
+ // build the page
+ include_once("./theme/page.tpl.php");
+ }
+}
+
+/**
+ * Includes and run functions
+ */
+
+// create asterisk manager interface singleton
+$asterisk_manager_interface = '';
+
+// array to keep track of loaded modules
+$loaded_modules = array();
+
+include_once("./includes/asi.php");
+include_once("./includes/database.php");
+include_once("./includes/display.php");
+include_once("./includes/ajax.php");
+
+include_once("./includes/freeside.class.php");
+
+?>
diff --git a/fs_selfservice/fri/includes/crypt.php b/fs_selfservice/fri/includes/crypt.php
new file mode 100644
index 000000000..301d8a840
--- /dev/null
+++ b/fs_selfservice/fri/includes/crypt.php
@@ -0,0 +1,81 @@
+<?php
+
+/*
+ * Allows encrypt and decrypt
+ */
+class Crypt {
+
+ /**
+ * Gets a random value for encryption
+ * - From php.net docs
+ *
+ * @param $iv_len
+ * length of random variable
+ */
+ function getRndIV($iv_len) {
+
+ $iv = '';
+ while ($iv_len-- > 0) {
+ $iv .= chr(mt_rand() & 0xff);
+ }
+ return $iv;
+ }
+
+ /**
+ * Encrypts string
+ * - From php.net docs
+ *
+ * @param $str
+ * string to encrypt
+ * @param $salt
+ * password to use for encryption
+ * @param $iv_len
+ * length of random number
+ */
+ function encrypt($str, $salt, $iv_len = 16) {
+
+ $str .= "\x13";
+ $n = strlen($str);
+ if ($n % 16) $str .= str_repeat("\0", 16 - ($n % 16));
+ $i = 0;
+ $enc_text = $this->getRndIV($iv_len);
+ $iv = substr($salt ^ $enc_text, 0, 512);
+ while ($i < $n) {
+ $block = substr($str, $i, 16) ^ pack('H*', md5($iv));
+ $enc_text .= $block;
+ $iv = substr($block . $iv, 0, 512) ^ $salt;
+ $i += 16;
+ }
+ return urlencode(base64_encode($enc_text));
+ }
+
+ /**
+ * Decrypts string
+ * - From php.net docs
+ *
+ * @param $enc
+ * encrypted string to decrypt
+ * @param $salt
+ * password to use for encryption
+ * @param $iv_len
+ * length of random number
+ */
+ function decrypt($enc, $salt, $iv_len = 16) {
+
+ $enc = urldecode(base64_decode($enc));
+ $n = strlen($enc);
+ $i = $iv_len;
+ $str = '';
+ $iv = substr($salt ^ substr($enc, 0, $iv_len), 0, 512);
+ while ($i < $n) {
+ $block = substr($enc, $i, 16);
+ $str .= $block ^ pack('H*', md5($iv));
+ $iv = substr($block . $iv, 0, 512) ^ $salt;
+ $i += 16;
+ }
+ return preg_replace('/\\x13\\x00*$/', '', $str);
+ }
+}
+
+
+?>
diff --git a/fs_selfservice/fri/includes/database.php b/fs_selfservice/fri/includes/database.php
new file mode 100644
index 000000000..ff3d199c0
--- /dev/null
+++ b/fs_selfservice/fri/includes/database.php
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * @file
+ * Functions for the database
+ */
+
+/*
+ * Database Class
+ */
+class Database {
+
+ /*
+ * Constructor
+ */
+ function Database() {
+
+ // PEAR must be installed
+ require_once('DB.php');
+ }
+
+ /*
+ * Logs into database and returns database handle
+ *
+
+ * @param $engine
+ * database engine
+ * @param $dbfile
+ * database file
+ * @param $username
+ * username for database
+ * @param $password
+ * password for database
+ * @param $host
+ * database host
+ * @param $name
+ * database name
+ * @return $dbh
+ * variable to hold the returned database handle
+ */
+ function logon($engine,$dbfile,$username,$password,$host,$name) {
+
+ // connect string
+ if ($dbfile) {
+ // datasource mostly to support sqlite: dbengine://dbfile?mode=xxxx
+ $dsn = $engine . '://' . $dbfile . '?mode=0666';
+ }
+ else {
+ // datasource in in this style: dbengine://username:password@host/database
+ $datasource = $engine . '://' . $username . ':' . $password . '@' . $host . '/' . $name;
+ }
+
+ // options
+ $options = array(
+ 'debug' => 2,
+ 'portability' => DB_PORTABILITY_LOWERCASE|DB_PORTABILITY_RTRIM|DB_PORTABILITY_DELETE_COUNT|DB_PORTABILITY_NUMROWS|DB_PORTABILITY_ERRORS|DB_PORTABILITY_NULL_TO_EMPTY,
+ );
+
+ // attempt connection
+ $dbh = DB::connect($datasource,$options);
+
+ // if connection failed show error
+ if(DB::isError($dbh)) {
+ $_SESSION['ari_error'] .= $dbh->getMessage() . "<br><br>";
+ return;
+ }
+ return $dbh;
+ }
+}
+
+
+?> \ No newline at end of file
diff --git a/fs_selfservice/fri/includes/display.php b/fs_selfservice/fri/includes/display.php
new file mode 100644
index 000000000..41d8dc5f0
--- /dev/null
+++ b/fs_selfservice/fri/includes/display.php
@@ -0,0 +1,222 @@
+<?php
+
+/**
+ * @file
+ * Functions common to display
+ */
+
+/**
+ * Display
+ */
+class Display {
+
+ /**
+ * display constructor
+ */
+ function Display() {
+ }
+
+ /**
+ * display text header
+ *
+ * @param $text
+ * Header text to display
+ */
+ function displayHeaderText($text) {
+
+ $ret = "<h2>" . $text . "</h2>
+ <br>";
+
+ return $ret;
+ }
+
+ /**
+ * displays header line
+ */
+ function displayLine() {
+
+ $ret = "
+ <div id='line'>
+ <div class='spacer'></div>
+ <div class='spacer'></div>
+ </div>
+ <br>";
+
+ return $ret;
+ }
+}
+
+/**
+ * DisplaySearch
+ */
+class DisplaySearch extends Display {
+
+ /**
+ * Constructor
+ */
+ function DisplaySearch() {
+ }
+
+ /**
+ * displays search controls
+ *
+ * @param $align
+ * where to align the control
+ * @param $q
+ * search query
+ * @param $focus
+ * whether to focus control on this block
+ */
+ function displaySearchBlock($align,$m,$q,$url_opts,$focus) {
+
+ // align
+ if ($align=='center') {
+ $alignText = "class='bar_center'";
+ }
+ else {
+ $alignText = "class='bar_left'";
+ }
+
+ // url options
+ foreach ($url_opts as $key => $value) {
+ $option_text .= "<input type=hidden name=" . $key . " value=" . $value . ">";
+ }
+
+ // build
+ $ret .= "<div " . $alignText . ">
+ <form class='bar' action='" . $_SESSION['ARI_ROOT'] . "' method='GET' name='search'>
+ <input type=hidden name=m value=" . $m . ">
+ <input type=text name=q size=40 value='" . $q . "' maxlength=256>
+ " . $option_text . "
+ <input type=hidden name=start value=0>
+ <input type=submit name=btnS value='" . _("Search") . "'>
+ </form>
+ </div>";
+
+ if ($focus=="true") { // search block loaded twice usually so only allow javascript to be loaded on the top block
+ $ret .= "<script type='text/javascript'>
+ <!--
+ if (document.search) {
+ document.search.q.focus();
+ }
+ // -->
+ </script>";
+ }
+
+ return $ret;
+ }
+
+ /**
+ * displays info bar
+ *
+ * @param $controls
+ * controls for the page on the bar
+ * @param $q
+ * search query
+ * @param $start
+ * start number of current page
+ * @param $span
+ * number of items on current page
+ * @param $total
+ * total number of records found by current search
+ */
+ function displayInfoBarBlock($controls,$q,$start,$span,$total) {
+
+ if ($total<$span) {
+ $span = $total;
+ }
+ $start_count = ($total>0)?$start+1:$start;
+ $span_count = ($start+$span>$total)?$total:$start+$span;
+
+ if ($controls) {
+ $left_text = $controls;
+ }
+ elseif ($q != NULL) {
+ $left_text = "<small><small>" . _("Searched for") . " <u>" . $q . "</u></small></small>";
+ }
+
+ if ($span<$total) {
+ $right_text = "<small><small>" . sprintf(_("Results %d - %d of %d"),$start_count,$span_count,$total) . "</small></small>";
+ } else {
+ $right_text = "<small><small>" . sprintf(_("Results %d"),$total) . "</small></small>";
+ }
+
+ $ret .= "
+ <table id='navbar' width='100%'>
+ <tr>
+ <td>
+ " . $left_text . "
+ </td>
+ <td align='right'>
+ " . $right_text ."
+ </td>
+ </tr>
+ </table>";
+
+ return $ret;
+ }
+
+ /**
+ * displays navigation bar
+ *
+ * @param $q
+ * search query
+ * @param $start
+ * start number of current page
+ * @param $span
+ * number of items on current page
+ * @param $total
+ * total number of records found by current search
+ */
+ function displayNavigationBlock($m,$q,$url_opts,$start,$span,$total) {
+
+ $start = $start=='' ? 0 : $start ;
+ $span = $span=='' ? 15 : $span ;
+
+ $total_pages = ceil($total/$span);
+ $start_page = floor($start/$span);
+
+ // if more than ten pages start at this page minus ten otherwise start at zero
+ $begin = ($start_page>10)?($start_page-10):0;
+ // if more than ten pages then stop at this page plus ten otherwise stop at last page
+ $end = ($start_page>8)?($start_page+10):10;
+
+ // url
+ $unicode_q = urlencode($q); // encode search string
+
+ foreach ($url_opts as $key => $value) {
+ $option_text .= "&" . $key . "=" . $value;
+ }
+
+ $url = $_SESSION['ARI_ROOT'] . "?m=" . $m . "&q=" . $unicode_q . $option_text;
+
+ // build
+ if ($start_page!=0) {
+ $start_page_text = "<a href='" . $url . "&start=0'><small>" . _("First") . "</a>&nbsp;</small>
+ <a href=" . $url . "&start=" . ($start-$span) . "><small><</a>&nbsp;</small>";
+ }
+
+ for($next_page=$begin;($next_page<$total_pages)&&($next_page<$end);$next_page++) {
+ if ($next_page == $start_page) {
+ $middle_page_text .= "<small>" . ($next_page+1) . "&nbsp;</small>";
+ } else {
+ $middle_page_text .= "<a href='" . $url . "&start=" . ($next_page*$span) . "'><small>" . ($next_page+1) . "</a>&nbsp;</small>";
+ }
+ }
+ if ( ($start_page != $total_pages-1) && ($total != 0) ) {
+ $end_page_text = "<a href='" . $url . "&start=" . ($start+$span) . "'><small>></a>&nbsp;</small>
+ <a href='" . $url . "&start=" . ($total_pages-1)*$span . "'><small>" . _("Last") . "</a>&nbsp;</small>";
+ }
+
+ $ret .= "<div class='bar_center'>
+ " . $start_page_text . "
+ " . $middle_page_text . "
+ " . $end_page_text . "
+ </div>";
+
+ return $ret;
+ }
+}
+
+
+?> \ No newline at end of file
diff --git a/fs_selfservice/fri/includes/freeside.class.php b/fs_selfservice/fri/includes/freeside.class.php
new file mode 100644
index 000000000..a4413984e
--- /dev/null
+++ b/fs_selfservice/fri/includes/freeside.class.php
@@ -0,0 +1,38 @@
+<?php
+class FreesideSelfService {
+
+ //Change this to match the location of your selfservice xmlrpc.cgi or daemon
+ //var $URL = 'https://www.example.com/selfservice/xmlrpc.cgi';
+ var $URL = 'http://localhost/selfservice/xmlrpc.cgi';
+
+ function FreesideSelfService() {
+ $this;
+ }
+
+ public function __call($name, $arguments) {
+
+ error_log("[FreesideSelfService] $name called, sending to ". $this->URL);
+
+ $request = xmlrpc_encode_request("FS.SelfService.XMLRPC.$name", $arguments);
+ $context = stream_context_create( array( 'http' => array(
+ 'method' => "POST",
+ 'header' => "Content-Type: text/xml",
+ 'content' => $request
+ )));
+ $file = file_get_contents($this->URL, false, $context);
+ if (!$file) {
+ trigger_error("[FreesideSelfService] XML-RPC communication error: file_get_contents did not return");
+ } else {
+ $response = xmlrpc_decode($file);
+ if (xmlrpc_is_fault($response)) {
+ trigger_error("[FreesideSelfService] XML-RPC communication error: $response[faultString] ($response[faultCode])");
+ } else {
+ //error_log("[FreesideSelfService] $response");
+ return $response;
+ }
+ }
+ }
+
+}
+
+?>
diff --git a/fs_selfservice/fri/includes/lang.php b/fs_selfservice/fri/includes/lang.php
new file mode 100644
index 000000000..b27b8e337
--- /dev/null
+++ b/fs_selfservice/fri/includes/lang.php
@@ -0,0 +1,112 @@
+<?php
+
+/**
+ * @file
+ * i18n language functions
+ */
+
+/**
+ * Class for login
+ */
+class Language {
+
+ var $error;
+
+ /**
+ * Sets i18n locale language
+ *
+ * sets the language for i18n php gettext module
+ * (gettext has to be enabled in the php.ini)
+ *
+ */
+ function set() {
+
+ if (extension_loaded('gettext')) {
+
+ // try and find the default locale
+ $default_lang = preg_replace('/-/','_',$_SERVER['HTTP_ACCEPT_LANGUAGE']);
+
+ $locale = 'en_US';
+ $locale_dir = "./locale";
+ $directories = getdirectories($locale_dir,"");
+ foreach($directories as $directory) {
+ $buf = substr($directory,strlen($locale_dir)+1,strlen($directory) - strlen($locale_dir));
+ if (preg_match("/" . $buf . "/i",$default_lang)) {
+ $locale = $buf;
+ break;
+ }
+ }
+
+ // set locale
+ $language = isset($_COOKIE['ari_lang']) ? $_COOKIE['ari_lang'] : $locale;
+ putenv("LANG=$language");
+ putenv("LANGUAGE=$language");
+ setlocale(LC_MESSAGES,$language);
+ bindtextdomain('ari','./locale');
+ bind_textdomain_codeset('ari', 'UTF-8');
+ textdomain('ari');
+
+ } else {
+ function _($str) {
+ return $str;
+ }
+ }
+ }
+
+ /**
+ * Sets the i18n language in a cookie
+ *
+ * @param $lang_code
+ * length of random number
+ */
+ function setCookie($lang_code) {
+
+ if (extension_loaded('gettext')) {
+ setcookie("ari_lang", $lang_code, time()+365*24*60*60);
+ }
+ }
+
+ /**
+ * Sets the i18n language in a cookie
+ *
+ * @param $lang_code
+ * length of random number
+ */
+ function getForm() {
+
+ // lang setting options
+ if (extension_loaded('gettext')) {
+
+ $langOptions = "
+ <script>
+ function setCookie(name,value) {
+ var t = new Date();
+ var e = new Date();
+ e.setTime(t.getTime() + 365*24*60*60);
+ document.cookie = name+\"=\"+escape(value) + \";expires=\"+e.toGMTString();
+ }
+ </script>
+ <form class='lang' name='lang' action=" . $_SESSION['ARI_ROOT'] . " method='POST'>
+ <select class='lang_code' name='lang_code' onChange=\"setCookie('ari_lang',document.lang.lang_code.value); window.location.reload();\">
+ <option value='en_US' " . ($_COOKIE['ari_lang']=='en_US' ? 'selected' : '') . ">English</option>
+ <option value='es_ES' " . ($_COOKIE['ari_lang']=='es_ES' ? 'selected' : '') . ">Espa&ntilde;ol</option>
+ <option value='fr_FR' " . ($_COOKIE['ari_lang']=='fr_FR' ? 'selected' : '') . ">French</option>
+ <option value='de_DE' " . ($_COOKIE['ari_lang']=='de_DE' ? 'selected' : '') . ">German</option>
+ <option value='el_GR' " . ($_COOKIE['ari_lang']=='el_GR' ? 'selected' : '') . ">Greek</option>
+ <option value='he_IL' " . ($_COOKIE['ari_lang']=='he_IL' ? 'selected' : '') . ">Hebrew</option>
+ <option value='hu_HU' " . ($_COOKIE['ari_lang']=='hu_HU' ? 'selected' : '') . ">Hungarian</option>
+ <option value='it_IT' " . ($_COOKIE['ari_lang']=='it_IT' ? 'selected' : '') . ">Italian</option>
+ <option value='pt_BR' " . ($_COOKIE['ari_lang']=='pt_BR' ? 'selected' : '') . ">Portuguese</option>
+ <option value='sv_SE' " . ($_COOKIE['ari_lang']=='sv_SE' ? 'selected' : '') . ">Swedish</option>
+ </select>
+ </form>";
+ }
+
+ return $langOptions;
+ }
+
+
+}
+
+
+?> \ No newline at end of file
diff --git a/fs_selfservice/fri/includes/login.php b/fs_selfservice/fri/includes/login.php
new file mode 100644
index 000000000..41bb7a64d
--- /dev/null
+++ b/fs_selfservice/fri/includes/login.php
@@ -0,0 +1,515 @@
+<?php
+
+/**
+ * @file
+ * login functions
+ */
+
+/**
+ * Class for login
+ */
+class Login {
+
+ var $error;
+
+ /**
+ * Authenticate user and register user information into a session
+ */
+ function Auth() {
+
+ global $ARI_ADMIN_USERNAME;
+ global $ARI_ADMIN_PASSWORD;
+ global $ARI_ADMIN_EXTENSIONS;
+ global $ARI_CRYPT_PASSWORD;
+ global $ASTERISK_VOICEMAIL_CONF;
+ global $ASTERISK_VOICEMAIL_CONTEXT;
+ global $ASTERISK_VOICEMAIL_PATH;
+ global $ASTERISK_PROTOCOLS;
+ global $CALLMONITOR_ADMIN_EXTENSIONS;
+ global $ARI_NO_LOGIN;
+ global $ARI_DEFAULT_ADMIN_PAGE;
+ global $ARI_DEFAULT_USER_PAGE;
+
+ $crypt = new Crypt();
+
+ // init variables
+ $extension = '';
+ $displayname = '';
+ $vm_password = '';
+ $category = '';
+ $context = '';
+ $voicemail_enabled = '';
+ $voicemail_email_address = '';
+ $voicemail_pager_address = '';
+ $voicemail_email_enable = '';
+ $admin = '';
+ $admin_callmonitor = '';
+ $default_page = '';
+
+ $username = '';
+ $password = '';
+
+ // get the ari authentication cookie
+ $data = '';
+ $chksum = '';
+ if (isset($_COOKIE['ari_auth'])) {
+ $buf = unserialize($_COOKIE['ari_auth']);
+ list($data,$chksum) = $buf;
+ }
+ if (md5($data) == $chksum) {
+ $data = unserialize($crypt->decrypt($data,$ARI_CRYPT_PASSWORD));
+ $username = $data['username'];
+ $password = $data['password'];
+ }
+
+ if (isset($_POST['username']) &&
+ isset($_POST['password'])) {
+ $username = $_POST['username'];
+ $password = $_POST['password'];
+ }
+
+ // init email options array
+ $voicemail_email = array();
+
+ // when login, make a new session
+ if ($username && !$ARI_NO_LOGIN) {
+
+ $auth = false;
+
+ // check admin
+ if (!$auth) {
+ if ($username==$ARI_ADMIN_USERNAME &&
+ $password==$ARI_ADMIN_PASSWORD) {
+
+ // authenticated
+ $auth = true;
+
+ $extension = 'admin';
+ $name = 'Administrator';
+ $admin = 1;
+ $admin_callmonitor = 1;
+
+ $default_page = $ARI_DEFAULT_ADMIN_PAGE;
+ }
+ }
+
+ // check voicemail login
+ if (!$auth) {
+
+ if (is_readable($ASTERISK_VOICEMAIL_CONF)) {
+
+ $lines = file($ASTERISK_VOICEMAIL_CONF);
+
+ // look for include files and tack their lines to end of array
+ foreach ($lines as $key => $line) {
+
+ if (preg_match("/include/i",$line)) {
+
+ $include_filename = '';
+ $parts = split(' ',$line);
+ if (isset($parts[1])) {
+ $include_filename = trim($parts[1]);
+ }
+
+ if ($include_filename) {
+ $path_parts = pathinfo($ASTERISK_VOICEMAIL_CONF);
+ $include_path = fixPathSlash($path_parts['dirname']) . $include_filename;
+ foreach (glob($include_path) as $include_file) {
+ $include_lines = file($include_file);
+ $lines = array_merge($include_lines,$lines);
+ }
+ }
+ }
+ }
+
+ // process
+ foreach ($lines as $key => $line) {
+
+ // check for current context and process
+ if (preg_match("/\[.*\]/i",$line)) {
+ $currentContext = trim(preg_replace('/\[|\]/', '', $line));
+ }
+ if ($ASTERISK_VOICEMAIL_CONTEXT &&
+ $currentContext!=$ASTERISK_VOICEMAIL_CONTEXT) {
+ continue;
+ }
+
+ // check for user and process
+ unset($value);
+ $parts = split('=>',$line);
+ if (isset($parts[0])) {
+ $var = $parts[0];
+ }
+ if (isset($parts[1])) {
+ $value = $parts[1];
+ }
+ $var = trim($var);
+ if ($var==$username && $value) {
+ $buf = split(',',$value);
+ if ($buf[0]==$password) {
+
+ // authenticated
+ $auth = true;
+ $extension = $username;
+ $displayname = $buf[1];
+ $vm_password = $buf[0];
+ $default_page = $ARI_DEFAULT_USER_PAGE;
+ $context = $currentContext;
+ $voicemail_enabled = 1;
+ $voicemail_email_address = $buf[2];
+ $voicemail_pager_address = $buf[3];
+
+ if ($voicemail_email_address || $voicemail_pager_address) {
+ $voicemail_email_enable = 1;
+ }
+
+ $options = split('\|',$buf[4]);
+ foreach ($options as $option) {
+ $opt_buf = split('=',$option);
+ $voicemail_email[$opt_buf[0]] = trim($opt_buf[1]);
+ }
+
+ $admin = 0;
+ if ($ARI_ADMIN_EXTENSIONS) {
+ $extensions = split(',',$ARI_ADMIN_EXTENSIONS);
+ foreach ($extensions as $key => $value) {
+ if ($extension==$value) {
+ $admin = 1;
+ break 2;
+ }
+ }
+ }
+
+ $admin_callmonitor = 0;
+ if ($CALLMONITOR_ADMIN_EXTENSIONS) {
+ $extensions = split(',',$CALLMONITOR_ADMIN_EXTENSIONS);
+ foreach ($extensions as $key => $value) {
+ if ($value=='all' || $extension==$value) {
+ $admin_callmonitor = 1;
+ break 2;
+ }
+ }
+ }
+ }
+ else {
+ $_SESSION['ari_error'] = "Incorrect Password";
+ return;
+ }
+ }
+ }
+ }
+ else {
+ $_SESSION['ari_error'] = "File not readable: " . $ASTERISK_VOICEMAIL_CONF;
+ return;
+ }
+ }
+
+ // check sip login
+ if (!$auth) {
+
+ foreach($ASTERISK_PROTOCOLS as $protocol => $value) {
+
+ $config_files = split(';',$value['config_files']);
+ foreach ($config_files as $config_file) {
+
+ if (is_readable($config_file)) {
+
+ $lines = file($config_file);
+ foreach ($lines as $key => $line) {
+
+ unset($value);
+ $parts = split('=',$line);
+ if (isset($parts[0])) {
+ $var = trim($parts[0]);
+ }
+ if (isset($parts[1])) {
+ $value = trim($parts[1]);
+ }
+ if ($var=="username") {
+ $protocol_username = $value;
+ }
+ if ($var=="secret") {
+
+ $protocol_password = $value;
+ if ($protocol_username==$username &&
+ $protocol_password==$password) {
+
+ // authenticated
+ $auth = true;
+ $extension = $username ;
+ $displayname = $username;
+ $default_page = $ARI_DEFAULT_ADMIN_PAGE;
+
+ $admin = 0;
+ if ($ARI_ADMIN_EXTENSIONS) {
+ $extensions = split(',',$ARI_ADMIN_EXTENSIONS);
+ foreach ($extensions as $key => $value) {
+ if ($extension==$value) {
+ $admin = 1;
+ break 2;
+ }
+ }
+ }
+
+ $admin_callmonitor = 0;
+ if ($CALLMONITOR_ADMIN_EXTENSIONS) {
+ $extensions = split(',',$CALLMONITOR_ADMIN_EXTENSIONS);
+ foreach ($extensions as $key => $value) {
+ if ($value=='all' || $extension==$value) {
+ $admin_callmonitor = 1;
+ break 2;
+ }
+ }
+ }
+ }
+ else if ($protocol_username==$username &&
+ $protocol_password!=$password) {
+ $_SESSION['ari_error'] = _("Incorrect Password");
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // let user know bad login
+ if (!$auth) {
+ $_SESSION['ari_error'] = _("Incorrect Username or Password");
+ }
+
+ // freeside login
+ $freeside = new FreesideSelfService();
+ $domain = 'svc_phone';
+ $response = $freeside->login( array(
+ 'username' => strtolower($username),
+ 'domain' => $domain,
+ 'password' => strtolower($password),
+ ) );
+ error_log("[login] received response from freeside: $response");
+ $error = $response['error'];
+
+ if ( ! $error && $response['session_id'] ) {
+
+ // sucessful freeside login
+ error_log("[login] logged into freeside with session_id=$session_id");
+
+ // store session id in your session store, to be used for other calls
+ //$fs_session_id = $response['session_id'];
+ $_SESSION['freeside_session_id'] = $response['session_id'];
+
+ $customer_info = $freeside->customer_info( array(
+ 'session_id' => $_SESSION['freeside_session_id'] ,
+ ) );
+ //XXX error checking here too
+ $displayname = $customer_info['name'];
+
+ } else {
+
+ // unsucessful login
+ error_log("[login] error logging into freeside: $error");
+ $auth = false;
+ $extension = '';
+
+ // display error message to user
+ $_SESSION['ari_error'] = _("Incorrect Username or Password");
+
+ }
+
+ // if authenticated and user wants to be remembered, set cookie
+ $remember = '';
+ if (isset($_POST['remember'])) {
+ $remember = $_POST['remember'];
+ }
+ if ($auth && $remember) {
+
+ $data = array('username' => $username, 'password' => $password);
+ $data = $crypt->encrypt(serialize($data),$ARI_CRYPT_PASSWORD);
+
+ $chksum = md5($data);
+
+ $buf = serialize(array($data,$chksum));
+ setcookie('ari_auth',$buf,time()+365*24*60*60,'/');
+ }
+
+ // set category
+ if (!$category) {
+ $category = "general";
+ }
+
+ // set context
+ if (!$context) {
+ $context = "default";
+ }
+
+ // no login user
+ if ($ARI_NO_LOGIN) {
+ $extension = 'admin';
+ $name = 'Administrator';
+ $admin_callmonitor = 1;
+ $default_page = $ARI_DEFAULT_ADMIN_PAGE;
+ }
+
+ // get outboundCID if it exists
+ $outboundCID = $this->getOutboundCID($extension);
+
+ // set
+ if ($extension) {
+ $_SESSION['ari_user']['extension'] = $extension;
+ $_SESSION['ari_user']['outboundCID'] = $outboundCID;
+ $_SESSION['ari_user']['displayname'] = $displayname;
+ $_SESSION['ari_user']['voicemail_password'] = $vm_password;
+ $_SESSION['ari_user']['category'] = $category;
+ $_SESSION['ari_user']['context'] = $context;
+ $_SESSION['ari_user']['voicemail_enabled'] = $voicemail_enabled;
+ $_SESSION['ari_user']['voicemail_email_address'] = $voicemail_email_address;
+ $_SESSION['ari_user']['voicemail_pager_address'] = $voicemail_pager_address;
+ $_SESSION['ari_user']['voicemail_email_enable'] = $voicemail_email_enable;
+ foreach ($voicemail_email as $key => $value) {
+ $_SESSION['ari_user']['voicemail_email'][$key] = $value;
+ }
+ $_SESSION['ari_user']['admin'] = $admin;
+ $_SESSION['ari_user']['admin_callmonitor'] = $admin_callmonitor;
+ $_SESSION['ari_user']['default_page'] = $default_page;
+
+ // force the session data saved
+ session_write_close();
+ }
+ }
+ }
+
+ /*
+ * Gets user outbound caller id
+ *
+ * @param $exten
+ * Extension to get information about
+ * @return $ret
+ * outbound caller id
+ */
+ function getOutboundCID($extension) {
+
+ global $asterisk_manager_interface;
+
+ $ret = '';
+ $response = $asterisk_manager_interface->Command2("Action: Command\r\nCommand: database get AMPUSER $extension/outboundcid\r\n\r\n");
+ if ($response) {
+
+ $posLeft = strpos( $response, "<")+strlen("<");
+ $posRight = strpos( $response, ">", $posLeft);
+ $ret = substr( $response,$posLeft,$posRight-$posLeft);
+ }
+ return $ret;
+ }
+
+ /**
+ * logout
+ */
+ function Unauth() {
+ unset($_COOKIE["ari_auth"]);
+ setcookie('ari_auth',"",time(),'/');
+ unset($_SESSION['ari_user']);
+ }
+
+ /**
+ * Provide a login form for user
+ *
+ * @param $request
+ * Variable to hold data entered into form
+ */
+ function GetForm() {
+
+ global $ARI_NO_LOGIN;
+
+ if ($ARI_NO_LOGIN) {
+ $ret = '';
+ return;
+ }
+
+ if (isset($_GET['login'])) {
+ $login = $_GET['login'];
+ }
+
+ // if user name and password were given, but there was a problem report the error
+ if ($this->error!='') {
+ $ret = $this->error;
+ }
+
+ $language = new Language();
+ $display = new Display(NULL);
+
+ // new header
+ $ret .= $display->DisplayHeaderText(_("Login"));
+ $ret .= $display->DisplayLine();
+ $ret .= checkErrorMessage();
+
+ $ret .= "
+ <table id='login'>
+ <form id='login' name='login' action=" . $_SESSION['ARI_ROOT'] . " method='POST'>
+ <tr>
+ <td class='right'>
+ <small><small>" . _("Login") . ":&nbsp;&nbsp;</small></small>
+ </td>
+ <td>
+ <input type='text' name='username' value='" . $login . "' maxlength=20 tabindex=1>
+ </td>
+ </tr>
+ <tr>
+ <td class='right'>
+ <small><small>" . _("Password") . ":&nbsp;&nbsp;</small></small>
+ </td>
+ <td colspan=1>
+ <input type='password' name='password' maxlength=20 tabindex=2>
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>
+ <input type='submit' name='btnSubmit' value='" . _("Submit") . "' tabindex=3></small></small></p>
+ </td>
+ </tr>
+ <tr>
+ <td class='right'>
+ <input type='checkbox' name='remember'>
+ </td>
+ <td class='left'>
+ <p class='small'>" . _("Remember Password") . "</p>
+ </td>
+ </tr>
+ </form>
+ <tr>
+ <td></td>
+ <td>
+ " . $language->getForm() . "
+ </td>
+ </tr>
+ <tr><td>&nbsp;</td></tr>
+ </table>
+ <table id='login_text'>
+ <tr>
+ <td>" .
+ _("Use your <b>Voicemail Mailbox and Password</b>") . "<br>" .
+ _("This is the same password used for the phone") . "<br>" .
+ "<br>" .
+ _("For password maintenance or assistance, contact your Phone System Administrator.") . "<br>" . "
+ </td>
+ </tr>
+ </table>";
+
+ $ret .= "
+ <script type='text/javascript'>
+ <!--
+ if (document.login) {
+ document.login.username.focus();
+ }
+ // -->
+ </script>";
+
+ return $ret;
+ }
+
+
+}
+
+
+?>
diff --git a/fs_selfservice/fri/includes/main.conf.php b/fs_selfservice/fri/includes/main.conf.php
new file mode 100644
index 000000000..cedf60cc6
--- /dev/null
+++ b/fs_selfservice/fri/includes/main.conf.php
@@ -0,0 +1,331 @@
+<?php
+
+/**
+ * @file
+ * site-specific configuration file.
+ */
+
+###############################
+# AMP or standalone settings
+###############################
+#
+# From AMP. Used for logon to database.
+#
+$AMP_FUNCTIONS_FILES = "../admin/functions.php;../admin/functions.inc.php";
+$AMPORTAL_CONF_FILE = "/etc/amportal.conf";
+
+#
+# Host for Asterisk Manager Interface
+#
+$ASTERISKMGR_DBHOST = "localhost";
+
+#
+# Database options for older legacy AMP installations (pre-FreePBX)
+# - $LEGACY_AMP_DBFILE only needs to be set if using a database like sqlite
+#
+$LEGACY_AMP_DBHOST = "localhost";
+$LEGACY_AMP_DBENGINE = "mysql";
+$LEGACY_AMP_DBFILE = "";
+$LEGACY_AMP_DBNAME = "asterisk";
+
+#
+# Database cdr settings
+# - Only need to update these settings if standalone or an older AMP version (pre-FreePBX) is used
+# - $ASTERISKCDR_DBFILE only needs to be set if using a database like sqlite
+# Options: supported database types (others are supported, but not listed)
+# 'mysql' - MySQL
+# 'pgsql' - PostgreSQL
+# 'oci8' - Oracle
+# 'odbc' - ODBC
+#
+$ASTERISKCDR_DBHOST = "localhost";
+$ASTERISKCDR_DBENGINE = "mysql";
+$ASTERISKCDR_DBFILE = "";
+$ASTERISKCDR_DBNAME = "asteriskcdrdb";
+$ASTERISKCDR_DBTABLE = "cdr";
+
+#
+# Standalone, for use without AMP
+# set use = true;
+# set asterisk_mgruser to Asterisk Call Manager username
+# set asterisk_mgrpass to Asterisk Call Manager password
+#
+$STANDALONE['use'] = false;
+$STANDALONE['asterisk_mgruser'] = "";
+$STANDALONE['asterisk_mgrpass'] = "";
+$STANDALONE['asteriskcdr_dbuser'] = "";
+$STANDALONE['asteriskcdr_dbpass'] = "";
+
+###############################
+# authentication settings
+###############################
+#
+# For using the Call Monitor only
+# option: 0 - use Authentication, Voicemail, and Call Monitor
+# 1 - use only the Call Monitor
+#
+$ARI_NO_LOGIN = 0;
+
+#
+# Admin only account
+#
+$ARI_ADMIN_USERNAME = "admin";
+$ARI_ADMIN_PASSWORD ="ari_password";
+#
+# Admin extensions
+# option: Comma delimited list of extensions
+#
+$ARI_ADMIN_EXTENSIONS = "";
+
+#
+# Authentication password to unlock cookie password
+# This must be all continuous and only letters and numbers
+#
+$ARI_CRYPT_PASSWORD = "z1Mc6KRxA7Nw90dGjY5qLXhtrPgJOfeCaUmHvQT3yW8nDsI2VkEpiS4blFoBuZ";
+
+###############################
+# modules settings
+###############################
+#
+# modules with admin only status (they will not be displayed for regular users)
+# option: Comma delimited list of module names (ie voicemail,callmonitor,help,settings)
+#
+$ARI_ADMIN_MODULES = "";
+
+#
+# disable modules (you can also just delete them from /recordings/modules without problems)
+# option: Comma delimited list of module names (ie voicemail,callmonitor,help,settings)
+#
+$ARI_DISABLED_MODULES = "";
+
+#
+# sets the default admin page
+# option: Comma delimited list of module names (ie voicemail,callmonitor,help,settings)
+#
+$ARI_DEFAULT_ADMIN_PAGE = "callmonitor";
+
+#
+# sets the default user page
+# option: Comma delimited list of module names (ie voicemail,callmonitor,help,settings)
+#
+#$ARI_DEFAULT_USER_PAGE = "voicemail";
+$ARI_DEFAULT_USER_PAGE = "dashboard";
+
+#
+# enables ajax page refresh
+# option: 0 - disable ajax page refresh
+# 1 - enable ajax page refresh
+#
+$AJAX_PAGE_REFRESH_ENABLE = 1;
+
+#
+# sets the default user page
+# option: refresh time in 'minutes:seconds' (0 to inifinity) : (0 to 59)
+#
+$AJAX_PAGE_REFRESH_TIME ="01:00";
+###############################
+# voicemail settings
+###############################
+#
+# voicemail config.
+#
+$ASTERISK_VOICEMAIL_CONF = "/etc/asterisk/voicemail.conf";
+
+#
+# To set to a specific context.
+# If using default or more than one context then leave blank
+#
+$ASTERISK_VOICEMAIL_CONTEXT = "";
+
+#
+# Location of asterisk voicemail recordings on server
+# Use semi-colon for multiple paths
+#
+$ASTERISK_VOICEMAIL_PATH = "/var/spool/asterisk/voicemail";
+
+#
+# valid mailbox folders
+#
+$ASTERISK_VOICEMAIL_FOLDERS = array();
+$ASTERISK_VOICEMAIL_FOLDERS[0]['folder'] = "INBOX";
+$ASTERISK_VOICEMAIL_FOLDERS[0]['name'] = _("INBOX");
+$ASTERISK_VOICEMAIL_FOLDERS[1]['folder'] = "Family";
+$ASTERISK_VOICEMAIL_FOLDERS[1]['name'] = _("Family");
+$ASTERISK_VOICEMAIL_FOLDERS[2]['folder'] = "Friends";
+$ASTERISK_VOICEMAIL_FOLDERS[2]['name'] = _("Friends");
+$ASTERISK_VOICEMAIL_FOLDERS[3]['folder'] = "Old";
+$ASTERISK_VOICEMAIL_FOLDERS[3]['name'] = _("Old");
+$ASTERISK_VOICEMAIL_FOLDERS[4]['folder'] = "Work";
+$ASTERISK_VOICEMAIL_FOLDERS[4]['name'] = _("Work");
+
+###############################
+# call monitor settings
+###############################
+#
+# Location of asterisk call monitor recordings on server
+#
+$ASTERISK_CALLMONITOR_PATH = "/var/spool/asterisk/monitor";
+
+#
+# Extensions with access to all call monitor recordings
+# option: Comma delimited list of extensions or "all"
+#
+$CALLMONITOR_ADMIN_EXTENSIONS ="";
+#
+# Allow call monitor users to delete monitored calls
+# option: 0 - do not show controls
+# 1 - show controls
+#
+$CALLMONITOR_ALLOW_DELETE = 1;
+
+#
+# Allow for aggressive matching of recording files to database records
+# will match recordings that are marked several seconds off
+# option: 0 - do not aggressively match
+# 1 - aggressively match
+#
+$CALLMONITOR_AGGRESSIVE_MATCHING = 1;
+
+#
+# Limits log/recording file matching to exact matching
+# will not try to look through all the recordings and make a best match
+# even if there is not uniqueid
+# requires that the MYSQL_UNIQUEID flag be compiled in asterisk-addons
+# (in the asterisk-addon Makefile add the following "CFLAGS+=-DMYSQL_LOGUNIQUEID")
+#
+# * use if there are or will be more than 2500 recording files
+#
+# option: 0 - do not exact match
+# 1 - only exact match
+#
+$CALLMONITOR_ONLY_EXACT_MATCHING = 0;
+
+###############################
+# conference page settings
+###############################
+#
+# Meetme extension prefix
+# for this module to function, the user has to have
+# a meetme conference room {prefix}{extension}
+#
+$CONFERENCE_WEBMEETME_PREFIX = "";
+
+#
+# url to web meetme conference room
+# example: "http://example.mycompany.com/webmeetme"
+#
+$CONFERENCE_WEBMEETME_URL = "";
+
+###############################
+# help page settings
+###############################
+#
+# help feature codes
+# list of handset options and their function
+#
+$ARI_HELP_FEATURE_CODES = array();
+//$ARI_HELP_FEATURE_CODES['*411'] = _("Directory");
+//$ARI_HELP_FEATURE_CODES['*43'] = _("Echo Test");
+//$ARI_HELP_FEATURE_CODES['*60'] = _("Time");
+//$ARI_HELP_FEATURE_CODES['*61'] = _("Weather");
+//$ARI_HELP_FEATURE_CODES['*62'] = _("Schedule wakeup call");
+//$ARI_HELP_FEATURE_CODES['*65'] = _("festival test (your extension is XXX)");
+//$ARI_HELP_FEATURE_CODES['*77'] = _("IVR Recording");
+//$ARI_HELP_FEATURE_CODES['*99'] = _("Playback IVR Recording");
+//$ARI_HELP_FEATURE_CODES['666'] = _("Test Fax");
+//$ARI_HELP_FEATURE_CODES['7777'] = _("Simulate incoming call");
+
+$ARI_HELP_FEATURE_CODES['*72'] = _("Call Forward All Activate");
+$ARI_HELP_FEATURE_CODES['*73'] = _("Call Forward All Deactivate");
+$ARI_HELP_FEATURE_CODES['*74'] = _("Call Forward All Prompting Deactivate");
+$ARI_HELP_FEATURE_CODES['*90'] = _("Call Forward Busy Activate");
+$ARI_HELP_FEATURE_CODES['*91'] = _("Call Forward Busy Deactivate");
+$ARI_HELP_FEATURE_CODES['*92'] = _("Call Forward Busy Prompting Deactivate");
+$ARI_HELP_FEATURE_CODES['*52'] = _("Call Forward No Answer/Unavailable Activate");
+$ARI_HELP_FEATURE_CODES['*53'] = _("Call Forward No Answer/Unavailable Deactivate");
+$ARI_HELP_FEATURE_CODES['*70'] = _("Call Waiting - Activate");
+$ARI_HELP_FEATURE_CODES['*71'] = _("Call Waiting - Deactivate");
+$ARI_HELP_FEATURE_CODES['*78'] = _("Do-Not-Disturb Activate");
+$ARI_HELP_FEATURE_CODES['*79'] = _("Do-Not-Disturb Deactivate");
+$ARI_HELP_FEATURE_CODES['*97'] = _("My Voicemail");
+$ARI_HELP_FEATURE_CODES['*98'] = _("Dial Voicemail");
+
+###############################
+# settings page settings
+###############################
+#
+# protocol config.
+# config_file options: semi-colon delimited list of extensions
+#
+$ASTERISK_PROTOCOLS = array();
+$ASTERISK_PROTOCOLS['iax']['table'] = "iax";
+$ASTERISK_PROTOCOLS['iax']['config_files'] = "/etc/asterisk/iax.conf;/etc/asterisk/iax_additional.conf";
+$ASTERISK_PROTOCOLS['sip']['table'] = "sip";
+$ASTERISK_PROTOCOLS['sip']['config_files'] = "/etc/asterisk/sip.conf;/etc/asterisk/sip_additional.conf";
+$ASTERISK_PROTOCOLS['zap']['table'] = "zap";
+$ASTERISK_PROTOCOLS['zap']['config_files'] = "/etc/asterisk/zapata.conf;/etc/asterisk/zapata_additional.conf";
+
+# Settings for Follow-Me Select Boxes in seconds
+#
+
+$SETTINGS_PRERING_LOW = 4;
+$SETTINGS_PRERING_HIGH = 30;
+$SETTINGS_LISTRING_LOW = 6;
+$SETTINGS_LISTRING_HIGH = 60;
+
+$SETTINGS_FOLLOW_ME_LIST_MAX = 5;
+$SETTINGS_ALLOW_VMX_SETTINGS = true;
+#
+# For setting
+# option: 0 - do not show controls
+# 1 - show controls
+#
+$SETTINGS_ALLOW_CALLFORWARD_SETTINGS = 1;
+$SETTINGS_ALLOW_VOICEMAIL_SETTINGS = 1;
+$SETTINGS_ALLOW_VOICEMAIL_PASSWORD_SET = 1;
+
+#
+# password length
+# setting: number of characters required for changing voicemail password
+#
+$SETTINGS_VOICEMAIL_PASSWORD_LENGTH = 3;
+
+#
+# password exact length
+# option: 0 - do not require exact length when setting the password
+# 1 - require exact length when setting the password
+#
+$SETTINGS_VOICEMAIL_PASSWORD_EXACT = 0;
+
+#
+# voicemail email option descriptions
+#
+$SETTINGS_VOICEMAIL_EMAIL_OPTION_DESCRIPTIONS = array();
+$SETTINGS_VOICEMAIL_EMAIL_OPTION_DESCRIPTIONS['attach'] = _("Email voicemail as attachment");
+$SETTINGS_VOICEMAIL_EMAIL_OPTION_DESCRIPTIONS['saycid'] = _("Say caller id in recording emailed");
+$SETTINGS_VOICEMAIL_EMAIL_OPTION_DESCRIPTIONS['envelope'] = _("Say envelop (date/time) in recording emailed");
+$SETTINGS_VOICEMAIL_EMAIL_OPTION_DESCRIPTIONS['delete'] = _("Delete voicemail when emailed");
+$SETTINGS_VOICEMAIL_EMAIL_OPTION_DESCRIPTIONS['nextaftercmd'] = _("Play next message after deleting current message");
+$SETTINGS_VOICEMAIL_EMAIL_OPTION_DESCRIPTIONS['review'] = _("Ask caller to review their voicemail before sending");
+$SETTINGS_VOICEMAIL_EMAIL_OPTION_DESCRIPTIONS['maxmessage'] = _("Maximum time in seconds a voicemail will record");
+
+#
+# Default
+# option: ".wav" - wav format
+# ".gsm" - gsm format
+#
+$ARI_VOICEMAIL_AUDIO_FORMAT_DEFAULT = ".wav";
+
+#
+# For setting
+# option: 0 - do not show controls
+# 1 - show controls
+#
+$SETTINGS_ALLOW_CALL_RECORDING_SET = 1;
+
+
+$SETTINGS_ALLOW_PHONE_SETTINGS = 1;
+
+
+
+?>
diff --git a/fs_selfservice/fri/index.php b/fs_selfservice/fri/index.php
new file mode 100644
index 000000000..0fe614992
--- /dev/null
+++ b/fs_selfservice/fri/index.php
@@ -0,0 +1,20 @@
+<?php
+
+/**
+ * @file
+ * main
+ */
+
+include_once("includes/bootstrap.php");
+ariPageHeader();
+include_once("includes/common.php");
+
+handler();
+
+ariPageFooter();
+
+
+?>
+
+
+
diff --git a/fs_selfservice/fri/locale/ari.po b/fs_selfservice/fri/locale/ari.po
new file mode 100644
index 000000000..4e3493e2f
--- /dev/null
+++ b/fs_selfservice/fri/locale/ari.po
@@ -0,0 +1,590 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-05-03 08:32-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../includes/asi.php:46
+msgid "Asterisk Call Manager not responding"
+msgstr ""
+
+#: ../includes/asi.php:54
+msgid "Asterisk authentication failed:"
+msgstr ""
+
+#: ../includes/asi.php:96 ../includes/asi.php:111
+msgid "Asterisk command not understood"
+msgstr ""
+
+#: ../includes/bootstrap.php:123
+#, php-format
+msgid "To many directories in %s Not all files processed"
+msgstr ""
+
+#: ../includes/bootstrap.php:226
+msgid "ARI requires a version of PHP 4.3 or later"
+msgstr ""
+
+#: ../includes/bootstrap.php:245
+msgid ""
+"PHP PEAR must be installed. Visit http://pear.php.net for help with "
+"installation."
+msgstr ""
+
+#: ../includes/common.php:173
+msgid "ARI does not appear to have access to the Asterisk Manager."
+msgstr ""
+
+#: ../includes/common.php:174
+msgid ""
+"Check the ARI 'main.conf.php' configuration file to set the Asterisk Manager "
+"Account."
+msgstr ""
+
+#: ../includes/common.php:175
+msgid "Check /etc/asterisk/manager.conf for a proper Asterisk Manager Account"
+msgstr ""
+
+#: ../includes/common.php:176
+msgid ""
+"make sure [general] enabled = yes and a 'permit=' line for localhost or the "
+"webserver."
+msgstr ""
+
+#: ../includes/common.php:193 ../includes/common.php:208
+msgid "Check AMP installation, asterisk, and ARI main.conf"
+msgstr ""
+
+#: ../includes/common.php:344
+msgid "Logout"
+msgstr ""
+
+#: ../includes/common.php:349
+msgid "Page Not Found."
+msgstr ""
+
+#: ../includes/display.php:92
+msgid "Search"
+msgstr ""
+
+#: ../includes/display.php:135
+msgid "Searched for"
+msgstr ""
+
+#: ../includes/display.php:139
+#, php-format
+msgid "Results %d - %d of %d"
+msgstr ""
+
+#: ../includes/display.php:141
+#, php-format
+msgid "Results %d"
+msgstr ""
+
+#: ../includes/display.php:195
+msgid "First"
+msgstr ""
+
+#: ../includes/display.php:208
+msgid "Last"
+msgstr ""
+
+#: ../includes/login.php:267
+msgid "Incorrect Password"
+msgstr ""
+
+#: ../includes/login.php:279
+msgid "Incorrect Username or Password"
+msgstr ""
+
+#: ../includes/login.php:402 ../includes/login.php:411
+msgid "Login"
+msgstr ""
+
+#: ../includes/login.php:419
+msgid "Password"
+msgstr ""
+
+#: ../includes/login.php:428
+msgid "Submit"
+msgstr ""
+
+#: ../includes/login.php:436
+msgid "Remember Password"
+msgstr ""
+
+#: ../includes/login.php:451
+msgid "Use your <b>Voicemail Mailbox and Password</b>"
+msgstr ""
+
+#: ../includes/login.php:452
+msgid "This is the same password used for the phone"
+msgstr ""
+
+#: ../includes/login.php:454
+msgid ""
+"For password maintenance or assistance, contact your Phone System "
+"Administrator."
+msgstr ""
+
+#: ../includes/main.conf.php:152
+msgid "INBOX"
+msgstr ""
+
+#: ../includes/main.conf.php:154
+msgid "Family"
+msgstr ""
+
+#: ../includes/main.conf.php:156
+msgid "Friends"
+msgstr ""
+
+#: ../includes/main.conf.php:158
+msgid "Old"
+msgstr ""
+
+#: ../includes/main.conf.php:160
+msgid "Work"
+msgstr ""
+
+#: ../includes/main.conf.php:229
+msgid "Directory"
+msgstr ""
+
+#: ../includes/main.conf.php:230
+msgid "Echo Test"
+msgstr ""
+
+#: ../includes/main.conf.php:231 ../modules/callmonitor.module:161
+#: ../modules/voicemail.module:324
+msgid "Time"
+msgstr ""
+
+#: ../includes/main.conf.php:232
+msgid "Weather"
+msgstr ""
+
+#: ../includes/main.conf.php:233
+msgid "Schedule wakeup call"
+msgstr ""
+
+#: ../includes/main.conf.php:234
+msgid "festival test (your extension is XXX)"
+msgstr ""
+
+#: ../includes/main.conf.php:235
+msgid "Activate Call Waiting (deactivated by default)"
+msgstr ""
+
+#: ../includes/main.conf.php:236
+msgid "Deactivate Call Waiting"
+msgstr ""
+
+#: ../includes/main.conf.php:237
+msgid "Call Forwarding System"
+msgstr ""
+
+#: ../includes/main.conf.php:238
+msgid "Disable Call Forwarding"
+msgstr ""
+
+#: ../includes/main.conf.php:239
+msgid "IVR Recording"
+msgstr ""
+
+#: ../includes/main.conf.php:240
+msgid "Enable Do-Not-Disturb"
+msgstr ""
+
+#: ../includes/main.conf.php:241
+msgid "Disable Do-Not-Disturb"
+msgstr ""
+
+#: ../includes/main.conf.php:242
+msgid "Call Forward on Busy"
+msgstr ""
+
+#: ../includes/main.conf.php:243
+msgid "Disable Call Forward on Busy"
+msgstr ""
+
+#: ../includes/main.conf.php:244
+msgid "Message Center (does not ask for extension)"
+msgstr ""
+
+#: ../includes/main.conf.php:245
+msgid "Enter Message Center"
+msgstr ""
+
+#: ../includes/main.conf.php:246
+msgid "Playback IVR Recording"
+msgstr ""
+
+#: ../includes/main.conf.php:247
+msgid "Test Fax"
+msgstr ""
+
+#: ../includes/main.conf.php:248
+msgid "Simulate incoming call"
+msgstr ""
+
+#: ../includes/main.conf.php:289
+msgid "Email voicemail as attachment"
+msgstr ""
+
+#: ../includes/main.conf.php:290
+msgid "Say caller id in recording emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:291
+msgid "Say envelop (date/time) in recording emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:292
+msgid "Delete voicemail when emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:293
+msgid "Play next message after deleting current message"
+msgstr ""
+
+#: ../includes/main.conf.php:294
+msgid "Ask caller to review their voicemail before sending"
+msgstr ""
+
+#: ../includes/main.conf.php:295
+msgid "Maximum time in seconds a voicemail will record"
+msgstr ""
+
+#: ../modules/callmonitor.module:37 ../modules/callmonitor.module:257
+msgid "Call Monitor"
+msgstr ""
+
+#: ../modules/callmonitor.module:132
+#, php-format
+msgid "Path is not a directory: %s"
+msgstr ""
+
+#: ../modules/callmonitor.module:141 ../modules/voicemail.module:301
+msgid "delete"
+msgstr ""
+
+#: ../modules/callmonitor.module:147
+msgid "duration"
+msgstr ""
+
+#: ../modules/callmonitor.module:150
+msgid "ignore"
+msgstr ""
+
+#: ../modules/callmonitor.module:159 ../modules/voicemail.module:322
+msgid "Date"
+msgstr ""
+
+#: ../modules/callmonitor.module:163 ../modules/voicemail.module:326
+msgid "Caller ID"
+msgstr ""
+
+#: ../modules/callmonitor.module:165
+msgid "Source"
+msgstr ""
+
+#: ../modules/callmonitor.module:167
+msgid "Destination"
+msgstr ""
+
+#: ../modules/callmonitor.module:169
+msgid "Context"
+msgstr ""
+
+#: ../modules/callmonitor.module:171 ../modules/voicemail.module:332
+msgid "Duration"
+msgstr ""
+
+#: ../modules/callmonitor.module:202
+msgid "Monitor"
+msgstr ""
+
+#: ../modules/callmonitor.module:222 ../modules/voicemail.module:373
+msgid "play"
+msgstr ""
+
+#: ../modules/callmonitor.module:259
+#, php-format
+msgid "Call Monitor for %s (%s)"
+msgstr "Call Monitor for %s (%s)"
+
+#: ../modules/callmonitor.module:311 ../modules/voicemail.module:475
+msgid "select"
+msgstr ""
+
+#: ../modules/callmonitor.module:312 ../modules/voicemail.module:476
+msgid "all"
+msgstr ""
+
+#: ../modules/callmonitor.module:313 ../modules/voicemail.module:477
+msgid "none"
+msgstr ""
+
+#: ../modules/callmonitor.module:533
+msgid "Only deletes recording files, not cdr log"
+msgstr ""
+
+#: ../modules/conference.module:55
+msgid "My Conference room"
+msgstr ""
+
+#: ../modules/conference.module:78
+#, php-format
+msgid "Conference for %s (%s%s)"
+msgstr ""
+
+#: ../modules/help.module:39 ../modules/help.module:68
+msgid "Help"
+msgstr ""
+
+#: ../modules/help.module:70
+#, php-format
+msgid "Help for %s (%s)"
+msgstr ""
+
+#: ../modules/help.module:77
+msgid "Handset Feature Code"
+msgstr ""
+
+#: ../modules/help.module:80
+msgid "Action"
+msgstr ""
+
+#: ../modules/settings.module:61 ../modules/settings.module:667
+msgid "Settings"
+msgstr ""
+
+#: ../modules/settings.module:125
+msgid "Call forward number not changed"
+msgstr ""
+
+#: ../modules/settings.module:126
+#, php-format
+msgid ""
+"Number %s must contain dial numbers (characters like '(', '-', and ')' are "
+"ok)"
+msgstr ""
+
+#: ../modules/settings.module:151 ../modules/settings.module:156
+#: ../modules/settings.module:161 ../modules/settings.module:166
+#: ../modules/settings.module:176 ../modules/settings.module:181
+msgid "Voicemail password not changed"
+msgstr ""
+
+#: ../modules/settings.module:152
+msgid "Password and password confirm must not be blank"
+msgstr ""
+
+#: ../modules/settings.module:157
+#, php-format
+msgid "Passwords must be all numbers and greater than %d digits"
+msgstr ""
+
+#: ../modules/settings.module:162
+#, php-format
+msgid "Passwords must be all numbers and only %d digits"
+msgstr ""
+
+#: ../modules/settings.module:167
+msgid "Password and password confirm do not match"
+msgstr ""
+
+#: ../modules/settings.module:177 ../modules/settings.module:182
+#: ../modules/settings.module:234 ../modules/settings.module:239
+#, php-format
+msgid "%s does not exist or is not writable"
+msgstr ""
+
+#: ../modules/settings.module:223
+msgid "Voicemail email and pager address not changed"
+msgstr ""
+
+#: ../modules/settings.module:233 ../modules/settings.module:238
+msgid "Voicemail email settings not changed"
+msgstr ""
+
+#: ../modules/settings.module:385
+msgid "Language:"
+msgstr ""
+
+#: ../modules/settings.module:408
+msgid "Call Routing"
+msgstr ""
+
+#: ../modules/settings.module:411
+msgid "Call Forwarding:"
+msgstr ""
+
+#: ../modules/settings.module:419 ../modules/settings.module:507
+msgid "Enable"
+msgstr ""
+
+#: ../modules/settings.module:431
+#, php-format
+msgid "Passwords must be all numbers and only %s digits"
+msgstr ""
+
+#: ../modules/settings.module:434
+#, php-format
+msgid "Passwords must be all numbers and at least %s digits"
+msgstr ""
+
+#: ../modules/settings.module:439
+msgid "Voicemail Password:"
+msgstr ""
+
+#: ../modules/settings.module:445
+msgid "Enter again to confirm:"
+msgstr ""
+
+#: ../modules/settings.module:492
+msgid "Email Voicemail To:"
+msgstr ""
+
+#: ../modules/settings.module:498
+msgid "Pager Voicemail To:"
+msgstr ""
+
+#: ../modules/settings.module:558
+msgid "Audio Format:"
+msgstr ""
+
+#: ../modules/settings.module:561
+msgid "Best Quality"
+msgstr ""
+
+#: ../modules/settings.module:562
+msgid "Smallest Download"
+msgstr ""
+
+#: ../modules/settings.module:570
+msgid "Voicemail Settings"
+msgstr ""
+
+#: ../modules/settings.module:611
+msgid "Call Monitor Settings"
+msgstr "Call Monitor Settings"
+
+#: ../modules/settings.module:614
+msgid "Record INCOMING:"
+msgstr ""
+
+#: ../modules/settings.module:616 ../modules/settings.module:624
+msgid "Always"
+msgstr ""
+
+#: ../modules/settings.module:617 ../modules/settings.module:625
+msgid "Never"
+msgstr ""
+
+#: ../modules/settings.module:618 ../modules/settings.module:626
+msgid "On-Demand"
+msgstr ""
+
+#: ../modules/settings.module:622
+msgid "Record OUTGOING:"
+msgstr ""
+
+#: ../modules/settings.module:669
+#, php-format
+msgid "Settings for %s (%s)"
+msgstr ""
+
+#: ../modules/settings.module:705
+msgid "Update"
+msgstr ""
+
+#: ../modules/voicemail.module:45
+msgid "Voicemail"
+msgstr ""
+
+#: ../modules/voicemail.module:164
+msgid "A folder must be selected before the message can be moved."
+msgstr ""
+
+#: ../modules/voicemail.module:178
+msgid "An extension must be selected before the message can be forwarded."
+msgstr ""
+
+#: ../modules/voicemail.module:304
+msgid "move_to"
+msgstr ""
+
+#: ../modules/voicemail.module:307
+msgid "Folder"
+msgstr ""
+
+#: ../modules/voicemail.module:311
+msgid "forward_to"
+msgstr ""
+
+#: ../modules/voicemail.module:328
+msgid "Priority"
+msgstr ""
+
+#: ../modules/voicemail.module:330
+msgid "Orig Mailbox"
+msgstr ""
+
+#: ../modules/voicemail.module:362
+msgid "Message"
+msgstr ""
+
+#: ../modules/voicemail.module:377
+msgid "Voicemail recording(s) was not found."
+msgstr ""
+
+#: ../modules/voicemail.module:378
+#, php-format
+msgid ""
+"On settings page, change voicemail audio format. It is currently set to %s"
+msgstr ""
+
+#: ../modules/voicemail.module:405
+msgid "Voicemail Login not found."
+msgstr ""
+
+#: ../modules/voicemail.module:406
+msgid "No access to voicemail"
+msgstr ""
+
+#: ../modules/voicemail.module:412
+msgid "No Voicemail Recordings for Admin"
+msgstr ""
+
+#: ../modules/voicemail.module:428
+#, php-format
+msgid "Voicemail for %s (%s)"
+msgstr ""
+
+#: ../modules/voicemail.module:678
+#, php-format
+msgid "Could not create mailbox folder %s on the server"
+msgstr ""
+
+#: ../modules/voicemail.module:718
+#, php-format
+msgid "Permission denied on folder %s or %s"
+msgstr ""
+
+#: ../misc/recording_popup.php:39
+msgid "download"
+msgstr ""
diff --git a/fs_selfservice/fri/locale/ari.utf-8.po b/fs_selfservice/fri/locale/ari.utf-8.po
new file mode 100644
index 000000000..aff5a75d1
--- /dev/null
+++ b/fs_selfservice/fri/locale/ari.utf-8.po
@@ -0,0 +1,590 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-05-03 08:32-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../includes/asi.php:46
+msgid "Asterisk Call Manager not responding"
+msgstr ""
+
+#: ../includes/asi.php:54
+msgid "Asterisk authentication failed:"
+msgstr ""
+
+#: ../includes/asi.php:96 ../includes/asi.php:111
+msgid "Asterisk command not understood"
+msgstr ""
+
+#: ../includes/bootstrap.php:123
+#, php-format
+msgid "To many directories in %s Not all files processed"
+msgstr ""
+
+#: ../includes/bootstrap.php:226
+msgid "ARI requires a version of PHP 4.3 or later"
+msgstr ""
+
+#: ../includes/bootstrap.php:245
+msgid ""
+"PHP PEAR must be installed. Visit http://pear.php.net for help with "
+"installation."
+msgstr ""
+
+#: ../includes/common.php:173
+msgid "ARI does not appear to have access to the Asterisk Manager."
+msgstr ""
+
+#: ../includes/common.php:174
+msgid ""
+"Check the ARI 'main.conf.php' configuration file to set the Asterisk Manager "
+"Account."
+msgstr ""
+
+#: ../includes/common.php:175
+msgid "Check /etc/asterisk/manager.conf for a proper Asterisk Manager Account"
+msgstr ""
+
+#: ../includes/common.php:176
+msgid ""
+"make sure [general] enabled = yes and a 'permit=' line for localhost or the "
+"webserver."
+msgstr ""
+
+#: ../includes/common.php:193 ../includes/common.php:208
+msgid "Check AMP installation, asterisk, and ARI main.conf"
+msgstr ""
+
+#: ../includes/common.php:344
+msgid "Logout"
+msgstr ""
+
+#: ../includes/common.php:349
+msgid "Page Not Found."
+msgstr ""
+
+#: ../includes/display.php:92
+msgid "Search"
+msgstr ""
+
+#: ../includes/display.php:135
+msgid "Searched for"
+msgstr ""
+
+#: ../includes/display.php:139
+#, php-format
+msgid "Results %d - %d of %d"
+msgstr ""
+
+#: ../includes/display.php:141
+#, php-format
+msgid "Results %d"
+msgstr ""
+
+#: ../includes/display.php:195
+msgid "First"
+msgstr ""
+
+#: ../includes/display.php:208
+msgid "Last"
+msgstr ""
+
+#: ../includes/login.php:267
+msgid "Incorrect Password"
+msgstr ""
+
+#: ../includes/login.php:279
+msgid "Incorrect Username or Password"
+msgstr ""
+
+#: ../includes/login.php:402 ../includes/login.php:411
+msgid "Login"
+msgstr ""
+
+#: ../includes/login.php:419
+msgid "Password"
+msgstr ""
+
+#: ../includes/login.php:428
+msgid "Submit"
+msgstr ""
+
+#: ../includes/login.php:436
+msgid "Remember Password"
+msgstr ""
+
+#: ../includes/login.php:451
+msgid "Use your <b>Voicemail Mailbox and Password</b>"
+msgstr ""
+
+#: ../includes/login.php:452
+msgid "This is the same password used for the phone"
+msgstr ""
+
+#: ../includes/login.php:454
+msgid ""
+"For password maintenance or assistance, contact your Phone System "
+"Administrator."
+msgstr ""
+
+#: ../includes/main.conf.php:152
+msgid "INBOX"
+msgstr ""
+
+#: ../includes/main.conf.php:154
+msgid "Family"
+msgstr ""
+
+#: ../includes/main.conf.php:156
+msgid "Friends"
+msgstr ""
+
+#: ../includes/main.conf.php:158
+msgid "Old"
+msgstr ""
+
+#: ../includes/main.conf.php:160
+msgid "Work"
+msgstr ""
+
+#: ../includes/main.conf.php:229
+msgid "Directory"
+msgstr ""
+
+#: ../includes/main.conf.php:230
+msgid "Echo Test"
+msgstr ""
+
+#: ../includes/main.conf.php:231 ../modules/callmonitor.module:161
+#: ../modules/voicemail.module:324
+msgid "Time"
+msgstr ""
+
+#: ../includes/main.conf.php:232
+msgid "Weather"
+msgstr ""
+
+#: ../includes/main.conf.php:233
+msgid "Schedule wakeup call"
+msgstr ""
+
+#: ../includes/main.conf.php:234
+msgid "festival test (your extension is XXX)"
+msgstr ""
+
+#: ../includes/main.conf.php:235
+msgid "Activate Call Waiting (deactivated by default)"
+msgstr ""
+
+#: ../includes/main.conf.php:236
+msgid "Deactivate Call Waiting"
+msgstr ""
+
+#: ../includes/main.conf.php:237
+msgid "Call Forwarding System"
+msgstr ""
+
+#: ../includes/main.conf.php:238
+msgid "Disable Call Forwarding"
+msgstr ""
+
+#: ../includes/main.conf.php:239
+msgid "IVR Recording"
+msgstr ""
+
+#: ../includes/main.conf.php:240
+msgid "Enable Do-Not-Disturb"
+msgstr ""
+
+#: ../includes/main.conf.php:241
+msgid "Disable Do-Not-Disturb"
+msgstr ""
+
+#: ../includes/main.conf.php:242
+msgid "Call Forward on Busy"
+msgstr ""
+
+#: ../includes/main.conf.php:243
+msgid "Disable Call Forward on Busy"
+msgstr ""
+
+#: ../includes/main.conf.php:244
+msgid "Message Center (does not ask for extension)"
+msgstr ""
+
+#: ../includes/main.conf.php:245
+msgid "Enter Message Center"
+msgstr ""
+
+#: ../includes/main.conf.php:246
+msgid "Playback IVR Recording"
+msgstr ""
+
+#: ../includes/main.conf.php:247
+msgid "Test Fax"
+msgstr ""
+
+#: ../includes/main.conf.php:248
+msgid "Simulate incoming call"
+msgstr ""
+
+#: ../includes/main.conf.php:289
+msgid "Email voicemail as attachment"
+msgstr ""
+
+#: ../includes/main.conf.php:290
+msgid "Say caller id in recording emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:291
+msgid "Say envelop (date/time) in recording emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:292
+msgid "Delete voicemail when emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:293
+msgid "Play next message after deleting current message"
+msgstr ""
+
+#: ../includes/main.conf.php:294
+msgid "Ask caller to review their voicemail before sending"
+msgstr ""
+
+#: ../includes/main.conf.php:295
+msgid "Maximum time in seconds a voicemail will record"
+msgstr ""
+
+#: ../modules/callmonitor.module:37 ../modules/callmonitor.module:257
+msgid "Call Monitor"
+msgstr ""
+
+#: ../modules/callmonitor.module:132
+#, php-format
+msgid "Path is not a directory: %s"
+msgstr ""
+
+#: ../modules/callmonitor.module:141 ../modules/voicemail.module:301
+msgid "delete"
+msgstr ""
+
+#: ../modules/callmonitor.module:147
+msgid "duration"
+msgstr ""
+
+#: ../modules/callmonitor.module:150
+msgid "ignore"
+msgstr ""
+
+#: ../modules/callmonitor.module:159 ../modules/voicemail.module:322
+msgid "Date"
+msgstr ""
+
+#: ../modules/callmonitor.module:163 ../modules/voicemail.module:326
+msgid "Caller ID"
+msgstr ""
+
+#: ../modules/callmonitor.module:165
+msgid "Source"
+msgstr ""
+
+#: ../modules/callmonitor.module:167
+msgid "Destination"
+msgstr ""
+
+#: ../modules/callmonitor.module:169
+msgid "Context"
+msgstr ""
+
+#: ../modules/callmonitor.module:171 ../modules/voicemail.module:332
+msgid "Duration"
+msgstr ""
+
+#: ../modules/callmonitor.module:202
+msgid "Monitor"
+msgstr ""
+
+#: ../modules/callmonitor.module:222 ../modules/voicemail.module:373
+msgid "play"
+msgstr ""
+
+#: ../modules/callmonitor.module:259
+#, php-format
+msgid "Call Monitor for %s (%s)"
+msgstr ""
+
+#: ../modules/callmonitor.module:311 ../modules/voicemail.module:475
+msgid "select"
+msgstr ""
+
+#: ../modules/callmonitor.module:312 ../modules/voicemail.module:476
+msgid "all"
+msgstr ""
+
+#: ../modules/callmonitor.module:313 ../modules/voicemail.module:477
+msgid "none"
+msgstr ""
+
+#: ../modules/callmonitor.module:533
+msgid "Only deletes recording files, not cdr log"
+msgstr ""
+
+#: ../modules/conference.module:55
+msgid "My Conference room"
+msgstr ""
+
+#: ../modules/conference.module:78
+#, php-format
+msgid "Conference for %s (%s%s)"
+msgstr ""
+
+#: ../modules/help.module:39 ../modules/help.module:68
+msgid "Help"
+msgstr ""
+
+#: ../modules/help.module:70
+#, php-format
+msgid "Help for %s (%s)"
+msgstr ""
+
+#: ../modules/help.module:77
+msgid "Handset Feature Code"
+msgstr ""
+
+#: ../modules/help.module:80
+msgid "Action"
+msgstr ""
+
+#: ../modules/settings.module:61 ../modules/settings.module:667
+msgid "Settings"
+msgstr ""
+
+#: ../modules/settings.module:125
+msgid "Call forward number not changed"
+msgstr ""
+
+#: ../modules/settings.module:126
+#, php-format
+msgid ""
+"Number %s must contain dial numbers (characters like '(', '-', and ')' are "
+"ok)"
+msgstr ""
+
+#: ../modules/settings.module:151 ../modules/settings.module:156
+#: ../modules/settings.module:161 ../modules/settings.module:166
+#: ../modules/settings.module:176 ../modules/settings.module:181
+msgid "Voicemail password not changed"
+msgstr ""
+
+#: ../modules/settings.module:152
+msgid "Password and password confirm must not be blank"
+msgstr ""
+
+#: ../modules/settings.module:157
+#, php-format
+msgid "Passwords must be all numbers and greater than %d digits"
+msgstr ""
+
+#: ../modules/settings.module:162
+#, php-format
+msgid "Passwords must be all numbers and only %d digits"
+msgstr ""
+
+#: ../modules/settings.module:167
+msgid "Password and password confirm do not match"
+msgstr ""
+
+#: ../modules/settings.module:177 ../modules/settings.module:182
+#: ../modules/settings.module:234 ../modules/settings.module:239
+#, php-format
+msgid "%s does not exist or is not writable"
+msgstr ""
+
+#: ../modules/settings.module:223
+msgid "Voicemail email and pager address not changed"
+msgstr ""
+
+#: ../modules/settings.module:233 ../modules/settings.module:238
+msgid "Voicemail email settings not changed"
+msgstr ""
+
+#: ../modules/settings.module:385
+msgid "Language:"
+msgstr ""
+
+#: ../modules/settings.module:408
+msgid "Call Routing"
+msgstr ""
+
+#: ../modules/settings.module:411
+msgid "Call Forwarding:"
+msgstr ""
+
+#: ../modules/settings.module:419 ../modules/settings.module:507
+msgid "Enable"
+msgstr ""
+
+#: ../modules/settings.module:431
+#, php-format
+msgid "Passwords must be all numbers and only %s digits"
+msgstr ""
+
+#: ../modules/settings.module:434
+#, php-format
+msgid "Passwords must be all numbers and at least %s digits"
+msgstr ""
+
+#: ../modules/settings.module:439
+msgid "Voicemail Password:"
+msgstr ""
+
+#: ../modules/settings.module:445
+msgid "Enter again to confirm:"
+msgstr ""
+
+#: ../modules/settings.module:492
+msgid "Email Voicemail To:"
+msgstr ""
+
+#: ../modules/settings.module:498
+msgid "Pager Voicemail To:"
+msgstr ""
+
+#: ../modules/settings.module:558
+msgid "Audio Format:"
+msgstr ""
+
+#: ../modules/settings.module:561
+msgid "Best Quality"
+msgstr ""
+
+#: ../modules/settings.module:562
+msgid "Smallest Download"
+msgstr ""
+
+#: ../modules/settings.module:570
+msgid "Voicemail Settings"
+msgstr ""
+
+#: ../modules/settings.module:611
+msgid "Call Monitor Settings"
+msgstr ""
+
+#: ../modules/settings.module:614
+msgid "Record INCOMING:"
+msgstr ""
+
+#: ../modules/settings.module:616 ../modules/settings.module:624
+msgid "Always"
+msgstr ""
+
+#: ../modules/settings.module:617 ../modules/settings.module:625
+msgid "Never"
+msgstr ""
+
+#: ../modules/settings.module:618 ../modules/settings.module:626
+msgid "On-Demand"
+msgstr ""
+
+#: ../modules/settings.module:622
+msgid "Record OUTGOING:"
+msgstr ""
+
+#: ../modules/settings.module:669
+#, php-format
+msgid "Settings for %s (%s)"
+msgstr ""
+
+#: ../modules/settings.module:705
+msgid "Update"
+msgstr ""
+
+#: ../modules/voicemail.module:45
+msgid "Voicemail"
+msgstr ""
+
+#: ../modules/voicemail.module:164
+msgid "A folder must be selected before the message can be moved."
+msgstr ""
+
+#: ../modules/voicemail.module:178
+msgid "An extension must be selected before the message can be forwarded."
+msgstr ""
+
+#: ../modules/voicemail.module:304
+msgid "move_to"
+msgstr ""
+
+#: ../modules/voicemail.module:307
+msgid "Folder"
+msgstr ""
+
+#: ../modules/voicemail.module:311
+msgid "forward_to"
+msgstr ""
+
+#: ../modules/voicemail.module:328
+msgid "Priority"
+msgstr ""
+
+#: ../modules/voicemail.module:330
+msgid "Orig Mailbox"
+msgstr ""
+
+#: ../modules/voicemail.module:362
+msgid "Message"
+msgstr ""
+
+#: ../modules/voicemail.module:377
+msgid "Voicemail recording(s) was not found."
+msgstr ""
+
+#: ../modules/voicemail.module:378
+#, php-format
+msgid ""
+"On settings page, change voicemail audio format. It is currently set to %s"
+msgstr ""
+
+#: ../modules/voicemail.module:405
+msgid "Voicemail Login not found."
+msgstr ""
+
+#: ../modules/voicemail.module:406
+msgid "No access to voicemail"
+msgstr ""
+
+#: ../modules/voicemail.module:412
+msgid "No Voicemail Recordings for Admin"
+msgstr ""
+
+#: ../modules/voicemail.module:428
+#, php-format
+msgid "Voicemail for %s (%s)"
+msgstr ""
+
+#: ../modules/voicemail.module:678
+#, php-format
+msgid "Could not create mailbox folder %s on the server"
+msgstr ""
+
+#: ../modules/voicemail.module:718
+#, php-format
+msgid "Permission denied on folder %s or %s"
+msgstr ""
+
+#: ../misc/recording_popup.php:39
+msgid "download"
+msgstr ""
diff --git a/fs_selfservice/fri/locale/de_DE/LC_MESSAGES/ari.mo b/fs_selfservice/fri/locale/de_DE/LC_MESSAGES/ari.mo
new file mode 100644
index 000000000..b94eba261
--- /dev/null
+++ b/fs_selfservice/fri/locale/de_DE/LC_MESSAGES/ari.mo
Binary files differ
diff --git a/fs_selfservice/fri/locale/de_DE/LC_MESSAGES/ari.po b/fs_selfservice/fri/locale/de_DE/LC_MESSAGES/ari.po
new file mode 100644
index 000000000..b89b612ee
--- /dev/null
+++ b/fs_selfservice/fri/locale/de_DE/LC_MESSAGES/ari.po
@@ -0,0 +1,631 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) 2005 AsteriskPBX.de
+# This file is distributed under the same license as the PACKAGE package.
+# Till Stoemer <ts@AsteriskPBX.de>, 2005.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: ari-de\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-04-03 08:26-0400\n"
+"PO-Revision-Date: 2005-12-10 19:50+0100\n"
+"Last-Translator: Till Stoermer <ts@AsteriskPBX.de>\n"
+"Language-Team: German <ts@AsteriskPBX.de>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../includes/asi.php:48
+msgid "Asterisk Call Manager not responding"
+msgstr "Der Asterisk Call-Manager reagiert nicht."
+
+#: ../includes/asi.php:56
+msgid "Asterisk authentication failed:"
+msgstr "Anmeldung am Asterisk gescheitert."
+
+#: ../includes/asi.php:98 ../includes/asi.php:112
+#, fuzzy
+msgid "Asterisk command not understood"
+msgstr "Asterisk reload command not understood"
+
+#: ../includes/bootstrap.php:106
+#, php-format
+msgid "To many directories in %s Not all files processed"
+msgstr ""
+
+#: ../includes/bootstrap.php:209
+msgid "ARI requires a version of PHP 4.0 or later"
+msgstr ""
+
+#: ../includes/bootstrap.php:228
+msgid ""
+"PHP PEAR must be installed. Visit http://pear.php.net for help with "
+"installation."
+msgstr ""
+
+#: ../includes/common.php:167
+#, fuzzy
+msgid "ARI does not appear to have access to the Asterisk Manager."
+msgstr "Kann nicht zum Asterisk-Manager verbinden"
+
+#: ../includes/common.php:168
+msgid ""
+"Check the ARI 'main.conf' configuration file to set the Asterisk Manager "
+"Account."
+msgstr ""
+
+#: ../includes/common.php:169
+msgid "Check /etc/asterisk/manager.conf for a proper Asterisk Manager Account"
+msgstr ""
+
+#: ../includes/common.php:170
+msgid ""
+"make sure [general] enabled = yes and a 'permit=' line for localhost or the "
+"webserver."
+msgstr ""
+
+#: ../includes/common.php:187 ../includes/common.php:202
+#, fuzzy
+msgid "Check AMP installation, asterisk, and ARI main.conf"
+msgstr ""
+"&Uuml;berpr&uuml;fe die AMP-Installation, Asterisk-Datenbank, oder die ARI "
+"main.conf"
+
+#: ../includes/common.php:332
+msgid "Logout"
+msgstr "Abmelden"
+
+#: ../includes/common.php:337
+msgid "Page Not Found."
+msgstr "Seite nicht gefunden"
+
+#: ../includes/display.php:92
+msgid "Search"
+msgstr "Suchen"
+
+#: ../includes/display.php:135
+msgid "Searched for"
+msgstr "Suchen nach"
+
+#: ../includes/display.php:139
+#, fuzzy, php-format
+msgid "Results %d of %d"
+msgstr "Ergebnis"
+
+#: ../includes/display.php:141
+#, fuzzy, php-format
+msgid "Results %d"
+msgstr "Ergebnis"
+
+#: ../includes/display.php:195
+msgid "First"
+msgstr "Erste"
+
+#: ../includes/display.php:208
+msgid "Last"
+msgstr "Letzte"
+
+#: ../includes/login.php:239
+#, fuzzy
+msgid "Voicemail Login not found."
+msgstr "Vicemail-Login nicht gefunden"
+
+#: ../includes/login.php:240
+msgid "No access to voicemail"
+msgstr "Kein Zugriff auf Voicemail"
+
+#: ../includes/login.php:266
+msgid "Incorrect Password"
+msgstr "Falsches Passwort"
+
+#: ../includes/login.php:278
+msgid "Incorrect Username or Password"
+msgstr "Falscher Benutzer oder Passwort"
+
+#: ../includes/login.php:381 ../includes/login.php:391
+msgid "Login"
+msgstr "Anmeldung"
+
+#: ../includes/login.php:399
+msgid "Password"
+msgstr "Passwort"
+
+#: ../includes/login.php:408
+msgid "Submit"
+msgstr "Anmelden"
+
+#: ../includes/login.php:416
+msgid "Remember Password"
+msgstr "Passwort merken"
+
+#: ../includes/login.php:431
+#, fuzzy
+msgid "Use your <b>Voicemail Mailbox and Password</b>"
+msgstr "Voicemail Mailbox und Password"
+
+#: ../includes/login.php:432
+msgid "This is the same password used for the phone"
+msgstr "Dieses ist das selbe Passwort, das beim Telefon genutzt wird."
+
+#: ../includes/login.php:434
+msgid ""
+"For password maintenance or assistance, contact your Phone System "
+"Administrator."
+msgstr ""
+"F&uuml;r Passwort-&Auml;nderungen, kontaktieren Sie Ihren Voicemail-Admin"
+
+#: ../includes/main.conf.php:152
+msgid "INBOX"
+msgstr "Eingang"
+
+#: ../includes/main.conf.php:154
+msgid "Family"
+msgstr "Familie"
+
+#: ../includes/main.conf.php:156
+msgid "Friends"
+msgstr "Freunde"
+
+#: ../includes/main.conf.php:158
+msgid "Old"
+msgstr "Alt"
+
+#: ../includes/main.conf.php:160
+msgid "Work"
+msgstr "Arbeit"
+
+#: ../includes/main.conf.php:213
+msgid "Directory"
+msgstr ""
+
+#: ../includes/main.conf.php:214
+msgid "Echo Test"
+msgstr ""
+
+#: ../includes/main.conf.php:215 ../modules/callmonitor.module:161
+#: ../modules/voicemail.module:326
+msgid "Time"
+msgstr "Uhrzeit"
+
+#: ../includes/main.conf.php:216
+msgid "Weather"
+msgstr ""
+
+#: ../includes/main.conf.php:217
+msgid "Schedule wakeup call"
+msgstr ""
+
+#: ../includes/main.conf.php:218
+msgid "festival test (your extension is XXX)"
+msgstr ""
+
+#: ../includes/main.conf.php:219
+msgid "Activate Call Waiting (deactivated by default)"
+msgstr ""
+
+#: ../includes/main.conf.php:220
+msgid "Deactivate Call Waiting"
+msgstr ""
+
+#: ../includes/main.conf.php:221
+msgid "Call Forwarding System"
+msgstr ""
+
+#: ../includes/main.conf.php:222
+msgid "Disable Call Forwarding"
+msgstr ""
+
+#: ../includes/main.conf.php:223
+#, fuzzy
+msgid "IVR Recording"
+msgstr "Aufnahmen"
+
+#: ../includes/main.conf.php:224
+msgid "Enable Do-Not-Disturb"
+msgstr ""
+
+#: ../includes/main.conf.php:225
+msgid "Disable Do-Not-Disturb"
+msgstr ""
+
+#: ../includes/main.conf.php:226
+msgid "Call Forward on Busy"
+msgstr ""
+
+#: ../includes/main.conf.php:227
+msgid "Disable Call Forward on Busy"
+msgstr ""
+
+#: ../includes/main.conf.php:228
+msgid "Message Center (does no ask for extension)"
+msgstr ""
+
+#: ../includes/main.conf.php:229
+msgid "Enter Message Center"
+msgstr ""
+
+#: ../includes/main.conf.php:230
+msgid "Playback IVR Recording"
+msgstr ""
+
+#: ../includes/main.conf.php:231
+msgid "Test Fax"
+msgstr ""
+
+#: ../includes/main.conf.php:232
+msgid "Simulate incoming call"
+msgstr ""
+
+#: ../includes/main.conf.php:273
+msgid "Email voicemail as attachment"
+msgstr ""
+
+#: ../includes/main.conf.php:274
+msgid "Say caller id in recording emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:275
+msgid "Say envelop (date/time) in recording emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:276
+msgid "Delete voicemail when emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:277
+msgid "Play next message after deleting current message"
+msgstr ""
+
+#: ../includes/main.conf.php:278
+msgid "Ask caller to review their voicemail before sending"
+msgstr ""
+
+#: ../includes/main.conf.php:279
+msgid "Maximum time in seconds a voicemail will record"
+msgstr ""
+
+#: ../modules/callmonitor.module:37 ../modules/callmonitor.module:257
+msgid "Call Monitor"
+msgstr "Anrufliste"
+
+#: ../modules/callmonitor.module:132 ../modules/voicemail.module:117
+#, php-format
+msgid "Path is not a directory: %s"
+msgstr ""
+
+#: ../modules/callmonitor.module:141 ../modules/voicemail.module:303
+#, fuzzy
+msgid "delete"
+msgstr "Ausw&auml;hlen"
+
+#: ../modules/callmonitor.module:147
+#, fuzzy
+msgid "duration"
+msgstr "Dauer"
+
+#: ../modules/callmonitor.module:150
+#, fuzzy
+msgid "ignore"
+msgstr "Keine"
+
+#: ../modules/callmonitor.module:159 ../modules/voicemail.module:324
+msgid "Date"
+msgstr "Datum"
+
+#: ../modules/callmonitor.module:163 ../modules/voicemail.module:328
+msgid "Caller ID"
+msgstr "Anrufer-Nummer"
+
+#: ../modules/callmonitor.module:165
+msgid "Source"
+msgstr "Anrufer"
+
+#: ../modules/callmonitor.module:167
+msgid "Destination"
+msgstr "Angerufener"
+
+#: ../modules/callmonitor.module:169
+msgid "Context"
+msgstr "Kontext"
+
+#: ../modules/callmonitor.module:171 ../modules/voicemail.module:334
+msgid "Duration"
+msgstr "Dauer"
+
+#: ../modules/callmonitor.module:202
+msgid "Monitor"
+msgstr "Monitor"
+
+#: ../modules/callmonitor.module:222 ../modules/voicemail.module:375
+msgid "play"
+msgstr "Abspielen"
+
+#: ../modules/callmonitor.module:259
+#, fuzzy, php-format
+msgid "Call Monitor for %s (%s)"
+msgstr "Anrufliste"
+
+#: ../modules/callmonitor.module:311 ../modules/voicemail.module:459
+msgid "select"
+msgstr "Ausw&auml;hlen"
+
+#: ../modules/callmonitor.module:312 ../modules/voicemail.module:460
+msgid "all"
+msgstr "Alle"
+
+#: ../modules/callmonitor.module:313 ../modules/voicemail.module:461
+msgid "none"
+msgstr "Keine"
+
+#: ../modules/callmonitor.module:543
+msgid "Only deletes recording files, not cdr log"
+msgstr "Nur die Aufnahme-Datei wird gel&ouml;scht (In der CDR nicht)"
+
+#: ../modules/help.module:39 ../modules/help.module:68
+msgid "Help"
+msgstr ""
+
+#: ../modules/help.module:70
+#, php-format
+msgid "Help for %s (%s)"
+msgstr ""
+
+#: ../modules/help.module:77
+msgid "Handset Feature Code"
+msgstr ""
+
+#: ../modules/help.module:80
+msgid "Action"
+msgstr ""
+
+#: ../modules/settings.module:61 ../modules/settings.module:647
+msgid "Settings"
+msgstr "Einstellungen"
+
+#: ../modules/settings.module:122
+msgid "Call forward number not changed"
+msgstr ""
+
+#: ../modules/settings.module:123
+#, php-format
+msgid ""
+"Number %s must contain dial numbers (characters like '(', '-', and ')' are "
+"ok)"
+msgstr ""
+
+#: ../modules/settings.module:143 ../modules/settings.module:148
+#: ../modules/settings.module:153 ../modules/settings.module:158
+#: ../modules/settings.module:168 ../modules/settings.module:173
+msgid "Voicemail password not changed"
+msgstr "Voicemail-Passwort nicht ge&auml;ndert"
+
+#: ../modules/settings.module:144
+msgid "Password and password confirm must not be blank"
+msgstr "Passwort und Passwort-Wiederholen-Feld darf nicht leer sein"
+
+#: ../modules/settings.module:149
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and greater than %d digits"
+msgstr "Das Passwort muss aus mindestens 4 Ziffern bestehen."
+
+#: ../modules/settings.module:154
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and only %d digits"
+msgstr "Das Passwort muss aus mindestens 4 Ziffern bestehen."
+
+#: ../modules/settings.module:159
+msgid "Password and password confirm do not match"
+msgstr "Die Passwort stimmen nicht &uuml;berein."
+
+#: ../modules/settings.module:169 ../modules/settings.module:174
+#: ../modules/settings.module:226 ../modules/settings.module:231
+#, fuzzy, php-format
+msgid "%s does not exist or is not writable"
+msgstr "existiert nicht, oder ist nicht lesbar."
+
+#: ../modules/settings.module:215
+#, fuzzy
+msgid "Voicemail email and pager address not changed"
+msgstr "Voicemail-Passwort nicht ge&auml;ndert"
+
+#: ../modules/settings.module:225 ../modules/settings.module:230
+#, fuzzy
+msgid "Voicemail email settings not changed"
+msgstr "Voicemail-Passwort nicht ge&auml;ndert"
+
+#: ../modules/settings.module:375
+msgid "Language:"
+msgstr "Sprache"
+
+#: ../modules/settings.module:396
+#, fuzzy
+msgid "Call Routing"
+msgstr "Call Monitor Einstellungen"
+
+#: ../modules/settings.module:399
+msgid "Call Forwarding:"
+msgstr ""
+
+#: ../modules/settings.module:407 ../modules/settings.module:486
+#, fuzzy
+msgid "Enable"
+msgstr "in Tabelle"
+
+#: ../modules/settings.module:418
+msgid "Voicemail Password:"
+msgstr "Voicemail-Passwort"
+
+#: ../modules/settings.module:424
+msgid "Enter again to confirm:"
+msgstr "Erneute Eingabe zum best&auml;tigen"
+
+#: ../modules/settings.module:430
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and only %s digits"
+msgstr "Das Passwort muss aus mindestens 4 Ziffern bestehen."
+
+#: ../modules/settings.module:471
+#, fuzzy
+msgid "Email Voicemail To:"
+msgstr "Voicemail"
+
+#: ../modules/settings.module:477
+#, fuzzy
+msgid "Pager Voicemail To:"
+msgstr "Voicemail"
+
+#: ../modules/settings.module:539
+msgid "Audio Format:"
+msgstr "Audio-Format"
+
+#: ../modules/settings.module:542
+msgid "Best Quality"
+msgstr "Beste Qualit&auml;t"
+
+#: ../modules/settings.module:543
+msgid "Smallest Download"
+msgstr "F&uuml;r geringen Download"
+
+#: ../modules/settings.module:551
+msgid "Voicemail Settings"
+msgstr "Voicemail-Einstellungen"
+
+#: ../modules/settings.module:591
+msgid "Call Monitor Settings"
+msgstr "Call Monitor Einstellungen"
+
+#: ../modules/settings.module:594
+msgid "Record INCOMING:"
+msgstr "Aufnahme eingehender Telefonate:"
+
+#: ../modules/settings.module:596 ../modules/settings.module:604
+msgid "Always"
+msgstr "Immer"
+
+#: ../modules/settings.module:597 ../modules/settings.module:605
+msgid "Never"
+msgstr "Nie"
+
+#: ../modules/settings.module:598 ../modules/settings.module:606
+msgid "On-Demand"
+msgstr "Bei Bedarf"
+
+#: ../modules/settings.module:602
+msgid "Record OUTGOING:"
+msgstr "Aufnahme abgehende Telefonate"
+
+#: ../modules/settings.module:649
+#, fuzzy, php-format
+msgid "Settings for %s (%s)"
+msgstr "Einstellungen f&uuml;r"
+
+#: ../modules/settings.module:685
+msgid "Update"
+msgstr "Erneuern"
+
+#: ../modules/voicemail.module:45
+msgid "Voicemail"
+msgstr "Voicemail"
+
+#: ../modules/voicemail.module:161
+msgid "A folder must be selected before the message can be moved."
+msgstr ""
+"Ein Ordner muss gew&auml;hlt werden, bevor die Nachricht verschoben werden "
+"kann."
+
+#: ../modules/voicemail.module:175
+msgid "An extension must be selected before the message can be forwarded."
+msgstr ""
+"Ein Anschluss muss gew&auml;hlt werden, bevor die Nachricht weitergeleitet "
+"werden kann."
+
+#: ../modules/voicemail.module:239
+msgid "No Voicemail Recordings for Admin"
+msgstr "No Voicemail Recordings for Admin"
+
+#: ../modules/voicemail.module:306
+msgid "move_to"
+msgstr ""
+
+#: ../modules/voicemail.module:309
+msgid "Folder"
+msgstr "Ordner"
+
+#: ../modules/voicemail.module:313
+msgid "forward_to"
+msgstr ""
+
+#: ../modules/voicemail.module:330
+msgid "Priority"
+msgstr "Prirorit&auml;t"
+
+#: ../modules/voicemail.module:332
+msgid "Orig Mailbox"
+msgstr "Orig Mailbox"
+
+#: ../modules/voicemail.module:364
+msgid "Message"
+msgstr ""
+
+#: ../modules/voicemail.module:379
+msgid "Voicemail recording(s) was not found."
+msgstr "Sprachnachricht(en) nicht gefunden"
+
+#: ../modules/voicemail.module:380
+#, php-format
+msgid ""
+"On settings page, change voicemail audio format. It is currently set to %s"
+msgstr ""
+
+#: ../modules/voicemail.module:412
+#, fuzzy, php-format
+msgid "Voicemail for %s (%s)"
+msgstr "Voicemail"
+
+#: ../modules/voicemail.module:662
+#, fuzzy, php-format
+msgid "Could not create mailbox folder %s on the server"
+msgstr "Konnte Mailbox-Ordner nicht erstellen"
+
+#: ../modules/voicemail.module:702
+#, fuzzy, php-format
+msgid "Permission denied on folder %s or %s"
+msgstr "Zugriff verweigert auf Ordner"
+
+#: ../misc/recording_popup.php:39
+msgid "download"
+msgstr "Download"
+
+#~ msgid "not a directory or not readable"
+#~ msgstr "Kein Verzeichnis, oder nicht lesbar"
+
+#~ msgid "No database connection"
+#~ msgstr "Keine Verbindung zur Datenbank"
+
+#~ msgid "of"
+#~ msgstr "von"
+
+#~ msgid "Login used"
+#~ msgstr "Login genutzt"
+
+#~ msgid "Use your"
+#~ msgstr "Nutze Deine"
+
+#~ msgid "for"
+#~ msgstr "f&uuml;r"
+
+#~ msgid "Password must be all numbers and 4 digits"
+#~ msgstr "Das Passwort muss aus mindestens 4 Ziffern bestehen."
+
+#~ msgid "Check voicemail audio format on settings page to change from"
+#~ msgstr "Check voicemail audio format on settings page to change from"
+
+#~ msgid "Searching of voicemail is not yet implemented"
+#~ msgstr "Searching of voicemail is not yet implemented"
+
+#~ msgid "on the server"
+#~ msgstr "auf dem Server"
+
+#~ msgid "Folders"
+#~ msgstr "Ordner"
diff --git a/fs_selfservice/fri/locale/el_GR/LC_MESSAGES/ari.mo b/fs_selfservice/fri/locale/el_GR/LC_MESSAGES/ari.mo
new file mode 100644
index 000000000..6b00b14d7
--- /dev/null
+++ b/fs_selfservice/fri/locale/el_GR/LC_MESSAGES/ari.mo
Binary files differ
diff --git a/fs_selfservice/fri/locale/el_GR/LC_MESSAGES/ari.po b/fs_selfservice/fri/locale/el_GR/LC_MESSAGES/ari.po
new file mode 100644
index 000000000..25664941c
--- /dev/null
+++ b/fs_selfservice/fri/locale/el_GR/LC_MESSAGES/ari.po
@@ -0,0 +1,648 @@
+# Copyright (C) 2005 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Elias Sofronas <esofronas@gmail.com>, 2005.
+#
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-05-03 08:32-0400\n"
+"PO-Revision-Date: 2005-11-14 10:06+0200\n"
+"Last-Translator: Elias Sofronas <esofronas@gmail.com>\n"
+"Language-Team: English <en@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../includes/asi.php:46
+msgid "Asterisk Call Manager not responding"
+msgstr "Ο διαχειÏιστής κλήσεων Asterisk δεν αποκÏίνεται"
+
+#: ../includes/asi.php:54
+msgid "Asterisk authentication failed:"
+msgstr "Η πιστοποίηση στο Asterisk απέτυχε:"
+
+#: ../includes/asi.php:96 ../includes/asi.php:111
+#, fuzzy
+msgid "Asterisk command not understood"
+msgstr "Η εντολή Asterisk επαναφόÏτωσης δεν αναγνωÏίστηκε"
+
+#: ../includes/bootstrap.php:123
+#, php-format
+msgid "To many directories in %s Not all files processed"
+msgstr ""
+
+#: ../includes/bootstrap.php:226
+msgid "ARI requires a version of PHP 4.3 or later"
+msgstr ""
+
+#: ../includes/bootstrap.php:245
+msgid ""
+"PHP PEAR must be installed. Visit http://pear.php.net for help with "
+"installation."
+msgstr ""
+
+#: ../includes/common.php:173
+#, fuzzy
+msgid "ARI does not appear to have access to the Asterisk Manager."
+msgstr "ΑδÏνατη η σÏνδεση στον Asterisk Manager"
+
+#: ../includes/common.php:174
+msgid ""
+"Check the ARI 'main.conf.php' configuration file to set the Asterisk Manager "
+"Account."
+msgstr ""
+
+#: ../includes/common.php:175
+msgid "Check /etc/asterisk/manager.conf for a proper Asterisk Manager Account"
+msgstr ""
+
+#: ../includes/common.php:176
+msgid ""
+"make sure [general] enabled = yes and a 'permit=' line for localhost or the "
+"webserver."
+msgstr ""
+
+#: ../includes/common.php:193 ../includes/common.php:208
+#, fuzzy
+msgid "Check AMP installation, asterisk, and ARI main.conf"
+msgstr ""
+"Ελέγχτε την εγκατάσταση του AMP, την βάση δεδομένων του asterisk, ή το ARI "
+"main.conf"
+
+#: ../includes/common.php:344
+msgid "Logout"
+msgstr "ΑποσÏνδεση"
+
+#: ../includes/common.php:349
+msgid "Page Not Found."
+msgstr "Η σελίδα δεν βÏέθηκε"
+
+#: ../includes/display.php:92
+msgid "Search"
+msgstr "ΕÏÏεση"
+
+#: ../includes/display.php:135
+msgid "Searched for"
+msgstr "ΕÏÏεση για"
+
+#: ../includes/display.php:139
+#, fuzzy, php-format
+msgid "Results %d - %d of %d"
+msgstr "Αποτελέσματα"
+
+#: ../includes/display.php:141
+#, fuzzy, php-format
+msgid "Results %d"
+msgstr "Αποτελέσματα"
+
+#: ../includes/display.php:195
+msgid "First"
+msgstr "ΠÏώτο"
+
+#: ../includes/display.php:208
+msgid "Last"
+msgstr "Τελευταίο"
+
+#: ../includes/login.php:267
+msgid "Incorrect Password"
+msgstr "Λάθος Κωδικός"
+
+#: ../includes/login.php:279
+msgid "Incorrect Username or Password"
+msgstr "Λάθος όνομα χÏήστη ή κωδικός"
+
+#: ../includes/login.php:402 ../includes/login.php:411
+msgid "Login"
+msgstr "ΘυÏίδα"
+
+#: ../includes/login.php:419
+msgid "Password"
+msgstr "Κωδικός"
+
+#: ../includes/login.php:428
+msgid "Submit"
+msgstr "Είσοδος"
+
+#: ../includes/login.php:436
+msgid "Remember Password"
+msgstr "Απομνημόνευση ΚωδικοÏ"
+
+#: ../includes/login.php:451
+#, fuzzy
+msgid "Use your <b>Voicemail Mailbox and Password</b>"
+msgstr "ΘυÏίδα Τηλεφωνητή και Κωδικό"
+
+#: ../includes/login.php:452
+msgid "This is the same password used for the phone"
+msgstr "Αυτό είναι ο ίδιος κωδικός που χÏησιμοποιήθηκε για το τηλέφωνο"
+
+#: ../includes/login.php:454
+msgid ""
+"For password maintenance or assistance, contact your Phone System "
+"Administrator."
+msgstr ""
+"Για αλλαγή ÎºÏ‰Î´Î¹ÎºÎ¿Ï Î® υποστήÏιξη, επικοινωνήστε με τον ΔιαχειÏιστή του "
+"συστήματος"
+
+#: ../includes/main.conf.php:152
+msgid "INBOX"
+msgstr "ΕΣΕΡΧΟΜΕÎΑ"
+
+#: ../includes/main.conf.php:154
+msgid "Family"
+msgstr "ΟΙΚΟΓΕÎΕΙΑ"
+
+#: ../includes/main.conf.php:156
+msgid "Friends"
+msgstr "ΦΙΛΟΙ"
+
+#: ../includes/main.conf.php:158
+msgid "Old"
+msgstr "ΠΑΛΙΑ"
+
+#: ../includes/main.conf.php:160
+msgid "Work"
+msgstr "ΔΟΥΛΕΙΑ"
+
+#: ../includes/main.conf.php:229
+msgid "Directory"
+msgstr ""
+
+#: ../includes/main.conf.php:230
+msgid "Echo Test"
+msgstr ""
+
+#: ../includes/main.conf.php:231 ../modules/callmonitor.module:161
+#: ../modules/voicemail.module:324
+msgid "Time"
+msgstr "ÎÏα"
+
+#: ../includes/main.conf.php:232
+msgid "Weather"
+msgstr ""
+
+#: ../includes/main.conf.php:233
+msgid "Schedule wakeup call"
+msgstr ""
+
+#: ../includes/main.conf.php:234
+msgid "festival test (your extension is XXX)"
+msgstr ""
+
+#: ../includes/main.conf.php:235
+msgid "Activate Call Waiting (deactivated by default)"
+msgstr ""
+
+#: ../includes/main.conf.php:236
+msgid "Deactivate Call Waiting"
+msgstr ""
+
+#: ../includes/main.conf.php:237
+msgid "Call Forwarding System"
+msgstr ""
+
+#: ../includes/main.conf.php:238
+msgid "Disable Call Forwarding"
+msgstr ""
+
+#: ../includes/main.conf.php:239
+#, fuzzy
+msgid "IVR Recording"
+msgstr "Μυνήματα ΘυÏίδας"
+
+#: ../includes/main.conf.php:240
+msgid "Enable Do-Not-Disturb"
+msgstr ""
+
+#: ../includes/main.conf.php:241
+msgid "Disable Do-Not-Disturb"
+msgstr ""
+
+#: ../includes/main.conf.php:242
+msgid "Call Forward on Busy"
+msgstr ""
+
+#: ../includes/main.conf.php:243
+msgid "Disable Call Forward on Busy"
+msgstr ""
+
+#: ../includes/main.conf.php:244
+msgid "Message Center (does not ask for extension)"
+msgstr ""
+
+#: ../includes/main.conf.php:245
+msgid "Enter Message Center"
+msgstr ""
+
+#: ../includes/main.conf.php:246
+msgid "Playback IVR Recording"
+msgstr ""
+
+#: ../includes/main.conf.php:247
+msgid "Test Fax"
+msgstr ""
+
+#: ../includes/main.conf.php:248
+msgid "Simulate incoming call"
+msgstr ""
+
+#: ../includes/main.conf.php:289
+msgid "Email voicemail as attachment"
+msgstr ""
+
+#: ../includes/main.conf.php:290
+msgid "Say caller id in recording emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:291
+msgid "Say envelop (date/time) in recording emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:292
+msgid "Delete voicemail when emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:293
+msgid "Play next message after deleting current message"
+msgstr ""
+
+#: ../includes/main.conf.php:294
+msgid "Ask caller to review their voicemail before sending"
+msgstr ""
+
+#: ../includes/main.conf.php:295
+msgid "Maximum time in seconds a voicemail will record"
+msgstr ""
+
+#: ../modules/callmonitor.module:37 ../modules/callmonitor.module:257
+msgid "Call Monitor"
+msgstr "ΠαÏακολοÏθηση Κλήσεων"
+
+#: ../modules/callmonitor.module:132
+#, php-format
+msgid "Path is not a directory: %s"
+msgstr ""
+
+#: ../modules/callmonitor.module:141 ../modules/voicemail.module:301
+msgid "delete"
+msgstr "διαγÏαφή"
+
+#: ../modules/callmonitor.module:147
+#, fuzzy
+msgid "duration"
+msgstr "ΔιάÏκεια"
+
+#: ../modules/callmonitor.module:150
+#, fuzzy
+msgid "ignore"
+msgstr "κανένα"
+
+#: ../modules/callmonitor.module:159 ../modules/voicemail.module:322
+msgid "Date"
+msgstr "ΗμεÏομηνία"
+
+#: ../modules/callmonitor.module:163 ../modules/voicemail.module:326
+msgid "Caller ID"
+msgstr "Ταυτότητα ΚαλοÏντος"
+
+#: ../modules/callmonitor.module:165
+msgid "Source"
+msgstr "Πηγή"
+
+#: ../modules/callmonitor.module:167
+msgid "Destination"
+msgstr "ΠÏοοÏισμός"
+
+#: ../modules/callmonitor.module:169
+msgid "Context"
+msgstr "ΠεÏιεχόμενο"
+
+#: ../modules/callmonitor.module:171 ../modules/voicemail.module:332
+msgid "Duration"
+msgstr "ΔιάÏκεια"
+
+#: ../modules/callmonitor.module:202
+msgid "Monitor"
+msgstr "ΠαÏακολοÏθηση"
+
+#: ../modules/callmonitor.module:222 ../modules/voicemail.module:373
+msgid "play"
+msgstr "άκουσε"
+
+#: ../modules/callmonitor.module:259
+#, fuzzy, php-format
+msgid "Call Monitor for %s (%s)"
+msgstr "ΠαÏακολοÏθηση Κλήσεων"
+
+#: ../modules/callmonitor.module:311 ../modules/voicemail.module:475
+msgid "select"
+msgstr "επιλογή"
+
+#: ../modules/callmonitor.module:312 ../modules/voicemail.module:476
+msgid "all"
+msgstr "όλα"
+
+#: ../modules/callmonitor.module:313 ../modules/voicemail.module:477
+msgid "none"
+msgstr "κανένα"
+
+#: ../modules/callmonitor.module:533
+msgid "Only deletes recording files, not cdr log"
+msgstr ""
+
+#: ../modules/conference.module:55
+msgid "My Conference room"
+msgstr ""
+
+#: ../modules/conference.module:78
+#, fuzzy, php-format
+msgid "Conference for %s (%s%s)"
+msgstr "Τηλεφωνητής"
+
+#: ../modules/help.module:39 ../modules/help.module:68
+msgid "Help"
+msgstr ""
+
+#: ../modules/help.module:70
+#, fuzzy, php-format
+msgid "Help for %s (%s)"
+msgstr "Ρυθμίσεις για"
+
+#: ../modules/help.module:77
+msgid "Handset Feature Code"
+msgstr ""
+
+#: ../modules/help.module:80
+msgid "Action"
+msgstr ""
+
+#: ../modules/settings.module:61 ../modules/settings.module:667
+msgid "Settings"
+msgstr "Ρυθμίσεις"
+
+#: ../modules/settings.module:125
+msgid "Call forward number not changed"
+msgstr ""
+
+#: ../modules/settings.module:126
+#, php-format
+msgid ""
+"Number %s must contain dial numbers (characters like '(', '-', and ')' are "
+"ok)"
+msgstr ""
+
+#: ../modules/settings.module:151 ../modules/settings.module:156
+#: ../modules/settings.module:161 ../modules/settings.module:166
+#: ../modules/settings.module:176 ../modules/settings.module:181
+msgid "Voicemail password not changed"
+msgstr "Ο κωδικός του τηλεφωνητή δεν άλλαξε"
+
+#: ../modules/settings.module:152
+msgid "Password and password confirm must not be blank"
+msgstr "Ο κωδικός και η επιβεβαίωση ÎºÏ‰Î´Î¹ÎºÎ¿Ï Î´ÎµÎ½ Ï€Ïέπει να είναι κενά"
+
+#: ../modules/settings.module:157
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and greater than %d digits"
+msgstr "Οι κωδικοί Ï€Ïέπει να είναι μόνο 4 αÏιθμοί"
+
+#: ../modules/settings.module:162
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and only %d digits"
+msgstr "Οι κωδικοί Ï€Ïέπει να είναι μόνο 4 αÏιθμοί"
+
+#: ../modules/settings.module:167
+msgid "Password and password confirm do not match"
+msgstr "Ο κωδικός και η επιβεβαίωση ÎºÏ‰Î´Î¹ÎºÎ¿Ï Î´ÎµÎ½ συμφωνοÏν"
+
+#: ../modules/settings.module:177 ../modules/settings.module:182
+#: ../modules/settings.module:234 ../modules/settings.module:239
+#, fuzzy, php-format
+msgid "%s does not exist or is not writable"
+msgstr "Δεν υπάÏχει ή δεν είναι εγγÏάψιμο"
+
+#: ../modules/settings.module:223
+#, fuzzy
+msgid "Voicemail email and pager address not changed"
+msgstr "Ο κωδικός του τηλεφωνητή δεν άλλαξε"
+
+#: ../modules/settings.module:233 ../modules/settings.module:238
+#, fuzzy
+msgid "Voicemail email settings not changed"
+msgstr "Ο κωδικός του τηλεφωνητή δεν άλλαξε"
+
+#: ../modules/settings.module:385
+msgid "Language:"
+msgstr "Γλώσσα:"
+
+#: ../modules/settings.module:408
+#, fuzzy
+msgid "Call Routing"
+msgstr "Ρυθμίσεις ΠαÏακολοÏθησης Κλήσεων"
+
+#: ../modules/settings.module:411
+#, fuzzy
+msgid "Call Forwarding:"
+msgstr "Ρυθμίσεις ΠαÏακολοÏθησης Κλήσεων"
+
+#: ../modules/settings.module:419 ../modules/settings.module:507
+#, fuzzy
+msgid "Enable"
+msgstr "στο πεδίο"
+
+#: ../modules/settings.module:431
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and only %s digits"
+msgstr "Οι κωδικοί Ï€Ïέπει να είναι μόνο 4 αÏιθμοί"
+
+#: ../modules/settings.module:434
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and at least %s digits"
+msgstr "Οι κωδικοί Ï€Ïέπει να είναι μόνο 4 αÏιθμοί"
+
+#: ../modules/settings.module:439
+#, fuzzy
+msgid "Voicemail Password:"
+msgstr "Κωδικός Τηλεφωνητή"
+
+#: ../modules/settings.module:445
+msgid "Enter again to confirm:"
+msgstr "Εισάγετε ξανά για επιβεβαίωση:"
+
+#: ../modules/settings.module:492
+#, fuzzy
+msgid "Email Voicemail To:"
+msgstr "Τηλεφωνητής"
+
+#: ../modules/settings.module:498
+#, fuzzy
+msgid "Pager Voicemail To:"
+msgstr "Τηλεφωνητής"
+
+#: ../modules/settings.module:558
+msgid "Audio Format:"
+msgstr "Ποιότητα Ήχου:"
+
+#: ../modules/settings.module:561
+msgid "Best Quality"
+msgstr "Μέγιστη Ποιότητα"
+
+#: ../modules/settings.module:562
+msgid "Smallest Download"
+msgstr "ΜικÏότεÏο Download"
+
+#: ../modules/settings.module:570
+msgid "Voicemail Settings"
+msgstr "Ρυθμίσεις Τηλεφωνητή"
+
+#: ../modules/settings.module:611
+msgid "Call Monitor Settings"
+msgstr "Ρυθμίσεις ΠαÏακολοÏθησης Κλήσεων"
+
+#: ../modules/settings.module:614
+msgid "Record INCOMING:"
+msgstr "ΗχογÏάφηση ΕΙΣΕΡΧΟΜΕÎΟΥ:"
+
+#: ../modules/settings.module:616 ../modules/settings.module:624
+msgid "Always"
+msgstr "Πάντα"
+
+#: ../modules/settings.module:617 ../modules/settings.module:625
+msgid "Never"
+msgstr "Ποτέ"
+
+#: ../modules/settings.module:618 ../modules/settings.module:626
+msgid "On-Demand"
+msgstr "Επιτόπου"
+
+#: ../modules/settings.module:622
+msgid "Record OUTGOING:"
+msgstr "ΗχογÏάφηση ΕΞΕΡΧΟΜΕÎΟΥ:"
+
+#: ../modules/settings.module:669
+#, fuzzy, php-format
+msgid "Settings for %s (%s)"
+msgstr "Ρυθμίσεις για"
+
+#: ../modules/settings.module:705
+msgid "Update"
+msgstr "Ανανέωση"
+
+#: ../modules/voicemail.module:45
+msgid "Voicemail"
+msgstr "Τηλεφωνητής"
+
+#: ../modules/voicemail.module:164
+msgid "A folder must be selected before the message can be moved."
+msgstr "ΠÏέπει να επιλεχθεί ένας κατάλογος Ï€Ïίν μεταφεÏεθεί το μÏνημα."
+
+#: ../modules/voicemail.module:178
+msgid "An extension must be selected before the message can be forwarded."
+msgstr "ΠÏέπει να επιλεχθεί ΘυÏίδα παÏαλήπτη Ï€Ïίν Ï€Ïοωθηθεί το μÏνημα."
+
+#: ../modules/voicemail.module:304
+msgid "move_to"
+msgstr "μετακίνηση"
+
+#: ../modules/voicemail.module:307
+#, fuzzy
+msgid "Folder"
+msgstr "Κατάλογοι"
+
+#: ../modules/voicemail.module:311
+msgid "forward_to"
+msgstr "Ï€Ïοώθηση"
+
+#: ../modules/voicemail.module:328
+msgid "Priority"
+msgstr "ΠÏοτεÏαιότητα"
+
+#: ../modules/voicemail.module:330
+msgid "Orig Mailbox"
+msgstr "ΑÏχικός Κατάλογος Μυνημάτων"
+
+#: ../modules/voicemail.module:362
+msgid "Message"
+msgstr ""
+
+#: ../modules/voicemail.module:377
+msgid "Voicemail recording(s) was not found."
+msgstr "Δεν βÏέθηκαν εγγÏαφή(ές) στον τηλεφωνητή."
+
+#: ../modules/voicemail.module:378
+#, php-format
+msgid ""
+"On settings page, change voicemail audio format. It is currently set to %s"
+msgstr ""
+
+#: ../modules/voicemail.module:405
+#, fuzzy
+msgid "Voicemail Login not found."
+msgstr "Δεν βÏέθηκε Ï€Ïόσβαση για θυÏίδα μυνημάτων"
+
+#: ../modules/voicemail.module:406
+msgid "No access to voicemail"
+msgstr "Καμία Ï€Ïόσβαση στον τηλεφωνητή"
+
+#: ../modules/voicemail.module:412
+msgid "No Voicemail Recordings for Admin"
+msgstr "Δεν ΥπάÏχουν ΕγγÏαφές Μυνημάτων για τον ΔιαχειÏιστή"
+
+#: ../modules/voicemail.module:428
+#, fuzzy, php-format
+msgid "Voicemail for %s (%s)"
+msgstr "Τηλεφωνητής"
+
+#: ../modules/voicemail.module:678
+#, fuzzy, php-format
+msgid "Could not create mailbox folder %s on the server"
+msgstr "ΑδÏνατη η δημιουÏγία καταλόγου μυνημάτων"
+
+#: ../modules/voicemail.module:718
+#, php-format
+msgid "Permission denied on folder %s or %s"
+msgstr ""
+
+#: ../misc/recording_popup.php:39
+msgid "download"
+msgstr "κατέβασμα"
+
+#~ msgid "Passwords must be all numbers and only 4 digits"
+#~ msgstr "Οι κωδικοί Ï€Ïέπει να είναι μόνο 4 αÏιθμοί"
+
+#~ msgid "Folders"
+#~ msgstr "Κατάλογοι"
+
+#~ msgid "Login used"
+#~ msgstr "Όνομα χÏήστη που χÏησιμοποιήθηκε"
+
+#, fuzzy
+#~ msgid "No Asterisk Manager Interface connection"
+#~ msgstr "Ο διαχειÏιστής κλήσεων Asterisk δεν αποκÏίνεται"
+
+#~ msgid "not a directory or not readable"
+#~ msgstr "δεν είναι κατάλογος ή δεν είναι αναγνώσιμος"
+
+#~ msgid "of"
+#~ msgstr "από"
+
+#~ msgid "Use your"
+#~ msgstr "ΧÏησιμοποίησε την δικιά σου"
+
+#~ msgid "for"
+#~ msgstr "για"
+
+#~ msgid "Password must be all numbers and 4 digits"
+#~ msgstr "Ο κωδικός Ï€Ïέπει να έιναι 4 αÏιθμοί"
+
+#~ msgid "Check voicemail audio format on settings page to change from"
+#~ msgstr ""
+#~ "Ελέγχτε το audio format του μυνήματος στην σελίδα Ïυθμίσεων για αλλαγή"
+
+#~ msgid "on the server"
+#~ msgstr "στον server"
+
+#~ msgid "No database connection"
+#~ msgstr "Δεν υπάÏχει σÏνδεση με την βάση δεδομένων"
diff --git a/fs_selfservice/fri/locale/es_ES/LC_MESSAGES/ari.mo b/fs_selfservice/fri/locale/es_ES/LC_MESSAGES/ari.mo
new file mode 100644
index 000000000..e0fbdd961
--- /dev/null
+++ b/fs_selfservice/fri/locale/es_ES/LC_MESSAGES/ari.mo
Binary files differ
diff --git a/fs_selfservice/fri/locale/es_ES/LC_MESSAGES/ari.po b/fs_selfservice/fri/locale/es_ES/LC_MESSAGES/ari.po
new file mode 100644
index 000000000..0518573d0
--- /dev/null
+++ b/fs_selfservice/fri/locale/es_ES/LC_MESSAGES/ari.po
@@ -0,0 +1,616 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# Grupo Ikusnet, Antonio F. Cano <antonio@igestec.com>, 2006.
+# Grupo Ikusnet, Agustin Vericat <agustin@igestec.com>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-05-03 08:32-0400\n"
+"PO-Revision-Date: 2006-03-31 13:00\n"
+"Last-Translator: Antonio F. Cano <antonio@igestec.com>\n"
+"Language-Team: Espanol <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../includes/asi.php:46
+msgid "Asterisk Call Manager not responding"
+msgstr "La Centralita no responde"
+
+#: ../includes/asi.php:54
+msgid "Asterisk authentication failed:"
+msgstr "Fallo la Autenticacion con la Centralita"
+
+#: ../includes/asi.php:96 ../includes/asi.php:111
+msgid "Asterisk command not understood"
+msgstr "La recarga no funcino"
+
+#: ../includes/bootstrap.php:123
+#, php-format
+msgid "To many directories in %s Not all files processed"
+msgstr "Demasiados directorios en %s, notodos los archivos han sido procesados"
+
+#: ../includes/bootstrap.php:226
+#, fuzzy
+msgid "ARI requires a version of PHP 4.3 or later"
+msgstr "Necesita una versi&oacute; de PHP 4.0 o superior"
+
+#: ../includes/bootstrap.php:245
+msgid ""
+"PHP PEAR must be installed. Visit http://pear.php.net for help with "
+"installation."
+msgstr ""
+"PHP PEAR debe estar instalado. Visite http://pear.php.net para obtener ayuda"
+
+#: ../includes/common.php:173
+msgid "ARI does not appear to have access to the Asterisk Manager."
+msgstr "No es posible conectar con la Centralita"
+
+#: ../includes/common.php:174
+#, fuzzy
+msgid ""
+"Check the ARI 'main.conf.php' configuration file to set the Asterisk Manager "
+"Account."
+msgstr ""
+"Compruebe el archivo 'main.conf' para configuar la conexi&oacute;n con "
+"Asterisk Manager"
+
+#: ../includes/common.php:175
+msgid "Check /etc/asterisk/manager.conf for a proper Asterisk Manager Account"
+msgstr ""
+"Compruebe /etc/asterisk/manager.conf para crear una cuenta Asterisk Manager"
+
+#: ../includes/common.php:176
+msgid ""
+"make sure [general] enabled = yes and a 'permit=' line for localhost or the "
+"webserver."
+msgstr ""
+
+#: ../includes/common.php:193 ../includes/common.php:208
+msgid "Check AMP installation, asterisk, and ARI main.conf"
+msgstr "Compruebe la instalacion de FreePBX, DDBB o ARI en main.conf"
+
+#: ../includes/common.php:344
+msgid "Logout"
+msgstr "Salir"
+
+#: ../includes/common.php:349
+msgid "Page Not Found."
+msgstr "Pagina No encontrada"
+
+#: ../includes/display.php:92
+msgid "Search"
+msgstr "Buscar"
+
+#: ../includes/display.php:135
+msgid "Searched for"
+msgstr "Buscado para"
+
+#: ../includes/display.php:139
+#, fuzzy, php-format
+msgid "Results %d - %d of %d"
+msgstr "Resultados %d de %d"
+
+#: ../includes/display.php:141
+#, php-format
+msgid "Results %d"
+msgstr "Resultados %d"
+
+#: ../includes/display.php:195
+msgid "First"
+msgstr "Primero"
+
+#: ../includes/display.php:208
+msgid "Last"
+msgstr "Ultimo"
+
+#: ../includes/login.php:267
+msgid "Incorrect Password"
+msgstr "Contrase&ntilde;a Incorrecta"
+
+#: ../includes/login.php:279
+msgid "Incorrect Username or Password"
+msgstr "Contrase&ntilde; Incorrecta"
+
+#: ../includes/login.php:402 ../includes/login.php:411
+msgid "Login"
+msgstr "Usuario"
+
+#: ../includes/login.php:419
+msgid "Password"
+msgstr "Contrase&ntilde;a"
+
+#: ../includes/login.php:428
+msgid "Submit"
+msgstr "Enviar"
+
+#: ../includes/login.php:436
+msgid "Remember Password"
+msgstr "Recordar Contrase&ntilde;a"
+
+#: ../includes/login.php:451
+msgid "Use your <b>Voicemail Mailbox and Password</b>"
+msgstr "Use su Buz&oacute;n de Voz (Usuario) y contrase&ntilde;a"
+
+#: ../includes/login.php:452
+msgid "This is the same password used for the phone"
+msgstr "Esta es es la misma contrase&ntilde;a usada para el telefono"
+
+#: ../includes/login.php:454
+msgid ""
+"For password maintenance or assistance, contact your Phone System "
+"Administrator."
+msgstr ""
+"Para mantenimiento de contrase&ntilde;as o asistencia, pongase en contacto "
+"con el Administrador."
+
+#: ../includes/main.conf.php:152
+msgid "INBOX"
+msgstr "Entrada"
+
+#: ../includes/main.conf.php:154
+msgid "Family"
+msgstr "Familiares"
+
+#: ../includes/main.conf.php:156
+msgid "Friends"
+msgstr "Amigos"
+
+#: ../includes/main.conf.php:158
+msgid "Old"
+msgstr "Antiguos"
+
+#: ../includes/main.conf.php:160
+msgid "Work"
+msgstr "Trabajo"
+
+#: ../includes/main.conf.php:229
+msgid "Directory"
+msgstr "Directorio"
+
+#: ../includes/main.conf.php:230
+msgid "Echo Test"
+msgstr "Test Eco"
+
+#: ../includes/main.conf.php:231 ../modules/callmonitor.module:161
+#: ../modules/voicemail.module:324
+msgid "Time"
+msgstr "Hora"
+
+#: ../includes/main.conf.php:232
+msgid "Weather"
+msgstr "Tiempo"
+
+#: ../includes/main.conf.php:233
+msgid "Schedule wakeup call"
+msgstr "Programar llamada despertador"
+
+#: ../includes/main.conf.php:234
+msgid "festival test (your extension is XXX)"
+msgstr "Test festival tts (su extension es XXX)"
+
+#: ../includes/main.conf.php:235
+msgid "Activate Call Waiting (deactivated by default)"
+msgstr "Activar Llamada en Espera (Desactivada por defecto)"
+
+#: ../includes/main.conf.php:236
+msgid "Deactivate Call Waiting"
+msgstr "Desactivar Llamada en Espera"
+
+#: ../includes/main.conf.php:237
+msgid "Call Forwarding System"
+msgstr "Desv&iacute;o de llamada"
+
+#: ../includes/main.conf.php:238
+msgid "Disable Call Forwarding"
+msgstr "Desactivar el Desv&iacute;o de Llamada"
+
+#: ../includes/main.conf.php:239
+msgid "IVR Recording"
+msgstr "Grabaciones"
+
+#: ../includes/main.conf.php:240
+msgid "Enable Do-Not-Disturb"
+msgstr "Activar No-Molestar"
+
+#: ../includes/main.conf.php:241
+msgid "Disable Do-Not-Disturb"
+msgstr "Desactivar No-Molestar"
+
+#: ../includes/main.conf.php:242
+msgid "Call Forward on Busy"
+msgstr "Desv&iacute;o de llamada cuando est&eacute; Ocupado"
+
+#: ../includes/main.conf.php:243
+msgid "Disable Call Forward on Busy"
+msgstr "Desactivar el Desv&iacute;o de llamada cuando est&eacute; Ocupado"
+
+#: ../includes/main.conf.php:244
+#, fuzzy
+msgid "Message Center (does not ask for extension)"
+msgstr "Centro de Mensajes (no pregunta la extens&iacute;n)"
+
+#: ../includes/main.conf.php:245
+msgid "Enter Message Center"
+msgstr "Entrar en el Centro de Mensajes"
+
+#: ../includes/main.conf.php:246
+msgid "Playback IVR Recording"
+msgstr "Escuchar la grabaci&oacute;n realizada"
+
+#: ../includes/main.conf.php:247
+msgid "Test Fax"
+msgstr "Probar Fax"
+
+#: ../includes/main.conf.php:248
+msgid "Simulate incoming call"
+msgstr "Simular una llamada entrante"
+
+#: ../includes/main.conf.php:289
+msgid "Email voicemail as attachment"
+msgstr "Adjuntar el mensaje de voz en el correo electr&oacute;nico"
+
+#: ../includes/main.conf.php:290
+msgid "Say caller id in recording emailed"
+msgstr ""
+"Indica el CallerID en la grabaci&oacute;n enviada por correo electr&oacute;"
+"nico"
+
+#: ../includes/main.conf.php:291
+msgid "Say envelop (date/time) in recording emailed"
+msgstr ""
+"Indica la etiqueta (tiempo/hora) en la grabaci&oacute;n enviada por correo "
+"electr&oacute;nico"
+
+#: ../includes/main.conf.php:292
+msgid "Delete voicemail when emailed"
+msgstr ""
+"Eliminar el mensaje de voz una vez enviado por correo electr&oacute;nico"
+
+#: ../includes/main.conf.php:293
+msgid "Play next message after deleting current message"
+msgstr "Reproducir el siguiente mensaje una vez eliminado el actual"
+
+#: ../includes/main.conf.php:294
+msgid "Ask caller to review their voicemail before sending"
+msgstr ""
+
+#: ../includes/main.conf.php:295
+msgid "Maximum time in seconds a voicemail will record"
+msgstr ""
+
+#: ../modules/callmonitor.module:37 ../modules/callmonitor.module:257
+msgid "Call Monitor"
+msgstr "Registro de Llamadas"
+
+#: ../modules/callmonitor.module:132
+#, php-format
+msgid "Path is not a directory: %s"
+msgstr "La ruta no es un directorio: %s"
+
+#: ../modules/callmonitor.module:141 ../modules/voicemail.module:301
+msgid "delete"
+msgstr "Eliminar"
+
+#: ../modules/callmonitor.module:147
+msgid "duration"
+msgstr "Duraci&oacute;n"
+
+#: ../modules/callmonitor.module:150
+msgid "ignore"
+msgstr "ninguno"
+
+#: ../modules/callmonitor.module:159 ../modules/voicemail.module:322
+msgid "Date"
+msgstr "Fecha"
+
+#: ../modules/callmonitor.module:163 ../modules/voicemail.module:326
+msgid "Caller ID"
+msgstr "Caller ID"
+
+#: ../modules/callmonitor.module:165
+msgid "Source"
+msgstr "Origen"
+
+#: ../modules/callmonitor.module:167
+msgid "Destination"
+msgstr "Destino"
+
+#: ../modules/callmonitor.module:169
+msgid "Context"
+msgstr "Contexto"
+
+#: ../modules/callmonitor.module:171 ../modules/voicemail.module:332
+msgid "Duration"
+msgstr "Duraci&oacute;n"
+
+#: ../modules/callmonitor.module:202
+msgid "Monitor"
+msgstr "Monitor para"
+
+#: ../modules/callmonitor.module:222 ../modules/voicemail.module:373
+msgid "play"
+msgstr "escuchar"
+
+#: ../modules/callmonitor.module:259
+#, php-format
+msgid "Call Monitor for %s (%s)"
+msgstr "Registro de Llamadas de %s (%s)"
+
+#: ../modules/callmonitor.module:311 ../modules/voicemail.module:475
+msgid "select"
+msgstr "Selecionar"
+
+#: ../modules/callmonitor.module:312 ../modules/voicemail.module:476
+msgid "all"
+msgstr "todos"
+
+#: ../modules/callmonitor.module:313 ../modules/voicemail.module:477
+msgid "none"
+msgstr "ninguno"
+
+#: ../modules/callmonitor.module:533
+msgid "Only deletes recording files, not cdr log"
+msgstr "Solo elimina los archivos grabados, no el log en el CDR"
+
+#: ../modules/conference.module:55
+msgid "My Conference room"
+msgstr ""
+
+#: ../modules/conference.module:78
+#, fuzzy, php-format
+msgid "Conference for %s (%s%s)"
+msgstr "Buz&oacute;n de Voz de %s (%s)"
+
+#: ../modules/help.module:39 ../modules/help.module:68
+msgid "Help"
+msgstr "Ayuda"
+
+#: ../modules/help.module:70
+#, php-format
+msgid "Help for %s (%s)"
+msgstr "Ayuda para %s (%s)"
+
+#: ../modules/help.module:77
+msgid "Handset Feature Code"
+msgstr "Teclas de Marcaci&oacute;n"
+
+#: ../modules/help.module:80
+msgid "Action"
+msgstr "Acci&oacute;n"
+
+#: ../modules/settings.module:61 ../modules/settings.module:667
+msgid "Settings"
+msgstr "Opciones"
+
+#: ../modules/settings.module:125
+msgid "Call forward number not changed"
+msgstr "El n&uacute;mero del desv&iacute;o no ha cambiado"
+
+#: ../modules/settings.module:126
+#, php-format
+msgid ""
+"Number %s must contain dial numbers (characters like '(', '-', and ')' are "
+"ok)"
+msgstr ""
+"El n&uacute;mero %s debe contener n&uacte;meros marcables (caracteres como "
+"'(', '-', y ')' son v&aacute;lidos)"
+
+#: ../modules/settings.module:151 ../modules/settings.module:156
+#: ../modules/settings.module:161 ../modules/settings.module:166
+#: ../modules/settings.module:176 ../modules/settings.module:181
+msgid "Voicemail password not changed"
+msgstr "La Contrase&ntilde;a del Buz&oacute;n de Voz no ha cambiado"
+
+#: ../modules/settings.module:152
+msgid "Password and password confirm must not be blank"
+msgstr ""
+"Contrase&ntilde;a y la confirmacion de esta no deben de estar en blanco"
+
+#: ../modules/settings.module:157
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and greater than %d digits"
+msgstr "Contrase&ntilde;a ha de ser numerica y de longitud %d digitos"
+
+#: ../modules/settings.module:162
+#, php-format
+msgid "Passwords must be all numbers and only %d digits"
+msgstr "Contrase&ntilde;a ha de ser numerica y de longitud %d digitos"
+
+#: ../modules/settings.module:167
+msgid "Password and password confirm do not match"
+msgstr "Contrase&ntilde;a y conformacion no corresponden"
+
+#: ../modules/settings.module:177 ../modules/settings.module:182
+#: ../modules/settings.module:234 ../modules/settings.module:239
+#, php-format
+msgid "%s does not exist or is not writable"
+msgstr "%s No existe o no se puede escribir"
+
+#: ../modules/settings.module:223
+msgid "Voicemail email and pager address not changed"
+msgstr "La Contrase&ntilde;a del Buz&oacute;n de Voz no ha cambiado"
+
+#: ../modules/settings.module:233 ../modules/settings.module:238
+msgid "Voicemail email settings not changed"
+msgstr "La Contrase&ntilde;a del Buz&oacute;n de Voz no ha cambiado"
+
+#: ../modules/settings.module:385
+msgid "Language:"
+msgstr "Idioma:"
+
+#: ../modules/settings.module:408
+msgid "Call Routing"
+msgstr "Enrutado de llamadas"
+
+#: ../modules/settings.module:411
+msgid "Call Forwarding:"
+msgstr "Desviar llamadas a:"
+
+#: ../modules/settings.module:419 ../modules/settings.module:507
+msgid "Enable"
+msgstr "Activar"
+
+#: ../modules/settings.module:431
+#, php-format
+msgid "Passwords must be all numbers and only %s digits"
+msgstr "Contrase&ntilde;a ha de ser numerica y de longitud %s digitos"
+
+#: ../modules/settings.module:434
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and at least %s digits"
+msgstr "Contrase&ntilde;a ha de ser numerica y de longitud %s digitos"
+
+#: ../modules/settings.module:439
+msgid "Voicemail Password:"
+msgstr "Contrase&ntilde;a del Buz&oacute;n de Voz"
+
+#: ../modules/settings.module:445
+msgid "Enter again to confirm:"
+msgstr "Introduzca otra vez para confirmar:"
+
+#: ../modules/settings.module:492
+msgid "Email Voicemail To:"
+msgstr "Buz&oacute;n de Voz para"
+
+#: ../modules/settings.module:498
+msgid "Pager Voicemail To:"
+msgstr "Buz&oacute;n de Voz para"
+
+#: ../modules/settings.module:558
+msgid "Audio Format:"
+msgstr "Formato del Audio:"
+
+#: ../modules/settings.module:561
+msgid "Best Quality"
+msgstr "Mejor Calidad"
+
+#: ../modules/settings.module:562
+msgid "Smallest Download"
+msgstr "Descarga rapida"
+
+#: ../modules/settings.module:570
+msgid "Voicemail Settings"
+msgstr "Propiedades del Buz&oacute;n de Voz"
+
+#: ../modules/settings.module:611
+msgid "Call Monitor Settings"
+msgstr "Propiedades del Registro de Llamadas"
+
+#: ../modules/settings.module:614
+msgid "Record INCOMING:"
+msgstr "Grabaciones Entrantes:"
+
+#: ../modules/settings.module:616 ../modules/settings.module:624
+msgid "Always"
+msgstr "Siempre"
+
+#: ../modules/settings.module:617 ../modules/settings.module:625
+msgid "Never"
+msgstr "Nunca"
+
+#: ../modules/settings.module:618 ../modules/settings.module:626
+msgid "On-Demand"
+msgstr "Bajo demanda"
+
+#: ../modules/settings.module:622
+msgid "Record OUTGOING:"
+msgstr "Grabaciones Salientes:"
+
+#: ../modules/settings.module:669
+#, php-format
+msgid "Settings for %s (%s)"
+msgstr "Ajustes para %s (%s)"
+
+#: ../modules/settings.module:705
+msgid "Update"
+msgstr "Actualizar"
+
+#: ../modules/voicemail.module:45
+msgid "Voicemail"
+msgstr "Buz&oacute;n de Voz"
+
+#: ../modules/voicemail.module:164
+msgid "A folder must be selected before the message can be moved."
+msgstr "Debe elegir primero una carpeta antes de mover el mensaje."
+
+#: ../modules/voicemail.module:178
+msgid "An extension must be selected before the message can be forwarded."
+msgstr "Debe de seleccionar una extension antes de reenviar el mensaje"
+
+#: ../modules/voicemail.module:304
+msgid "move_to"
+msgstr "Mover a"
+
+#: ../modules/voicemail.module:307
+msgid "Folder"
+msgstr "Carpetas"
+
+#: ../modules/voicemail.module:311
+msgid "forward_to"
+msgstr "Enviar a"
+
+#: ../modules/voicemail.module:328
+msgid "Priority"
+msgstr "Prioridad"
+
+#: ../modules/voicemail.module:330
+msgid "Orig Mailbox"
+msgstr "Buz&oacute;n de Voz Orig"
+
+#: ../modules/voicemail.module:362
+msgid "Message"
+msgstr "Mensaje"
+
+#: ../modules/voicemail.module:377
+msgid "Voicemail recording(s) was not found."
+msgstr "No se ha encontrado grabaciones en el Buz&oacute;n de Voz."
+
+#: ../modules/voicemail.module:378
+#, php-format
+msgid ""
+"On settings page, change voicemail audio format. It is currently set to %s"
+msgstr ""
+
+#: ../modules/voicemail.module:405
+msgid "Voicemail Login not found."
+msgstr ""
+"No se encontro el usuario del Buz&oacute;n de Voz, se usa el usuario de la "
+"extension"
+
+#: ../modules/voicemail.module:406
+msgid "No access to voicemail"
+msgstr "No tiene permiso para acceder al Buz&oacute;n de Voz"
+
+#: ../modules/voicemail.module:412
+msgid "No Voicemail Recordings for Admin"
+msgstr "No hay grabaciones en el Buz&oacute;n de Voz de Admin"
+
+#: ../modules/voicemail.module:428
+#, php-format
+msgid "Voicemail for %s (%s)"
+msgstr "Buz&oacute;n de Voz de %s (%s)"
+
+#: ../modules/voicemail.module:678
+#, php-format
+msgid "Could not create mailbox folder %s on the server"
+msgstr "No puedo crear la carpeta %s en el buz&oacute;n de voz"
+
+#: ../modules/voicemail.module:718
+#, php-format
+msgid "Permission denied on folder %s or %s"
+msgstr "Permiso denegado en el directorio %s o %s"
+
+#: ../misc/recording_popup.php:39
+msgid "download"
+msgstr "Descargar"
+
+#~ msgid "Settings for"
+#~ msgstr "Configuracion de"
+
+#~ msgid "Folders"
+#~ msgstr "Carpetas"
diff --git a/fs_selfservice/fri/locale/fr_FR/LC_MESSAGES/ari.mo b/fs_selfservice/fri/locale/fr_FR/LC_MESSAGES/ari.mo
new file mode 100644
index 000000000..78d4733ad
--- /dev/null
+++ b/fs_selfservice/fri/locale/fr_FR/LC_MESSAGES/ari.mo
Binary files differ
diff --git a/fs_selfservice/fri/locale/fr_FR/LC_MESSAGES/ari.po b/fs_selfservice/fri/locale/fr_FR/LC_MESSAGES/ari.po
new file mode 100644
index 000000000..7f15c7ac8
--- /dev/null
+++ b/fs_selfservice/fri/locale/fr_FR/LC_MESSAGES/ari.po
@@ -0,0 +1,635 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <jbp@phileas-com.net>, 15/11/2005.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: 1.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-05-03 08:32-0400\n"
+"PO-Revision-Date: 2006-04-29 11:30+0100\n"
+"Last-Translator: Xavier Ourcière <xourciere@propolys.com>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../includes/asi.php:46
+msgid "Asterisk Call Manager not responding"
+msgstr "Asterisk Call Manager ne répond pas"
+
+#: ../includes/asi.php:54
+msgid "Asterisk authentication failed:"
+msgstr "Authentification Asterisk échoue :"
+
+#: ../includes/asi.php:96 ../includes/asi.php:111
+msgid "Asterisk command not understood"
+msgstr "Asterisk: commande non comprise"
+
+#: ../includes/bootstrap.php:123
+#, php-format
+msgid "To many directories in %s Not all files processed"
+msgstr ""
+
+#: ../includes/bootstrap.php:226
+msgid "ARI requires a version of PHP 4.3 or later"
+msgstr ""
+
+#: ../includes/bootstrap.php:245
+msgid ""
+"PHP PEAR must be installed. Visit http://pear.php.net for help with "
+"installation."
+msgstr ""
+
+#: ../includes/common.php:173
+msgid "ARI does not appear to have access to the Asterisk Manager."
+msgstr "Connexion impossible à Asterisk Manager"
+
+#: ../includes/common.php:174
+msgid ""
+"Check the ARI 'main.conf.php' configuration file to set the Asterisk Manager "
+"Account."
+msgstr ""
+
+#: ../includes/common.php:175
+msgid "Check /etc/asterisk/manager.conf for a proper Asterisk Manager Account"
+msgstr ""
+
+#: ../includes/common.php:176
+msgid ""
+"make sure [general] enabled = yes and a 'permit=' line for localhost or the "
+"webserver."
+msgstr ""
+
+#: ../includes/common.php:193 ../includes/common.php:208
+msgid "Check AMP installation, asterisk, and ARI main.conf"
+msgstr ""
+"Vérifiez l'installation d'AMP, de Asterisk, ou le fichier ARI main.conf"
+
+#: ../includes/common.php:344
+msgid "Logout"
+msgstr "Déconexion"
+
+#: ../includes/common.php:349
+msgid "Page Not Found."
+msgstr "Fichier introuvable"
+
+#: ../includes/display.php:92
+msgid "Search"
+msgstr "Rechercher"
+
+#: ../includes/display.php:135
+msgid "Searched for"
+msgstr "Rechercher pour"
+
+#: ../includes/display.php:139
+#, php-format
+msgid "Results %d - %d of %d"
+msgstr "Résultats %d à %s sur %d"
+
+#: ../includes/display.php:141
+#, php-format
+msgid "Results %d"
+msgstr "Résultats %d"
+
+#: ../includes/display.php:195
+msgid "First"
+msgstr "Premier"
+
+#: ../includes/display.php:208
+msgid "Last"
+msgstr "Dernier"
+
+#: ../includes/login.php:267
+msgid "Incorrect Password"
+msgstr "Mot de Passe eronné"
+
+#: ../includes/login.php:279
+msgid "Incorrect Username or Password"
+msgstr "Login ou Mot de Passe erroné"
+
+#: ../includes/login.php:402 ../includes/login.php:411
+msgid "Login"
+msgstr "Authentification"
+
+#: ../includes/login.php:419
+msgid "Password"
+msgstr "Mot de Passe"
+
+#: ../includes/login.php:428
+msgid "Submit"
+msgstr "Valider"
+
+#: ../includes/login.php:436
+msgid "Remember Password"
+msgstr "Se souvenir du mot de passe"
+
+#: ../includes/login.php:451
+msgid "Use your <b>Voicemail Mailbox and Password</b>"
+msgstr "Utilisez votre <b>numéro de la boîte vocale et votre mot de passe</b>"
+
+#: ../includes/login.php:452
+msgid "This is the same password used for the phone"
+msgstr "C'est le même Mot de Passe que sur le téléphone"
+
+#: ../includes/login.php:454
+msgid ""
+"For password maintenance or assistance, contact your Phone System "
+"Administrator."
+msgstr "Pour de l'assistance contactez votre administrateur de téléphonie."
+
+#: ../includes/main.conf.php:152
+msgid "INBOX"
+msgstr "NOUVEAUX"
+
+#: ../includes/main.conf.php:154
+msgid "Family"
+msgstr "Famille"
+
+#: ../includes/main.conf.php:156
+msgid "Friends"
+msgstr "Amis"
+
+#: ../includes/main.conf.php:158
+msgid "Old"
+msgstr "Anciens"
+
+#: ../includes/main.conf.php:160
+msgid "Work"
+msgstr "Travail"
+
+#: ../includes/main.conf.php:229
+msgid "Directory"
+msgstr "Annuaire local"
+
+#: ../includes/main.conf.php:230
+msgid "Echo Test"
+msgstr "Test d'echo"
+
+#: ../includes/main.conf.php:231 ../modules/callmonitor.module:161
+#: ../modules/voicemail.module:324
+msgid "Time"
+msgstr "Heure"
+
+#: ../includes/main.conf.php:232
+msgid "Weather"
+msgstr "Météo"
+
+#: ../includes/main.conf.php:233
+msgid "Schedule wakeup call"
+msgstr "Programmation de réveil"
+
+#: ../includes/main.conf.php:234
+msgid "festival test (your extension is XXX)"
+msgstr "test de festival (votre numéro de téléphone est le XXXX)"
+
+#: ../includes/main.conf.php:235
+msgid "Activate Call Waiting (deactivated by default)"
+msgstr ""
+
+#: ../includes/main.conf.php:236
+msgid "Deactivate Call Waiting"
+msgstr ""
+
+#: ../includes/main.conf.php:237
+msgid "Call Forwarding System"
+msgstr ""
+
+#: ../includes/main.conf.php:238
+msgid "Disable Call Forwarding"
+msgstr ""
+
+#: ../includes/main.conf.php:239
+#, fuzzy
+msgid "IVR Recording"
+msgstr "Enregistrement"
+
+#: ../includes/main.conf.php:240
+msgid "Enable Do-Not-Disturb"
+msgstr "Active ne pas déranger"
+
+#: ../includes/main.conf.php:241
+msgid "Disable Do-Not-Disturb"
+msgstr "Désactive ne pas déranger"
+
+#: ../includes/main.conf.php:242
+msgid "Call Forward on Busy"
+msgstr ""
+
+#: ../includes/main.conf.php:243
+msgid "Disable Call Forward on Busy"
+msgstr ""
+
+#: ../includes/main.conf.php:244
+#, fuzzy
+msgid "Message Center (does not ask for extension)"
+msgstr "Boite vocale personnelle"
+
+#: ../includes/main.conf.php:245
+msgid "Enter Message Center"
+msgstr "Centre de messageries"
+
+#: ../includes/main.conf.php:246
+msgid "Playback IVR Recording"
+msgstr ""
+
+#: ../includes/main.conf.php:247
+msgid "Test Fax"
+msgstr ""
+
+#: ../includes/main.conf.php:248
+msgid "Simulate incoming call"
+msgstr "Simulation d'appel entrant"
+
+#: ../includes/main.conf.php:289
+msgid "Email voicemail as attachment"
+msgstr ""
+
+#: ../includes/main.conf.php:290
+msgid "Say caller id in recording emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:291
+msgid "Say envelop (date/time) in recording emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:292
+msgid "Delete voicemail when emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:293
+msgid "Play next message after deleting current message"
+msgstr ""
+
+#: ../includes/main.conf.php:294
+msgid "Ask caller to review their voicemail before sending"
+msgstr ""
+
+#: ../includes/main.conf.php:295
+msgid "Maximum time in seconds a voicemail will record"
+msgstr ""
+
+#: ../modules/callmonitor.module:37 ../modules/callmonitor.module:257
+msgid "Call Monitor"
+msgstr "Journal d'Appels"
+
+#: ../modules/callmonitor.module:132
+#, php-format
+msgid "Path is not a directory: %s"
+msgstr ""
+
+#: ../modules/callmonitor.module:141 ../modules/voicemail.module:301
+msgid "delete"
+msgstr "Supprimer"
+
+#: ../modules/callmonitor.module:147
+msgid "duration"
+msgstr "Durée supérieure à"
+
+#: ../modules/callmonitor.module:150
+msgid "ignore"
+msgstr "Filtrer"
+
+#: ../modules/callmonitor.module:159 ../modules/voicemail.module:322
+msgid "Date"
+msgstr "Date"
+
+#: ../modules/callmonitor.module:163 ../modules/voicemail.module:326
+msgid "Caller ID"
+msgstr "ID Appelant"
+
+#: ../modules/callmonitor.module:165
+msgid "Source"
+msgstr ""
+
+#: ../modules/callmonitor.module:167
+msgid "Destination"
+msgstr ""
+
+#: ../modules/callmonitor.module:169
+msgid "Context"
+msgstr "Contexte"
+
+#: ../modules/callmonitor.module:171 ../modules/voicemail.module:332
+msgid "Duration"
+msgstr "Durée"
+
+#: ../modules/callmonitor.module:202
+msgid "Monitor"
+msgstr "Enregistrement"
+
+#: ../modules/callmonitor.module:222 ../modules/voicemail.module:373
+msgid "play"
+msgstr "Ecouter"
+
+#: ../modules/callmonitor.module:259
+#, php-format
+msgid "Call Monitor for %s (%s)"
+msgstr "Journal d'Appels de %s (%s)"
+
+#: ../modules/callmonitor.module:311 ../modules/voicemail.module:475
+msgid "select"
+msgstr "Sélection"
+
+#: ../modules/callmonitor.module:312 ../modules/voicemail.module:476
+msgid "all"
+msgstr "Tous"
+
+#: ../modules/callmonitor.module:313 ../modules/voicemail.module:477
+msgid "none"
+msgstr "Aucun"
+
+#: ../modules/callmonitor.module:533
+msgid "Only deletes recording files, not cdr log"
+msgstr "Supprime seulement les fichiers des enregistrements mais pas les CDRs"
+
+#: ../modules/conference.module:55
+msgid "My Conference room"
+msgstr ""
+
+#: ../modules/conference.module:78
+#, fuzzy, php-format
+msgid "Conference for %s (%s%s)"
+msgstr "Boîte Vocale de %s (%s)"
+
+#: ../modules/help.module:39 ../modules/help.module:68
+msgid "Help"
+msgstr "Aide"
+
+#: ../modules/help.module:70
+#, php-format
+msgid "Help for %s (%s)"
+msgstr "Aide: %s (%s)"
+
+#: ../modules/help.module:77
+msgid "Handset Feature Code"
+msgstr ""
+
+#: ../modules/help.module:80
+msgid "Action"
+msgstr ""
+
+#: ../modules/settings.module:61 ../modules/settings.module:667
+msgid "Settings"
+msgstr "Paramètres"
+
+#: ../modules/settings.module:125
+msgid "Call forward number not changed"
+msgstr ""
+
+#: ../modules/settings.module:126
+#, php-format
+msgid ""
+"Number %s must contain dial numbers (characters like '(', '-', and ')' are "
+"ok)"
+msgstr ""
+
+#: ../modules/settings.module:151 ../modules/settings.module:156
+#: ../modules/settings.module:161 ../modules/settings.module:166
+#: ../modules/settings.module:176 ../modules/settings.module:181
+msgid "Voicemail password not changed"
+msgstr "Mot de passe de boite vocale non changé"
+
+#: ../modules/settings.module:152
+msgid "Password and password confirm must not be blank"
+msgstr "Le mot de passe et sa confirmation ne peuvent pas être vides"
+
+#: ../modules/settings.module:157
+#, php-format
+msgid "Passwords must be all numbers and greater than %d digits"
+msgstr ""
+"Le mot de passe doit comporter uniquement des chiffres et doit avoir une "
+"longueur supérieure à %d"
+
+#: ../modules/settings.module:162
+#, php-format
+msgid "Passwords must be all numbers and only %d digits"
+msgstr ""
+"Le mot de passe doit comporter uniquement des chiffres et doit avoir une "
+"longueur de %d"
+
+#: ../modules/settings.module:167
+msgid "Password and password confirm do not match"
+msgstr ""
+
+#: ../modules/settings.module:177 ../modules/settings.module:182
+#: ../modules/settings.module:234 ../modules/settings.module:239
+#, php-format
+msgid "%s does not exist or is not writable"
+msgstr "%s n'existe pas ou n'a pas l'autorisation en écriture"
+
+#: ../modules/settings.module:223
+msgid "Voicemail email and pager address not changed"
+msgstr "Email voicemail et adresse de pager inchangés"
+
+#: ../modules/settings.module:233 ../modules/settings.module:238
+msgid "Voicemail email settings not changed"
+msgstr "Paramètres de la boite vocale inchangés"
+
+#: ../modules/settings.module:385
+msgid "Language:"
+msgstr "Langue"
+
+#: ../modules/settings.module:408
+msgid "Call Routing"
+msgstr "Routage d'appels"
+
+#: ../modules/settings.module:411
+msgid "Call Forwarding:"
+msgstr "Transfert vers:"
+
+#: ../modules/settings.module:419 ../modules/settings.module:507
+msgid "Enable"
+msgstr "Activer"
+
+#: ../modules/settings.module:431
+#, php-format
+msgid "Passwords must be all numbers and only %s digits"
+msgstr ""
+"Le mot de passe doit comporter uniquement des chiffres et seulement 4 "
+"chiffres"
+
+#: ../modules/settings.module:434
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and at least %s digits"
+msgstr ""
+"Le mot de passe doit comporter uniquement des chiffres et seulement 4 "
+"chiffres"
+
+#: ../modules/settings.module:439
+msgid "Voicemail Password:"
+msgstr "Mot de passe de la boîte vocale"
+
+#: ../modules/settings.module:445
+msgid "Enter again to confirm:"
+msgstr "Repetez le mot de passe:"
+
+#: ../modules/settings.module:492
+msgid "Email Voicemail To:"
+msgstr "Adresse émail pour le Voicemail:"
+
+#: ../modules/settings.module:498
+msgid "Pager Voicemail To:"
+msgstr ""
+
+#: ../modules/settings.module:558
+msgid "Audio Format:"
+msgstr "Format audio:"
+
+#: ../modules/settings.module:561
+msgid "Best Quality"
+msgstr "Meilleure Qualité"
+
+#: ../modules/settings.module:562
+msgid "Smallest Download"
+msgstr "Taille réduite"
+
+#: ../modules/settings.module:570
+msgid "Voicemail Settings"
+msgstr "Paramètres boîte vocale"
+
+#: ../modules/settings.module:611
+msgid "Call Monitor Settings"
+msgstr "Enregistrements d'appels"
+
+#: ../modules/settings.module:614
+msgid "Record INCOMING:"
+msgstr "Enregistrements ENTRANTS"
+
+#: ../modules/settings.module:616 ../modules/settings.module:624
+msgid "Always"
+msgstr "Toujours"
+
+#: ../modules/settings.module:617 ../modules/settings.module:625
+msgid "Never"
+msgstr "Jamais"
+
+#: ../modules/settings.module:618 ../modules/settings.module:626
+msgid "On-Demand"
+msgstr "Sur demande"
+
+#: ../modules/settings.module:622
+msgid "Record OUTGOING:"
+msgstr "Enregistrements SORTANTS"
+
+#: ../modules/settings.module:669
+#, php-format
+msgid "Settings for %s (%s)"
+msgstr "Paramètres de %s (%s)"
+
+#: ../modules/settings.module:705
+msgid "Update"
+msgstr "Mettre à jour"
+
+#: ../modules/voicemail.module:45
+msgid "Voicemail"
+msgstr "Boîte Vocale"
+
+#: ../modules/voicemail.module:164
+msgid "A folder must be selected before the message can be moved."
+msgstr "Sélection un dossier avant de déplacer le message."
+
+#: ../modules/voicemail.module:178
+msgid "An extension must be selected before the message can be forwarded."
+msgstr "Sélectionnez d'abord une extension pour le transfert du message."
+
+#: ../modules/voicemail.module:304
+msgid "move_to"
+msgstr "Déplacer vers"
+
+#: ../modules/voicemail.module:307
+msgid "Folder"
+msgstr "Dossier"
+
+#: ../modules/voicemail.module:311
+msgid "forward_to"
+msgstr "Transmettre à"
+
+#: ../modules/voicemail.module:328
+msgid "Priority"
+msgstr "Priorité"
+
+#: ../modules/voicemail.module:330
+msgid "Orig Mailbox"
+msgstr "Boîte Source"
+
+#: ../modules/voicemail.module:362
+msgid "Message"
+msgstr ""
+
+#: ../modules/voicemail.module:377
+msgid "Voicemail recording(s) was not found."
+msgstr "Enregistrement audio non trouvé"
+
+#: ../modules/voicemail.module:378
+#, php-format
+msgid ""
+"On settings page, change voicemail audio format. It is currently set to %s"
+msgstr ""
+
+#: ../modules/voicemail.module:405
+#, fuzzy
+msgid "Voicemail Login not found."
+msgstr "Enregistrement audio non trouvé"
+
+#: ../modules/voicemail.module:406
+msgid "No access to voicemail"
+msgstr "Aucun accès à la boîte vocale"
+
+#: ../modules/voicemail.module:412
+msgid "No Voicemail Recordings for Admin"
+msgstr "Pas d'enregistrement pour Admin"
+
+#: ../modules/voicemail.module:428
+#, php-format
+msgid "Voicemail for %s (%s)"
+msgstr "Boîte Vocale de %s (%s)"
+
+#: ../modules/voicemail.module:678
+#, php-format
+msgid "Could not create mailbox folder %s on the server"
+msgstr "N'a pas pu créer le dossier %s"
+
+#: ../modules/voicemail.module:718
+#, php-format
+msgid "Permission denied on folder %s or %s"
+msgstr ""
+
+#: ../misc/recording_popup.php:39
+msgid "download"
+msgstr ""
+
+#~ msgid "Passwords must be all numbers and only 4 digits"
+#~ msgstr ""
+#~ "Le mot de passe doit comporter que des chiffres et 4 chiffres maximum"
+
+#, fuzzy
+#~ msgid "No Asterisk Manager Interface connection"
+#~ msgstr "Asterisk Call Manager ne répond pas"
+
+#~ msgid "not a directory or not readable"
+#~ msgstr "pas un répertoire ou non lisible"
+
+#~ msgid "of"
+#~ msgstr "de"
+
+#~ msgid "Use your"
+#~ msgstr "Utilisez votre"
+
+#~ msgid "Password must be all numbers and 4 digits"
+#~ msgstr ""
+#~ "Le mot de passe doit comporter que des chiffres et 4 chiffres maximum"
+
+#~ msgid "Check voicemail audio format on settings page to change from"
+#~ msgstr "Vérifiez le format audio à la page paramètres"
+
+#~ msgid "on the server"
+#~ msgstr "sur le serveur"
+
+#~ msgid "No database connection"
+#~ msgstr "Pas de connexion à la base de données"
+
+#~ msgid "Format Audio:"
+#~ msgstr "Format Audio :"
diff --git a/fs_selfservice/fri/locale/he_IL/LC_MESSAGES/ari.mo b/fs_selfservice/fri/locale/he_IL/LC_MESSAGES/ari.mo
new file mode 100644
index 000000000..3b00bd1f3
--- /dev/null
+++ b/fs_selfservice/fri/locale/he_IL/LC_MESSAGES/ari.mo
Binary files differ
diff --git a/fs_selfservice/fri/locale/he_IL/LC_MESSAGES/ari.po b/fs_selfservice/fri/locale/he_IL/LC_MESSAGES/ari.po
new file mode 100644
index 000000000..7c9ae9768
--- /dev/null
+++ b/fs_selfservice/fri/locale/he_IL/LC_MESSAGES/ari.po
@@ -0,0 +1,646 @@
+# translation of ari-he.po to Hebrew
+# This file is distributed under the same license as the PACKAGE package.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER.
+# Diego Iastrubni <diego.iastrubni@xorcom.com>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ari-he\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-05-03 08:32-0400\n"
+"PO-Revision-Date: 2006-02-05 11:48+0200\n"
+"Last-Translator: Diego Iastrubni <diego.iastrubni@xorcom.com>\n"
+"Language-Team: Hebrew <xorcom-users@xorcom.com>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.9.1\n"
+
+#: ../includes/asi.php:46
+msgid "Asterisk Call Manager not responding"
+msgstr "מנהל השיחות של Asterisk ×œ× ×ž×’×™×‘"
+
+#: ../includes/asi.php:54
+msgid "Asterisk authentication failed:"
+msgstr "×”×ימות מול Asterisk נכשל:"
+
+#: ../includes/asi.php:96 ../includes/asi.php:111
+#, fuzzy
+msgid "Asterisk command not understood"
+msgstr "פקודת reload של Asterisk ×œ× ×ž×•×‘× ×ª"
+
+#: ../includes/bootstrap.php:123
+#, php-format
+msgid "To many directories in %s Not all files processed"
+msgstr ""
+
+#: ../includes/bootstrap.php:226
+msgid "ARI requires a version of PHP 4.3 or later"
+msgstr ""
+
+#: ../includes/bootstrap.php:245
+msgid ""
+"PHP PEAR must be installed. Visit http://pear.php.net for help with "
+"installation."
+msgstr ""
+
+#: ../includes/common.php:173
+#, fuzzy
+msgid "ARI does not appear to have access to the Asterisk Manager."
+msgstr "×ין ×פשרות להתחבר למנהל של Asterisk"
+
+#: ../includes/common.php:174
+msgid ""
+"Check the ARI 'main.conf.php' configuration file to set the Asterisk Manager "
+"Account."
+msgstr ""
+
+#: ../includes/common.php:175
+msgid "Check /etc/asterisk/manager.conf for a proper Asterisk Manager Account"
+msgstr ""
+
+#: ../includes/common.php:176
+msgid ""
+"make sure [general] enabled = yes and a 'permit=' line for localhost or the "
+"webserver."
+msgstr ""
+
+#: ../includes/common.php:193 ../includes/common.php:208
+#, fuzzy
+msgid "Check AMP installation, asterisk, and ARI main.conf"
+msgstr ""
+"בדוק ×ת ההתקנה של AMP, בסיס ×”× ×ª×•× ×™× ×©×œ asterisk ×ו הקובץ main.conf של ARI"
+
+#: ../includes/common.php:344
+msgid "Logout"
+msgstr "יצי××”"
+
+#: ../includes/common.php:349
+msgid "Page Not Found."
+msgstr "דף ×œ× × ×ž×¦×"
+
+#: ../includes/display.php:92
+msgid "Search"
+msgstr "חפש"
+
+#: ../includes/display.php:135
+msgid "Searched for"
+msgstr "חיפוש של"
+
+#: ../includes/display.php:139
+#, fuzzy, php-format
+msgid "Results %d - %d of %d"
+msgstr "תוצ×ות"
+
+#: ../includes/display.php:141
+#, fuzzy, php-format
+msgid "Results %d"
+msgstr "תוצ×ות"
+
+#: ../includes/display.php:195
+msgid "First"
+msgstr "ר×שון"
+
+#: ../includes/display.php:208
+msgid "Last"
+msgstr "×חרון"
+
+#: ../includes/login.php:267
+msgid "Incorrect Password"
+msgstr "ססמה ×œ× × ×›×•× ×”"
+
+#: ../includes/login.php:279
+msgid "Incorrect Username or Password"
+msgstr "×©× ×ž×©×ª×ž×© ×œ× × ×›×•×Ÿ ×ו ססמה ×œ× × ×›×•× ×”"
+
+#: ../includes/login.php:402 ../includes/login.php:411
+msgid "Login"
+msgstr "×©× ×ž×©×ª×ž×©"
+
+#: ../includes/login.php:419
+msgid "Password"
+msgstr "ססמה"
+
+#: ../includes/login.php:428
+msgid "Submit"
+msgstr "שלח"
+
+#: ../includes/login.php:436
+msgid "Remember Password"
+msgstr "זכור ססמה"
+
+#: ../includes/login.php:451
+#, fuzzy
+msgid "Use your <b>Voicemail Mailbox and Password</b>"
+msgstr "תיבה קולית וססמה"
+
+#: ../includes/login.php:452
+msgid "This is the same password used for the phone"
+msgstr "זוהי ×ותה ססמה שבשימוש בטלפון שלך"
+
+#: ../includes/login.php:454
+msgid ""
+"For password maintenance or assistance, contact your Phone System "
+"Administrator."
+msgstr "עבור ססמה התחזוקה, ×× × ×¤× ×” ×ל מנהל הטלפוניה שלך."
+
+#: ../includes/main.conf.php:152
+msgid "INBOX"
+msgstr "נכנסות"
+
+#: ../includes/main.conf.php:154
+msgid "Family"
+msgstr "משפחה"
+
+#: ../includes/main.conf.php:156
+msgid "Friends"
+msgstr "חברי×"
+
+#: ../includes/main.conf.php:158
+msgid "Old"
+msgstr "ישני×"
+
+#: ../includes/main.conf.php:160
+msgid "Work"
+msgstr "עבודה"
+
+#: ../includes/main.conf.php:229
+msgid "Directory"
+msgstr ""
+
+#: ../includes/main.conf.php:230
+msgid "Echo Test"
+msgstr ""
+
+#: ../includes/main.conf.php:231 ../modules/callmonitor.module:161
+#: ../modules/voicemail.module:324
+msgid "Time"
+msgstr "שעה"
+
+#: ../includes/main.conf.php:232
+msgid "Weather"
+msgstr ""
+
+#: ../includes/main.conf.php:233
+msgid "Schedule wakeup call"
+msgstr ""
+
+#: ../includes/main.conf.php:234
+msgid "festival test (your extension is XXX)"
+msgstr ""
+
+#: ../includes/main.conf.php:235
+msgid "Activate Call Waiting (deactivated by default)"
+msgstr ""
+
+#: ../includes/main.conf.php:236
+msgid "Deactivate Call Waiting"
+msgstr ""
+
+#: ../includes/main.conf.php:237
+msgid "Call Forwarding System"
+msgstr ""
+
+#: ../includes/main.conf.php:238
+msgid "Disable Call Forwarding"
+msgstr ""
+
+#: ../includes/main.conf.php:239
+#, fuzzy
+msgid "IVR Recording"
+msgstr "הקלטות"
+
+#: ../includes/main.conf.php:240
+msgid "Enable Do-Not-Disturb"
+msgstr ""
+
+#: ../includes/main.conf.php:241
+msgid "Disable Do-Not-Disturb"
+msgstr ""
+
+#: ../includes/main.conf.php:242
+msgid "Call Forward on Busy"
+msgstr ""
+
+#: ../includes/main.conf.php:243
+msgid "Disable Call Forward on Busy"
+msgstr ""
+
+#: ../includes/main.conf.php:244
+msgid "Message Center (does not ask for extension)"
+msgstr ""
+
+#: ../includes/main.conf.php:245
+msgid "Enter Message Center"
+msgstr ""
+
+#: ../includes/main.conf.php:246
+msgid "Playback IVR Recording"
+msgstr ""
+
+#: ../includes/main.conf.php:247
+msgid "Test Fax"
+msgstr ""
+
+#: ../includes/main.conf.php:248
+msgid "Simulate incoming call"
+msgstr ""
+
+#: ../includes/main.conf.php:289
+msgid "Email voicemail as attachment"
+msgstr ""
+
+#: ../includes/main.conf.php:290
+msgid "Say caller id in recording emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:291
+msgid "Say envelop (date/time) in recording emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:292
+msgid "Delete voicemail when emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:293
+msgid "Play next message after deleting current message"
+msgstr ""
+
+#: ../includes/main.conf.php:294
+msgid "Ask caller to review their voicemail before sending"
+msgstr ""
+
+#: ../includes/main.conf.php:295
+msgid "Maximum time in seconds a voicemail will record"
+msgstr ""
+
+#: ../modules/callmonitor.module:37 ../modules/callmonitor.module:257
+msgid "Call Monitor"
+msgstr "צג שיחות"
+
+#: ../modules/callmonitor.module:132
+#, php-format
+msgid "Path is not a directory: %s"
+msgstr ""
+
+#: ../modules/callmonitor.module:141 ../modules/voicemail.module:301
+#, fuzzy
+msgid "delete"
+msgstr "בחר"
+
+#: ../modules/callmonitor.module:147
+#, fuzzy
+msgid "duration"
+msgstr "משך"
+
+#: ../modules/callmonitor.module:150
+#, fuzzy
+msgid "ignore"
+msgstr "כלו×"
+
+#: ../modules/callmonitor.module:159 ../modules/voicemail.module:322
+msgid "Date"
+msgstr "ת×ריך"
+
+#: ../modules/callmonitor.module:163 ../modules/voicemail.module:326
+msgid "Caller ID"
+msgstr "שיחה מזוהה"
+
+#: ../modules/callmonitor.module:165
+msgid "Source"
+msgstr "מקור"
+
+#: ../modules/callmonitor.module:167
+msgid "Destination"
+msgstr "יעד"
+
+#: ../modules/callmonitor.module:169
+msgid "Context"
+msgstr "הקשר"
+
+#: ../modules/callmonitor.module:171 ../modules/voicemail.module:332
+msgid "Duration"
+msgstr "משך"
+
+#: ../modules/callmonitor.module:202
+msgid "Monitor"
+msgstr "ניטור"
+
+#: ../modules/callmonitor.module:222 ../modules/voicemail.module:373
+msgid "play"
+msgstr "נגן"
+
+#: ../modules/callmonitor.module:259
+#, fuzzy, php-format
+msgid "Call Monitor for %s (%s)"
+msgstr "צג שיחות"
+
+#: ../modules/callmonitor.module:311 ../modules/voicemail.module:475
+msgid "select"
+msgstr "בחר"
+
+#: ../modules/callmonitor.module:312 ../modules/voicemail.module:476
+msgid "all"
+msgstr "הכל"
+
+#: ../modules/callmonitor.module:313 ../modules/voicemail.module:477
+msgid "none"
+msgstr "כלו×"
+
+#: ../modules/callmonitor.module:533
+msgid "Only deletes recording files, not cdr log"
+msgstr "מחק הקלטות בלבד, ×œ× ×ת ×¨×™×©×•× ×”Ö¾cdr"
+
+#: ../modules/conference.module:55
+msgid "My Conference room"
+msgstr ""
+
+#: ../modules/conference.module:78
+#, fuzzy, php-format
+msgid "Conference for %s (%s%s)"
+msgstr "תיבה קולית"
+
+#: ../modules/help.module:39 ../modules/help.module:68
+msgid "Help"
+msgstr ""
+
+#: ../modules/help.module:70
+#, fuzzy, php-format
+msgid "Help for %s (%s)"
+msgstr "הגדרות עבור"
+
+#: ../modules/help.module:77
+msgid "Handset Feature Code"
+msgstr ""
+
+#: ../modules/help.module:80
+msgid "Action"
+msgstr ""
+
+#: ../modules/settings.module:61 ../modules/settings.module:667
+msgid "Settings"
+msgstr "הגדרות"
+
+#: ../modules/settings.module:125
+msgid "Call forward number not changed"
+msgstr ""
+
+#: ../modules/settings.module:126
+#, php-format
+msgid ""
+"Number %s must contain dial numbers (characters like '(', '-', and ')' are "
+"ok)"
+msgstr ""
+
+#: ../modules/settings.module:151 ../modules/settings.module:156
+#: ../modules/settings.module:161 ../modules/settings.module:166
+#: ../modules/settings.module:176 ../modules/settings.module:181
+msgid "Voicemail password not changed"
+msgstr "ססמת התיבה הקולית ×œ× ×©×•× ×ª×”"
+
+#: ../modules/settings.module:152
+msgid "Password and password confirm must not be blank"
+msgstr "הסממה וה×ימות של הססמה ×œ× ×™×›×•×œ×™× ×œ×”×™×•×ª רקי×"
+
+#: ../modules/settings.module:157
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and greater than %d digits"
+msgstr "הסממ×ות חייבת להכיל 4 ספרות בלבד"
+
+#: ../modules/settings.module:162
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and only %d digits"
+msgstr "הסממ×ות חייבת להכיל 4 ספרות בלבד"
+
+#: ../modules/settings.module:167
+msgid "Password and password confirm do not match"
+msgstr "הסממה וה×ימות של הססמה ×œ× ×ª×•×מי×"
+
+#: ../modules/settings.module:177 ../modules/settings.module:182
+#: ../modules/settings.module:234 ../modules/settings.module:239
+#, fuzzy, php-format
+msgid "%s does not exist or is not writable"
+msgstr "×œ× ×§×™×™× ×ו ×ין ×פשרות לכתוב עליו"
+
+#: ../modules/settings.module:223
+#, fuzzy
+msgid "Voicemail email and pager address not changed"
+msgstr "ססמת התיבה הקולית ×œ× ×©×•× ×ª×”"
+
+#: ../modules/settings.module:233 ../modules/settings.module:238
+#, fuzzy
+msgid "Voicemail email settings not changed"
+msgstr "ססמת התיבה הקולית ×œ× ×©×•× ×ª×”"
+
+#: ../modules/settings.module:385
+msgid "Language:"
+msgstr "שפה:"
+
+#: ../modules/settings.module:408
+#, fuzzy
+msgid "Call Routing"
+msgstr "הגדרות ניתור שיחות"
+
+#: ../modules/settings.module:411
+#, fuzzy
+msgid "Call Forwarding:"
+msgstr "הגדרות ניתור שיחות"
+
+#: ../modules/settings.module:419 ../modules/settings.module:507
+#, fuzzy
+msgid "Enable"
+msgstr "בטבלה"
+
+#: ../modules/settings.module:431
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and only %s digits"
+msgstr "הסממ×ות חייבת להכיל 4 ספרות בלבד"
+
+#: ../modules/settings.module:434
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and at least %s digits"
+msgstr "הסממ×ות חייבת להכיל 4 ספרות בלבד"
+
+#: ../modules/settings.module:439
+#, fuzzy
+msgid "Voicemail Password:"
+msgstr "ססמת תיבה קולית:"
+
+#: ../modules/settings.module:445
+msgid "Enter again to confirm:"
+msgstr "הכנס שוב ל×ימות:"
+
+#: ../modules/settings.module:492
+#, fuzzy
+msgid "Email Voicemail To:"
+msgstr "תיבה קולית"
+
+#: ../modules/settings.module:498
+#, fuzzy
+msgid "Pager Voicemail To:"
+msgstr "תיבה קולית"
+
+#: ../modules/settings.module:558
+msgid "Audio Format:"
+msgstr "תבנית שמע:"
+
+#: ../modules/settings.module:561
+msgid "Best Quality"
+msgstr "×יכות ×”×›×™ טובה"
+
+#: ../modules/settings.module:562
+msgid "Smallest Download"
+msgstr "הורדה הכי קטנה"
+
+#: ../modules/settings.module:570
+msgid "Voicemail Settings"
+msgstr "הגדרות תיבה קולית"
+
+#: ../modules/settings.module:611
+msgid "Call Monitor Settings"
+msgstr "הגדרות ניתור שיחות"
+
+#: ../modules/settings.module:614
+msgid "Record INCOMING:"
+msgstr "הקלטת שיחות נכנסות:"
+
+#: ../modules/settings.module:616 ../modules/settings.module:624
+msgid "Always"
+msgstr "תמיד"
+
+#: ../modules/settings.module:617 ../modules/settings.module:625
+msgid "Never"
+msgstr "××£ פע×"
+
+#: ../modules/settings.module:618 ../modules/settings.module:626
+msgid "On-Demand"
+msgstr "לפי דרישה"
+
+#: ../modules/settings.module:622
+msgid "Record OUTGOING:"
+msgstr "הקלטה שיחות יוצ×ות:"
+
+#: ../modules/settings.module:669
+#, fuzzy, php-format
+msgid "Settings for %s (%s)"
+msgstr "הגדרות עבור"
+
+#: ../modules/settings.module:705
+msgid "Update"
+msgstr "עדכן"
+
+#: ../modules/voicemail.module:45
+msgid "Voicemail"
+msgstr "תיבה קולית"
+
+#: ../modules/voicemail.module:164
+msgid "A folder must be selected before the message can be moved."
+msgstr "יש לבחור תיקייה לפני ש×פשר להעביר ×ת ההודעה."
+
+#: ../modules/voicemail.module:178
+msgid "An extension must be selected before the message can be forwarded."
+msgstr "יש לבחור שלוחה לפני ש×פשר העביר ×ת השיחה הל××”."
+
+#: ../modules/voicemail.module:304
+msgid "move_to"
+msgstr ""
+
+#: ../modules/voicemail.module:307
+msgid "Folder"
+msgstr "תיקייה"
+
+#: ../modules/voicemail.module:311
+msgid "forward_to"
+msgstr ""
+
+#: ../modules/voicemail.module:328
+msgid "Priority"
+msgstr "עדיפות"
+
+#: ../modules/voicemail.module:330
+msgid "Orig Mailbox"
+msgstr "תיבת דו×ר מקורית"
+
+#: ../modules/voicemail.module:362
+msgid "Message"
+msgstr ""
+
+#: ../modules/voicemail.module:377
+msgid "Voicemail recording(s) was not found."
+msgstr "הקלטת תיבה קולית ×œ× × ×ž×¦××”."
+
+#: ../modules/voicemail.module:378
+#, php-format
+msgid ""
+"On settings page, change voicemail audio format. It is currently set to %s"
+msgstr ""
+
+#: ../modules/voicemail.module:405
+#, fuzzy
+msgid "Voicemail Login not found."
+msgstr "×©× ×”×ž×©×ª×ž×© של תיבת הקול"
+
+#: ../modules/voicemail.module:406
+msgid "No access to voicemail"
+msgstr "×ין גישה לתיבת הקול"
+
+#: ../modules/voicemail.module:412
+msgid "No Voicemail Recordings for Admin"
+msgstr "×ין הקלטות בתיבת הקול של המנהל"
+
+#: ../modules/voicemail.module:428
+#, fuzzy, php-format
+msgid "Voicemail for %s (%s)"
+msgstr "תיבה קולית"
+
+#: ../modules/voicemail.module:678
+#, fuzzy, php-format
+msgid "Could not create mailbox folder %s on the server"
+msgstr "×ין ×פשרות ליצור ×ת תיקיית הדו×ר"
+
+#: ../modules/voicemail.module:718
+#, fuzzy, php-format
+msgid "Permission denied on folder %s or %s"
+msgstr "הגישה נדחתה בתיקייה"
+
+#: ../misc/recording_popup.php:39
+msgid "download"
+msgstr "הורדה"
+
+#~ msgid "Passwords must be all numbers and only 4 digits"
+#~ msgstr "הסממ×ות חייבת להכיל 4 ספרות בלבד"
+
+#~ msgid "Folders"
+#~ msgstr "תיקיות"
+
+#~ msgid "Login used"
+#~ msgstr "×©× ×”×©×ž×©×ª×©"
+
+#, fuzzy
+#~ msgid "No Asterisk Manager Interface connection"
+#~ msgstr "מנהל השיחות של Asterisk ×œ× ×ž×’×™×‘"
+
+#~ msgid "not a directory or not readable"
+#~ msgstr "×œ× ×¡×¤×¨×™×™×”, ×ו ×ין ×פשרות לקר×"
+
+#~ msgid "of"
+#~ msgstr "של "
+
+#~ msgid "Use your"
+#~ msgstr "השתמש בשלך"
+
+#~ msgid "for"
+#~ msgstr "עבור"
+
+#~ msgid "Password must be all numbers and 4 digits"
+#~ msgstr "הסממה חייבת להכיל 4 ספרות בלבד"
+
+#, fuzzy
+#~ msgid "Check voicemail audio format on settings page to change from"
+#~ msgstr "בחר ×ת תבנית השמע של התיבה הקולית בחלון ההגדרות "
+
+#~ msgid "on the server"
+#~ msgstr "ברשת"
+
+#~ msgid "No database connection"
+#~ msgstr "×ין חיבור לבסיס נתוני×"
diff --git a/fs_selfservice/fri/locale/hu_HU/LC_MESSAGES/ari.mo b/fs_selfservice/fri/locale/hu_HU/LC_MESSAGES/ari.mo
new file mode 100644
index 000000000..ff5a92220
--- /dev/null
+++ b/fs_selfservice/fri/locale/hu_HU/LC_MESSAGES/ari.mo
Binary files differ
diff --git a/fs_selfservice/fri/locale/hu_HU/LC_MESSAGES/ari.po b/fs_selfservice/fri/locale/hu_HU/LC_MESSAGES/ari.po
new file mode 100644
index 000000000..c9d9e44c0
--- /dev/null
+++ b/fs_selfservice/fri/locale/hu_HU/LC_MESSAGES/ari.po
@@ -0,0 +1,645 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-05-03 08:32-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: Varasdy Imre <csvarasdy@softpbx.hu>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../includes/asi.php:46
+msgid "Asterisk Call Manager not responding"
+msgstr "Asterisk Call Manager nem válaszol"
+
+#: ../includes/asi.php:54
+msgid "Asterisk authentication failed:"
+msgstr "Asterisk bejelentkezés elutasítva:"
+
+#: ../includes/asi.php:96 ../includes/asi.php:111
+#, fuzzy
+msgid "Asterisk command not understood"
+msgstr "Asterisk frissítés parancs ismeretlen"
+
+#: ../includes/bootstrap.php:123
+#, php-format
+msgid "To many directories in %s Not all files processed"
+msgstr ""
+
+#: ../includes/bootstrap.php:226
+msgid "ARI requires a version of PHP 4.3 or later"
+msgstr ""
+
+#: ../includes/bootstrap.php:245
+msgid ""
+"PHP PEAR must be installed. Visit http://pear.php.net for help with "
+"installation."
+msgstr ""
+
+#: ../includes/common.php:173
+#, fuzzy
+msgid "ARI does not appear to have access to the Asterisk Manager."
+msgstr "Nem tudok csatlakozni az Asterisk Managerhez"
+
+#: ../includes/common.php:174
+msgid ""
+"Check the ARI 'main.conf.php' configuration file to set the Asterisk Manager "
+"Account."
+msgstr ""
+
+#: ../includes/common.php:175
+msgid "Check /etc/asterisk/manager.conf for a proper Asterisk Manager Account"
+msgstr ""
+
+#: ../includes/common.php:176
+msgid ""
+"make sure [general] enabled = yes and a 'permit=' line for localhost or the "
+"webserver."
+msgstr ""
+
+#: ../includes/common.php:193 ../includes/common.php:208
+#, fuzzy
+msgid "Check AMP installation, asterisk, and ARI main.conf"
+msgstr ""
+"Ellen&otilde;rizze az AMP telepítést, asterisk adatbázist, vagy az ARI main."
+"conf filet"
+
+#: ../includes/common.php:344
+msgid "Logout"
+msgstr "Kilépés"
+
+#: ../includes/common.php:349
+msgid "Page Not Found."
+msgstr "Nincs ilyen oldal."
+
+#: ../includes/display.php:92
+msgid "Search"
+msgstr "Keres"
+
+#: ../includes/display.php:135
+msgid "Searched for"
+msgstr "Keresés"
+
+#: ../includes/display.php:139
+#, fuzzy, php-format
+msgid "Results %d - %d of %d"
+msgstr "Eredmény"
+
+#: ../includes/display.php:141
+#, fuzzy, php-format
+msgid "Results %d"
+msgstr "Eredmény"
+
+#: ../includes/display.php:195
+msgid "First"
+msgstr "Els&otilde;"
+
+#: ../includes/display.php:208
+msgid "Last"
+msgstr "Utolsó"
+
+#: ../includes/login.php:267
+msgid "Incorrect Password"
+msgstr "Hibás jelszó"
+
+#: ../includes/login.php:279
+msgid "Incorrect Username or Password"
+msgstr "Rossz Felhasználonév vagy jelszó"
+
+#: ../includes/login.php:402 ../includes/login.php:411
+msgid "Login"
+msgstr "Azonosító"
+
+#: ../includes/login.php:419
+msgid "Password"
+msgstr "Jelszó"
+
+#: ../includes/login.php:428
+msgid "Submit"
+msgstr "Rögzít"
+
+#: ../includes/login.php:436
+msgid "Remember Password"
+msgstr "Jelszó megjegyzése"
+
+#: ../includes/login.php:451
+#, fuzzy
+msgid "Use your <b>Voicemail Mailbox and Password</b>"
+msgstr "Hangposta és Jelszó"
+
+#: ../includes/login.php:452
+msgid "This is the same password used for the phone"
+msgstr "A jelszó ugyanaz, mint a telefonhoz"
+
+#: ../includes/login.php:454
+msgid ""
+"For password maintenance or assistance, contact your Phone System "
+"Administrator."
+msgstr ""
+"Om du har problem med lösenord eller behöver hjälp ska du kontakta din vÃ"
+"¤xel ansvarig"
+
+#: ../includes/main.conf.php:152
+msgid "INBOX"
+msgstr "Bejövõ"
+
+#: ../includes/main.conf.php:154
+msgid "Family"
+msgstr "Család"
+
+#: ../includes/main.conf.php:156
+msgid "Friends"
+msgstr "Barátok"
+
+#: ../includes/main.conf.php:158
+msgid "Old"
+msgstr "Régi"
+
+#: ../includes/main.conf.php:160
+msgid "Work"
+msgstr "Munka"
+
+#: ../includes/main.conf.php:229
+msgid "Directory"
+msgstr ""
+
+#: ../includes/main.conf.php:230
+msgid "Echo Test"
+msgstr ""
+
+#: ../includes/main.conf.php:231 ../modules/callmonitor.module:161
+#: ../modules/voicemail.module:324
+msgid "Time"
+msgstr "Idõ"
+
+#: ../includes/main.conf.php:232
+msgid "Weather"
+msgstr ""
+
+#: ../includes/main.conf.php:233
+msgid "Schedule wakeup call"
+msgstr ""
+
+#: ../includes/main.conf.php:234
+msgid "festival test (your extension is XXX)"
+msgstr ""
+
+#: ../includes/main.conf.php:235
+msgid "Activate Call Waiting (deactivated by default)"
+msgstr ""
+
+#: ../includes/main.conf.php:236
+msgid "Deactivate Call Waiting"
+msgstr ""
+
+#: ../includes/main.conf.php:237
+msgid "Call Forwarding System"
+msgstr ""
+
+#: ../includes/main.conf.php:238
+msgid "Disable Call Forwarding"
+msgstr ""
+
+#: ../includes/main.conf.php:239
+#, fuzzy
+msgid "IVR Recording"
+msgstr "Felvétel"
+
+#: ../includes/main.conf.php:240
+msgid "Enable Do-Not-Disturb"
+msgstr ""
+
+#: ../includes/main.conf.php:241
+msgid "Disable Do-Not-Disturb"
+msgstr ""
+
+#: ../includes/main.conf.php:242
+msgid "Call Forward on Busy"
+msgstr ""
+
+#: ../includes/main.conf.php:243
+msgid "Disable Call Forward on Busy"
+msgstr ""
+
+#: ../includes/main.conf.php:244
+msgid "Message Center (does not ask for extension)"
+msgstr ""
+
+#: ../includes/main.conf.php:245
+msgid "Enter Message Center"
+msgstr ""
+
+#: ../includes/main.conf.php:246
+msgid "Playback IVR Recording"
+msgstr ""
+
+#: ../includes/main.conf.php:247
+msgid "Test Fax"
+msgstr ""
+
+#: ../includes/main.conf.php:248
+msgid "Simulate incoming call"
+msgstr ""
+
+#: ../includes/main.conf.php:289
+msgid "Email voicemail as attachment"
+msgstr ""
+
+#: ../includes/main.conf.php:290
+msgid "Say caller id in recording emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:291
+msgid "Say envelop (date/time) in recording emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:292
+msgid "Delete voicemail when emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:293
+msgid "Play next message after deleting current message"
+msgstr ""
+
+#: ../includes/main.conf.php:294
+msgid "Ask caller to review their voicemail before sending"
+msgstr ""
+
+#: ../includes/main.conf.php:295
+msgid "Maximum time in seconds a voicemail will record"
+msgstr ""
+
+#: ../modules/callmonitor.module:37 ../modules/callmonitor.module:257
+msgid "Call Monitor"
+msgstr "Hangrögzítés"
+
+#: ../modules/callmonitor.module:132
+#, php-format
+msgid "Path is not a directory: %s"
+msgstr ""
+
+#: ../modules/callmonitor.module:141 ../modules/voicemail.module:301
+msgid "delete"
+msgstr "Töröl"
+
+#: ../modules/callmonitor.module:147
+#, fuzzy
+msgid "duration"
+msgstr "Hossz"
+
+#: ../modules/callmonitor.module:150
+#, fuzzy
+msgid "ignore"
+msgstr "semmi"
+
+#: ../modules/callmonitor.module:159 ../modules/voicemail.module:322
+msgid "Date"
+msgstr "Dátum"
+
+#: ../modules/callmonitor.module:163 ../modules/voicemail.module:326
+msgid "Caller ID"
+msgstr "Hivószám"
+
+#: ../modules/callmonitor.module:165
+msgid "Source"
+msgstr "Hívó"
+
+#: ../modules/callmonitor.module:167
+msgid "Destination"
+msgstr "Hívott"
+
+#: ../modules/callmonitor.module:169
+msgid "Context"
+msgstr "Csoport"
+
+#: ../modules/callmonitor.module:171 ../modules/voicemail.module:332
+msgid "Duration"
+msgstr "Hossz"
+
+#: ../modules/callmonitor.module:202
+msgid "Monitor"
+msgstr "Rögzítés"
+
+#: ../modules/callmonitor.module:222 ../modules/voicemail.module:373
+msgid "play"
+msgstr "Lejátszás"
+
+#: ../modules/callmonitor.module:259
+#, fuzzy, php-format
+msgid "Call Monitor for %s (%s)"
+msgstr "Hangrögzítés"
+
+#: ../modules/callmonitor.module:311 ../modules/voicemail.module:475
+msgid "select"
+msgstr "Választ"
+
+#: ../modules/callmonitor.module:312 ../modules/voicemail.module:476
+msgid "all"
+msgstr "Mind"
+
+#: ../modules/callmonitor.module:313 ../modules/voicemail.module:477
+msgid "none"
+msgstr "semmi"
+
+#: ../modules/callmonitor.module:533
+msgid "Only deletes recording files, not cdr log"
+msgstr "Csak a hangfileokat törli, a CDR-t nem"
+
+#: ../modules/conference.module:55
+msgid "My Conference room"
+msgstr ""
+
+#: ../modules/conference.module:78
+#, fuzzy, php-format
+msgid "Conference for %s (%s%s)"
+msgstr "Hangposta"
+
+#: ../modules/help.module:39 ../modules/help.module:68
+msgid "Help"
+msgstr ""
+
+#: ../modules/help.module:70
+#, fuzzy, php-format
+msgid "Help for %s (%s)"
+msgstr "Beállítások"
+
+#: ../modules/help.module:77
+msgid "Handset Feature Code"
+msgstr ""
+
+#: ../modules/help.module:80
+msgid "Action"
+msgstr ""
+
+#: ../modules/settings.module:61 ../modules/settings.module:667
+msgid "Settings"
+msgstr "Beállítások"
+
+#: ../modules/settings.module:125
+msgid "Call forward number not changed"
+msgstr ""
+
+#: ../modules/settings.module:126
+#, php-format
+msgid ""
+"Number %s must contain dial numbers (characters like '(', '-', and ')' are "
+"ok)"
+msgstr ""
+
+#: ../modules/settings.module:151 ../modules/settings.module:156
+#: ../modules/settings.module:161 ../modules/settings.module:166
+#: ../modules/settings.module:176 ../modules/settings.module:181
+msgid "Voicemail password not changed"
+msgstr "A jelszót nem változtattam meg"
+
+#: ../modules/settings.module:152
+msgid "Password and password confirm must not be blank"
+msgstr "A jelszavakat nem hagyhatja üresen"
+
+#: ../modules/settings.module:157
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and greater than %d digits"
+msgstr "A jelszó csak számból állhat és csak 4 karakteres lehet"
+
+#: ../modules/settings.module:162
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and only %d digits"
+msgstr "A jelszó csak számból állhat és csak 4 karakteres lehet"
+
+#: ../modules/settings.module:167
+msgid "Password and password confirm do not match"
+msgstr "A két jelszó nem egyezik"
+
+#: ../modules/settings.module:177 ../modules/settings.module:182
+#: ../modules/settings.module:234 ../modules/settings.module:239
+#, fuzzy, php-format
+msgid "%s does not exist or is not writable"
+msgstr "nem létezik vagy nem írható"
+
+#: ../modules/settings.module:223
+#, fuzzy
+msgid "Voicemail email and pager address not changed"
+msgstr "A jelszót nem változtattam meg"
+
+#: ../modules/settings.module:233 ../modules/settings.module:238
+#, fuzzy
+msgid "Voicemail email settings not changed"
+msgstr "A jelszót nem változtattam meg"
+
+#: ../modules/settings.module:385
+msgid "Language:"
+msgstr "Nyelv"
+
+#: ../modules/settings.module:408
+#, fuzzy
+msgid "Call Routing"
+msgstr "Hangrögzítés beállításai"
+
+#: ../modules/settings.module:411
+#, fuzzy
+msgid "Call Forwarding:"
+msgstr "Hangrögzítés beállításai"
+
+#: ../modules/settings.module:419 ../modules/settings.module:507
+#, fuzzy
+msgid "Enable"
+msgstr "táblában"
+
+#: ../modules/settings.module:431
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and only %s digits"
+msgstr "A jelszó csak számból állhat és csak 4 karakteres lehet"
+
+#: ../modules/settings.module:434
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and at least %s digits"
+msgstr "A jelszó csak számból állhat és csak 4 karakteres lehet"
+
+#: ../modules/settings.module:439
+#, fuzzy
+msgid "Voicemail Password:"
+msgstr "Hangposta jelszó:"
+
+#: ../modules/settings.module:445
+msgid "Enter again to confirm:"
+msgstr "Irja be újra:"
+
+#: ../modules/settings.module:492
+#, fuzzy
+msgid "Email Voicemail To:"
+msgstr "Hangposta"
+
+#: ../modules/settings.module:498
+#, fuzzy
+msgid "Pager Voicemail To:"
+msgstr "Hangposta"
+
+#: ../modules/settings.module:558
+msgid "Audio Format:"
+msgstr "Hangformátum:"
+
+#: ../modules/settings.module:561
+msgid "Best Quality"
+msgstr "Legjobb minõség"
+
+#: ../modules/settings.module:562
+msgid "Smallest Download"
+msgstr "Legkisebb méret"
+
+#: ../modules/settings.module:570
+msgid "Voicemail Settings"
+msgstr "Hangposta beállítások"
+
+#: ../modules/settings.module:611
+msgid "Call Monitor Settings"
+msgstr "Hangrögzítés beállításai"
+
+#: ../modules/settings.module:614
+msgid "Record INCOMING:"
+msgstr "Hangrögzítés - Bejövõ:"
+
+#: ../modules/settings.module:616 ../modules/settings.module:624
+msgid "Always"
+msgstr "Mindíg"
+
+#: ../modules/settings.module:617 ../modules/settings.module:625
+msgid "Never"
+msgstr "Soha"
+
+#: ../modules/settings.module:618 ../modules/settings.module:626
+msgid "On-Demand"
+msgstr "Igény esetén"
+
+#: ../modules/settings.module:622
+msgid "Record OUTGOING:"
+msgstr "Hangrögzítés - Bejövõ:"
+
+#: ../modules/settings.module:669
+#, fuzzy, php-format
+msgid "Settings for %s (%s)"
+msgstr "Beállítások"
+
+#: ../modules/settings.module:705
+msgid "Update"
+msgstr "Frissít"
+
+#: ../modules/voicemail.module:45
+msgid "Voicemail"
+msgstr "Hangposta"
+
+#: ../modules/voicemail.module:164
+msgid "A folder must be selected before the message can be moved."
+msgstr "Ãthelyezés elõtt ki kell jelölni egy mappát."
+
+#: ../modules/voicemail.module:178
+msgid "An extension must be selected before the message can be forwarded."
+msgstr "Üzenet áthelyezése elõtt ki kell jelölni egy melléket."
+
+#: ../modules/voicemail.module:304
+msgid "move_to"
+msgstr "Ãthelyez"
+
+#: ../modules/voicemail.module:307
+#, fuzzy
+msgid "Folder"
+msgstr "Mappa"
+
+#: ../modules/voicemail.module:311
+msgid "forward_to"
+msgstr "Ãtirányít"
+
+#: ../modules/voicemail.module:328
+msgid "Priority"
+msgstr "Prioritás"
+
+#: ../modules/voicemail.module:330
+msgid "Orig Mailbox"
+msgstr "Eredeti Postafiók"
+
+#: ../modules/voicemail.module:362
+msgid "Message"
+msgstr ""
+
+#: ../modules/voicemail.module:377
+msgid "Voicemail recording(s) was not found."
+msgstr "Nem találok rögzítés(eke)t."
+
+#: ../modules/voicemail.module:378
+#, php-format
+msgid ""
+"On settings page, change voicemail audio format. It is currently set to %s"
+msgstr ""
+
+#: ../modules/voicemail.module:405
+#, fuzzy
+msgid "Voicemail Login not found."
+msgstr "Hangposta Azonosító nem található"
+
+#: ../modules/voicemail.module:406
+msgid "No access to voicemail"
+msgstr "Nincs hozzáférés a hangpostához"
+
+#: ../modules/voicemail.module:412
+msgid "No Voicemail Recordings for Admin"
+msgstr "Nincs hangfelvétel az Admin részére"
+
+#: ../modules/voicemail.module:428
+#, fuzzy, php-format
+msgid "Voicemail for %s (%s)"
+msgstr "Hangposta"
+
+#: ../modules/voicemail.module:678
+#, fuzzy, php-format
+msgid "Could not create mailbox folder %s on the server"
+msgstr "Nem tudom létrehozni a hangposta mappát"
+
+#: ../modules/voicemail.module:718
+#, fuzzy, php-format
+msgid "Permission denied on folder %s or %s"
+msgstr "Hozzáférés elutasítva"
+
+#: ../misc/recording_popup.php:39
+msgid "download"
+msgstr "letöltés"
+
+#~ msgid "Passwords must be all numbers and only 4 digits"
+#~ msgstr "A jelszó csak számból állhat és csak 4 karakteres lehet"
+
+#~ msgid "Folders"
+#~ msgstr "Mappák"
+
+#~ msgid "Login used"
+#~ msgstr "Azonosító használt"
+
+#, fuzzy
+#~ msgid "No Asterisk Manager Interface connection"
+#~ msgstr "Asterisk Call Manager nem válaszol"
+
+#~ msgid "not a directory or not readable"
+#~ msgstr "nem k&ouml;nyvtár vagy nem olvasható"
+
+#~ msgid "of"
+#~ msgstr "av"
+
+#~ msgid "Use your"
+#~ msgstr "Használja "
+
+#~ msgid "for"
+#~ msgstr " - "
+
+#~ msgid "Password must be all numbers and 4 digits"
+#~ msgstr "A jelszó csak számból állhat és 4 karakteres lehet"
+
+#~ msgid "on the server"
+#~ msgstr "a serveren"
+
+#~ msgid "No database connection"
+#~ msgstr "Nincs adatbázis kapcsolat"
diff --git a/fs_selfservice/fri/locale/it_IT/LC_MESSAGES/ari.mo b/fs_selfservice/fri/locale/it_IT/LC_MESSAGES/ari.mo
new file mode 100644
index 000000000..d5a7da899
--- /dev/null
+++ b/fs_selfservice/fri/locale/it_IT/LC_MESSAGES/ari.mo
Binary files differ
diff --git a/fs_selfservice/fri/locale/it_IT/LC_MESSAGES/ari.po b/fs_selfservice/fri/locale/it_IT/LC_MESSAGES/ari.po
new file mode 100644
index 000000000..db245f995
--- /dev/null
+++ b/fs_selfservice/fri/locale/it_IT/LC_MESSAGES/ari.po
@@ -0,0 +1,999 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: 1.1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-08-24 12:33+0200\n"
+"PO-Revision-Date: 2007-08-25 22:41-0600\n"
+"Last-Translator: Francesco Romano\n"
+"Language-Team: Italian\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../includes/asi.php:46
+msgid "Asterisk Call Manager not responding"
+msgstr "Il Call Manager di Asterisk non risponde"
+
+#: ../includes/asi.php:54
+msgid "Asterisk authentication failed:"
+msgstr "Autenticazione Asterisk fallita:"
+
+#
+#: ../includes/asi.php:96 ../includes/asi.php:111 ../includes/asi.php:130
+#: ../includes/asi.php:144
+msgid "Asterisk command not understood"
+msgstr "comando reload di Asterisk non eseguito"
+
+#
+#: ../includes/bootstrap.php:123
+#, php-format
+msgid "To many directories in %s Not all files processed"
+msgstr "Troppe directory in %s Non tutti i files sono stati processati"
+
+#: ../includes/bootstrap.php:226
+#, fuzzy
+msgid "ARI requires a version of PHP 4.3 or later"
+msgstr "ARI richiede PHP 4.0 o superiore"
+
+#: ../includes/bootstrap.php:245
+msgid ""
+"PHP PEAR must be installed. Visit http://pear.php.net for help with "
+"installation."
+msgstr ""
+"PHP PEAR deve essere installato. Visitare http://pear.php.net per aiuto "
+"nell'installazione."
+
+#
+#: ../includes/common.php:180
+msgid "ARI does not appear to have access to the Asterisk Manager."
+msgstr "Impossibile connettersi all'Asterisk Manager"
+
+#: ../includes/common.php:181
+##, fuzzy
+msgid ""
+"Check the ARI 'main.conf.php' configuration file to set the Asterisk Manager "
+"Account."
+msgstr ""
+"Controllare il file di configurazione main.conf di ARI per l'impostazione "
+"sull'account dell'Asterisk Manager."
+
+#: ../includes/common.php:182
+msgid "Check /etc/asterisk/manager.conf for a proper Asterisk Manager Account"
+msgstr ""
+"Controllare /etc/asterisk/manager.conf per un valido account Asterisk Manager"
+
+#: ../includes/common.php:183
+msgid ""
+"make sure [general] enabled = yes and a 'permit=' line for localhost or the "
+"webserver."
+msgstr ""
+"assicurarsi che in [general] sia presente enable = yes e la riga 'permit=' "
+"con l'indirizzo localhost o il webserver."
+
+#
+#: ../includes/common.php:200 ../includes/common.php:215
+msgid "Check AMP installation, asterisk, and ARI main.conf"
+msgstr ""
+"Controllare l'installazione di AMP, il database di asterisk o il file main."
+"conf di ARI"
+
+#: ../includes/common.php:351
+msgid "Logout"
+msgstr "Esci"
+
+#: ../includes/common.php:356
+msgid "Page Not Found."
+msgstr "Pagina Non Trovata"
+
+#: ../includes/display.php:92
+msgid "Search"
+msgstr "Cerca"
+
+#: ../includes/display.php:135
+msgid "Searched for"
+msgstr "Ricerca per"
+
+#
+#: ../includes/display.php:139
+##, fuzzy, php-format
+msgid "Results %d - %d of %d"
+msgstr "Risultati %d - %d di %d"
+
+#
+#: ../includes/display.php:141
+#, php-format
+msgid "Results %d"
+msgstr "Risultati %d"
+
+#: ../includes/display.php:195
+msgid "First"
+msgstr "Prima"
+
+#: ../includes/display.php:208
+msgid "Last"
+msgstr "Ultima"
+
+#: ../includes/login.php:267
+msgid "Incorrect Password"
+msgstr "Password sbagliata"
+
+#: ../includes/login.php:279
+msgid "Incorrect Username or Password"
+msgstr "Nome Utente o Password sbagliati"
+
+#: ../includes/login.php:404 ../includes/login.php:413
+msgid "Login"
+msgstr "Login"
+
+#: ../includes/login.php:421
+msgid "Password"
+msgstr "Password"
+
+#: ../includes/login.php:430
+msgid "Submit"
+msgstr "Invia"
+
+#: ../includes/login.php:438
+msgid "Remember Password"
+msgstr "Ricorda Password"
+
+#
+#: ../includes/login.php:453
+msgid "Use your <b>Voicemail Mailbox and Password</b>"
+msgstr ""
+"Utilizzare come login il numero della <b>Casella Vocale e relativa "
+"Password</b>"
+
+#: ../includes/login.php:454
+msgid "This is the same password used for the phone"
+msgstr "Sono gli stessi utilizzati dal proprio telefono"
+
+#: ../includes/login.php:456
+msgid ""
+"For password maintenance or assistance, contact your Phone System "
+"Administrator."
+msgstr ""
+"Per assistenza o manutenzione, contattare l'amministratore del Centralino."
+
+#: ../includes/main.conf.php:150
+msgid "INBOX"
+msgstr "NUOVI"
+
+#: ../includes/main.conf.php:152
+msgid "Family"
+msgstr "Personali"
+
+#: ../includes/main.conf.php:154
+msgid "Friends"
+msgstr "Amici"
+
+#: ../includes/main.conf.php:156
+msgid "Old"
+msgstr "Vecchi"
+
+#: ../includes/main.conf.php:158
+msgid "Work"
+msgstr "Lavoro"
+
+#: ../includes/main.conf.php:237
+msgid "Call Forward All Activate"
+msgstr "Attivazione Trasferimento di Chiamata Incondizionato"
+
+#: ../includes/main.conf.php:238
+msgid "Call Forward All Deactivate"
+msgstr "Disattivazione Trasferimento di Chiamata Incondizionato"
+
+#: ../includes/main.conf.php:239
+msgid "Call Forward All Prompting Deactivate"
+msgstr "Disattivazione Trasferimento di Chiamata Incondizionato (chiede dettagli)"
+
+#: ../includes/main.conf.php:240
+msgid "Call Forward Busy Activate"
+msgstr "Attivazione Trasferimento di Chiamata su Occupato"
+
+#: ../includes/main.conf.php:241
+msgid "Call Forward Busy Deactivate"
+msgstr "Disattivazione Trasferimento di Chiamata su Occupato"
+
+#: ../includes/main.conf.php:242
+msgid "Call Forward Busy Prompting Deactivate"
+msgstr "Disattivazione Trasferimento di Chiamata su Occupato (chiede dettagli)"
+
+#: ../includes/main.conf.php:243
+msgid "Call Forward No Answer/Unavailable Activate"
+msgstr "Attivazione Trasferimento di Chiamata su nessuna risposta"
+
+#: ../includes/main.conf.php:244
+msgid "Call Forward No Answer/Unavailable Deactivate"
+msgstr "Disattivazione Trasferimento di Chiamata su nessuna risposta"
+
+#: ../includes/main.conf.php:245
+msgid "Call Waiting - Activate"
+msgstr "Attivazione Avviso di chiamata"
+
+#: ../includes/main.conf.php:247
+msgid "Do-Not-Disturb Activate"
+msgstr "Attivazione Non-Disturbare"
+
+#: ../includes/main.conf.php:248
+msgid "Do-Not-Disturb Deactivate"
+msgstr "Disattivazione Non-Disturbare"
+
+#: ../includes/main.conf.php:249
+msgid "My Voicemail"
+msgstr "Propria Casella Vocale"
+
+#: ../includes/main.conf.php:250
+msgid "Dial Voicemail"
+msgstr "Casella Vocale"
+
+#: ../includes/main.conf.php:303
+msgid "Email voicemail as attachment"
+msgstr "Invia messaggio vocale come allegato email"
+
+#: ../includes/main.conf.php:304
+msgid "Say caller id in recording emailed"
+msgstr "Riproduci ID chiamante nella registrazione inviata"
+
+#: ../includes/main.conf.php:305
+msgid "Say envelop (date/time) in recording emailed"
+msgstr "Riproduci data/ora nella registrazione inviata"
+
+#: ../includes/main.conf.php:306
+msgid "Delete voicemail when emailed"
+msgstr "Elimina messaggio vocale dopo aver spedito l'email"
+
+#: ../includes/main.conf.php:307
+msgid "Play next message after deleting current message"
+msgstr ""
+"Riproduci il messaggio seguente dopo aver eliminato il messaggio corrente"
+
+#: ../includes/main.conf.php:308
+msgid "Ask caller to review their voicemail before sending"
+msgstr ""
+
+#: ../includes/main.conf.php:309
+msgid "Maximum time in seconds a voicemail will record"
+msgstr ""
+
+#: ../modules/VmX.module:58
+msgid "VmX&#8482 Locator"
+msgstr "VmX&#8482 Locator"
+
+#: ../modules/VmX.module:115
+msgid ""
+"Your Premium VmX Locator service has been disabled, REFRESH your browser to "
+"remove this message"
+msgstr ""
+"Il proprio VmX Locator è stato disabilitato, AGGIORNARE la pagina per "
+"rimuovere questo messaggio"
+
+#: ../modules/VmX.module:116 ../modules/followme.module:101
+#, php-format
+msgid ""
+"Check with your Telephone System Administrator if you think there is a "
+"problem"
+msgstr ""
+"Contattare l'amministratore del Sistema Telefonico se ci sono dei problemi"
+
+#: ../modules/VmX.module:147
+msgid "Option 0 not changed"
+msgstr "Opzione 0 non cambiata"
+
+#
+#: ../modules/VmX.module:148 ../modules/VmX.module:181
+#: ../modules/VmX.module:201 ../modules/phonefeatures.module:302
+#, php-format
+msgid ""
+"Number %s must contain dial numbers (characters like '(', '-', and ')' are "
+"ok)"
+msgstr ""
+"Il numero %s deve contenere cifre valide (vanno benne caratteri come '(', "
+"'-' e ')')"
+
+#: ../modules/VmX.module:180
+msgid "Option 1 not changed"
+msgstr "Opzione 1 non cambiata"
+
+#: ../modules/VmX.module:200
+msgid "Option 2 not changed"
+msgstr "opzione 2 non cambiata"
+
+#: ../modules/VmX.module:300
+msgid "Use When:"
+msgstr "Utilizzare quando:"
+
+#: ../modules/VmX.module:300
+msgid ""
+"Menu options below are available during your personal voicemail greeting "
+"playback. <br/><br/>Check both to use at all times."
+msgstr ""
+"Le opzioni del menu disponibili qui sotto sono proposte durante il messaggio "
+"di benvenuto della casella vocale. <br/><br/>"
+
+#: ../modules/VmX.module:302
+msgid "unavailable"
+msgstr "non disponibile"
+
+#: ../modules/VmX.module:306
+msgid "busy"
+msgstr "occupato"
+
+#: ../modules/VmX.module:310
+msgid "Voicemail Instructions:"
+msgstr "Istruzioni Casella Vocale:"
+
+#: ../modules/VmX.module:310
+msgid "Uncheck to play a beep after your personal voicemail greeting."
+msgstr "Deselezionare per riprodurre un tono dopo il messaggio di benvenuto."
+
+#: ../modules/VmX.module:313
+msgid "Standard voicemail prompts."
+msgstr "Messaggi standard Casella Vocale"
+
+#: ../modules/VmX.module:321
+msgid "Press 0:"
+msgstr "Premere 0:"
+
+#: ../modules/VmX.module:321
+msgid ""
+"Pressing 0 during your personal voicemail greeing goes to the Operator. \n"
+"\t\t\t\t\tUncheck to enter another destination here."
+msgstr ""
+"Premendo 0 durante il messaggio di benvenuto della Casella Vocale, la "
+"chiamata sarà reindirizzata all'operatore. \n"
+"\t\t\t\t\tDeselezionare per inserire un'altra destinazione."
+
+#: ../modules/VmX.module:329
+msgid "Go To Operator"
+msgstr "Per andare all'Operatore"
+
+#: ../modules/VmX.module:333
+msgid "Press 1:"
+msgstr "Premere 1:"
+
+#: ../modules/VmX.module:336
+msgid ""
+"The remaining options can have internal extensions, ringgroups, queues and "
+"external numbers that may be rung. It is often used to include your cell "
+"phone. You should run a test to make sure that the number is functional any "
+"time a change is made so you don't leave a caller stranded or receiving "
+"invalid number messages."
+msgstr ""
+
+#: ../modules/VmX.module:338
+msgid ""
+"Enter an alternate number here, then change your personal voicemail greeting "
+"to let callers know to press 1 to reach that number. <br/><br/>If you'd like "
+"to use your Follow Me List, check \"Send to Follow Me\" and disable Follow "
+"Me above."
+msgstr ""
+"Immettere una destinazione alternativa, dopo, cambiare il messaggio di "
+"benvenuto per permettere ai chiamanti di premere 1 per raggiungere quella "
+"numerazione. <br/><br/> Se si vuole utilizzare la Lista Seguimi, selezionare "
+"\"Invia al Seguimi\" e disattivare sopra il Seguimi."
+
+#: ../modules/VmX.module:351
+msgid "Send to Follow-Me"
+msgstr "Invia al Seguimi"
+
+#: ../modules/VmX.module:359
+msgid "Press 2:"
+msgstr "Premere 2:"
+
+#: ../modules/VmX.module:359
+msgid ""
+"Use any extensions, ringgroups, queues or external numbers. <br/><br/"
+">Remember to re-record your personal voicemail greeting and include "
+"instructions. Run a test to make sure that the number is functional."
+msgstr ""
+"Utilizzare qualsiasi interno, gruppo di chiamata, coda o numero esterno. <br/"
+"><br/>Ricordarsi di ri-registrare il proprio messaggio di benvenuto e "
+"includere delle istruzioni. Fare dei test per assicurarsi che tutto funzioni."
+
+#
+#: ../modules/VmX.module:373
+##, fuzzy, php-format
+msgid "VmX Locator&#8482; Settings for %s (%s)"
+msgstr "Impostazioni di %s (%s)"
+
+#: ../modules/VmX.module:415 ../modules/followme.module:384
+#: ../modules/phonefeatures.module:180 ../modules/settings.module:625
+msgid "Update"
+msgstr "Aggiorna"
+
+#: ../modules/callmonitor.module:36 ../modules/callmonitor.module:256
+msgid "Call Monitor"
+msgstr "Registrazioni Chiamate"
+
+#
+#: ../modules/callmonitor.module:131
+#, php-format
+msgid "Path is not a directory: %s"
+msgstr "Il percorso non è una directory: %s"
+
+#: ../modules/callmonitor.module:140 ../modules/voicemail.module:318
+msgid "delete"
+msgstr "elimina"
+
+#
+#: ../modules/callmonitor.module:146
+msgid "duration"
+msgstr "durata"
+
+#
+#: ../modules/callmonitor.module:149
+msgid "ignore"
+msgstr "niente"
+
+#: ../modules/callmonitor.module:158 ../modules/voicemail.module:339
+msgid "Date"
+msgstr "Data"
+
+#: ../modules/callmonitor.module:160 ../modules/voicemail.module:341
+msgid "Time"
+msgstr "Ora"
+
+#: ../modules/callmonitor.module:162 ../modules/voicemail.module:343
+msgid "Caller ID"
+msgstr "ID Chiamante"
+
+#: ../modules/callmonitor.module:164
+msgid "Source"
+msgstr "Sorgente"
+
+#: ../modules/callmonitor.module:166
+msgid "Destination"
+msgstr "Destinazione"
+
+#: ../modules/callmonitor.module:168
+msgid "Context"
+msgstr "Contesto"
+
+#: ../modules/callmonitor.module:170 ../modules/voicemail.module:349
+msgid "Duration"
+msgstr "Durata"
+
+#: ../modules/callmonitor.module:201
+msgid "Monitor"
+msgstr "Registrazione"
+
+#: ../modules/callmonitor.module:221 ../modules/voicemail.module:390
+msgid "play"
+msgstr "riproduci"
+
+#
+#: ../modules/callmonitor.module:258
+#, php-format
+msgid "Call Monitor for %s (%s)"
+msgstr "Registrazioni Chiamate di %s (%s)"
+
+#: ../modules/callmonitor.module:310 ../modules/voicemail.module:492
+msgid "select"
+msgstr "seleziona"
+
+#: ../modules/callmonitor.module:311 ../modules/voicemail.module:493
+msgid "all"
+msgstr "tutto"
+
+#: ../modules/callmonitor.module:312 ../modules/voicemail.module:494
+msgid "none"
+msgstr "niente"
+
+#: ../modules/callmonitor.module:532
+msgid "Only deletes recording files, not cdr log"
+msgstr "Eliminati solo i file di registrazione, non i log delle chiamate"
+
+#: ../modules/featurecodes.module:36 ../modules/featurecodes.module:63
+##, fuzzy
+msgid "Feature Codes"
+msgstr "Codici Servizi"
+
+#
+#: ../modules/featurecodes.module:65
+##, fuzzy, php-format
+msgid " for %s (%s)"
+msgstr " per %s (%s)"
+
+#: ../modules/featurecodes.module:72
+msgid "Handset Feature Code"
+msgstr "Codice"
+
+#: ../modules/featurecodes.module:75
+msgid "Action"
+msgstr "Azione"
+
+#: ../modules/followme.module:43
+msgid "Follow Me"
+msgstr "Seguimi"
+
+#: ../modules/followme.module:100
+msgid ""
+"Your Follow-Me has been disabled, REFRESH your browser to remove this message"
+msgstr ""
+"Il Seguimi è disattivato, AGGIORNA la pagina per rimuovere questo messaggio"
+
+#: ../modules/followme.module:118
+msgid "Follow-Me pre-ring time not changed"
+msgstr "Tempo di pre-squillo per il Seguimi non cambiato"
+
+#: ../modules/followme.module:119 ../modules/followme.module:142
+#, php-format
+msgid "Number %s must be an interger number of seconds"
+msgstr "Il numero %s deve contenere numeri interi"
+
+#: ../modules/followme.module:141
+msgid "Follow-Me list ring time not changed"
+msgstr "Tempo di squillo Lista Seguimi non cambiato"
+
+#: ../modules/followme.module:185
+msgid "Follow-Me list must contain at least one valid number"
+msgstr "Il Seguimi deve contenere almeno un numero valido"
+
+#: ../modules/followme.module:186
+#, php-format
+msgid "The following: %s is not valid"
+msgstr "Il seguente: %s non è valido"
+
+#
+#: ../modules/followme.module:291 ../modules/followme.module:344
+#: ../modules/phonefeatures.module:335 ../modules/settings.module:420
+msgid "Enable"
+msgstr "Attiva"
+
+#: ../modules/followme.module:292
+msgid ""
+"Dial-by-name Directory, IVR, and internal \n"
+"\t\t\t\t\t\t\t\t\t\t\t\t\tcalls will ring the numbers in the FollowMe \n"
+"\t\t\t\t\t\t\t\t\t\t\t\t\tList. Any FreePBX routes that directly \n"
+"\t\t\t\t\t\t\t\t\t\t\t\t\treference a FollowMe are unaffected by this \n"
+"\t\t\t\t\t\t\t\t\t\t\t\t\tenable/disable setting."
+msgstr "L'Elenco Telefonico, l'IVR e le chiamate interne chiameranno i numeri definiti nella Lista Seguimi. Qualsiasi rotta che ha come referenza un Seguimi non sarà affetto dall'attivazione o dalla disattivazione di questa impostazione."
+
+#: ../modules/followme.module:304
+msgid "Follow Me List:"
+msgstr "Lista Seguimi:"
+
+#: ../modules/followme.module:305
+#, php-format
+msgid "Extensions and outside numbers to ring next."
+msgstr "Interni e numeri esterni da chiamare dopo."
+
+#: ../modules/followme.module:306
+#, php-format
+msgid "Include %s to keep it ringing."
+msgstr "Immettere %s per lasciar squillare."
+
+#: ../modules/followme.module:312
+#, php-format
+msgid "Ring %s First For:"
+msgstr "Chiama prima %s per:"
+
+#: ../modules/followme.module:313
+#, php-format
+msgid "Time to ring extension %s before ringing the %s Follow Me List %s"
+msgstr ""
+"Il tempo di chiamata per l'interno %s prima di far squillare la %s Lista "
+"Seguimi %s"
+
+#: ../modules/followme.module:323 ../modules/followme.module:336
+msgid "seconds"
+msgstr "secondi"
+
+#: ../modules/followme.module:326
+msgid "Ring Followme List for:"
+msgstr "Chiama la Lista Seguimi per:"
+
+#: ../modules/followme.module:326
+msgid "Time to ring the Follow Me List."
+msgstr "Il tempo di chiamata per la Lista Seguimi."
+
+#: ../modules/followme.module:341
+msgid "Use Confirmation:"
+msgstr "Utilizza Conferma:"
+
+#: ../modules/followme.module:341
+msgid ""
+"Outside lines that are part of the Follow Me List will be called and offered "
+"a menu:<br/><br/> \"You have an incoming call. Press 1 to accept or 2 to "
+"decline.\"<br/><br/> This keeps calls from ending up in external voicemail. "
+"Make sure that the List Ring Time is long enough to allow for you to hear "
+"and react to this message."
+msgstr ""
+"Ai Numeri esterni che fanno parte della Lista Seguimi sarà proposto un menu:"
+"<br/><br/> \"Hai una chiamata in arrivo. Premere 1 per accettare o 2 per "
+"rifiutare.\" Questo evita alle chiamate esterne di finire in una segreteria. "
+"Assicurarsi che il tempo di chiamata sia abbastanza lungo per rispondere a "
+"questo messaggio."
+
+#: ../modules/followme.module:356
+##, fuzzy
+msgid "Followme Settings"
+msgstr "Impostazioni Seguimi"
+
+#
+#: ../modules/followme.module:358
+##, fuzzy, php-format
+msgid "Followme Settings for %s (%s)"
+msgstr "Impostazioni Seguimi per %s (%s)"
+
+#: ../modules/phonefeatures.module:25 ../modules/phonefeatures.module:96
+#: ../modules/phonefeatures.module:163
+msgid "Phone Features"
+msgstr "Servizi Telefonici"
+
+#
+#: ../modules/phonefeatures.module:149
+##, fuzzy
+msgid "Call Forwarding"
+msgstr "Trasferimento di Chiamata"
+
+#
+#: ../modules/phonefeatures.module:165
+##, fuzzy, php-format
+msgid "Features for %s (%s)"
+msgstr "Impostazioni per %s (%s)"
+
+#: ../modules/phonefeatures.module:301
+msgid "Call forward number not changed"
+msgstr "Numero per il trasferimento di chiamata non cambiato"
+
+#: ../modules/settings.module:56
+msgid "Settings"
+msgstr "Impostazioni"
+
+#: ../modules/settings.module:118 ../modules/settings.module:123
+#: ../modules/settings.module:128 ../modules/settings.module:133
+#: ../modules/settings.module:143 ../modules/settings.module:148
+msgid "Voicemail password not changed"
+msgstr "Password Casella Vocale non cambiata"
+
+#: ../modules/settings.module:119
+msgid "Password and password confirm must not be blank"
+msgstr "Password e conferma password non possono essere vuoti"
+
+#
+#: ../modules/settings.module:124
+##, fuzzy, php-format
+msgid "Passwords must be all numbers and greater than %d digits"
+msgstr "La Password deve essere minimo di %d numeri"
+
+#
+#: ../modules/settings.module:129
+##, fuzzy, php-format
+msgid "Passwords must be all numbers and only %d digits"
+msgstr "La Password deve essere di %d numeri"
+
+#: ../modules/settings.module:134
+msgid "Password and password confirm do not match"
+msgstr "Password e Conferma password non corrispondono"
+
+#
+#: ../modules/settings.module:144 ../modules/settings.module:149
+#: ../modules/settings.module:200 ../modules/settings.module:205
+##, fuzzy, php-format
+msgid "%s does not exist or is not writable"
+msgstr "%s non esiste o non è scrivile"
+
+#
+#: ../modules/settings.module:189
+msgid "Voicemail email and pager address not changed"
+msgstr "Password Casella Vocale non cambiata"
+
+#
+#: ../modules/settings.module:199 ../modules/settings.module:204
+msgid "Voicemail email settings not changed"
+msgstr "Password Casella Vocale non cambiata"
+
+#: ../modules/settings.module:347
+msgid "Language:"
+msgstr "Lingua:"
+
+#
+#: ../modules/settings.module:357
+#, php-format
+msgid "Passwords must be all numbers and only %s digits"
+msgstr "La Password deve essere di solo numeri e %s cifre"
+
+#
+#: ../modules/settings.module:360
+##, fuzzy, php-format
+msgid "Passwords must be all numbers and at least %s digits"
+msgstr "La Password deve essere di solo numeri e minimo %s cifre"
+
+#
+#: ../modules/settings.module:365
+msgid "Voicemail Password:"
+msgstr "Password Casella Vocale:"
+
+#: ../modules/settings.module:371
+msgid "Enter again to confirm:"
+msgstr "Conferma password:"
+
+#
+#: ../modules/settings.module:419
+msgid "Email Notification"
+msgstr "Notifica Email"
+
+#
+#: ../modules/settings.module:423
+msgid "Email Voicemail To:"
+msgstr "Notifica Email a:"
+
+#
+#: ../modules/settings.module:429
+msgid "Pager Email Notification To:"
+msgstr "Invia Notifica Email al Pager:"
+
+#: ../modules/settings.module:485
+msgid "Audio Format:"
+msgstr "Formato Audio:"
+
+#: ../modules/settings.module:488
+msgid "Best Quality"
+msgstr "Migliore Qualità"
+
+#: ../modules/settings.module:489
+msgid "Smallest Download"
+msgstr "Download Veloci"
+
+#: ../modules/settings.module:497
+msgid "Voicemail Settings"
+msgstr "Impostazioni Casella Vocale"
+
+#: ../modules/settings.module:538
+msgid "Call Monitor Settings"
+msgstr "Impostazioni Registrazioni Chiamate"
+
+#: ../modules/settings.module:541
+msgid "Record INCOMING:"
+msgstr "Registra ENTRANTI:"
+
+#: ../modules/settings.module:543 ../modules/settings.module:551
+msgid "Always"
+msgstr "Sempre"
+
+#: ../modules/settings.module:544 ../modules/settings.module:552
+msgid "Never"
+msgstr "Mai"
+
+#: ../modules/settings.module:545 ../modules/settings.module:553
+msgid "On-Demand"
+msgstr "Su richiesta"
+
+#: ../modules/settings.module:549
+msgid "Record OUTGOING:"
+msgstr "Registra USCENTI:"
+
+#
+#: ../modules/settings.module:592
+##, fuzzy, php-format
+msgid "Settings for %s (%s)"
+msgstr "Impostazioni per %s (%s)"
+
+#: ../modules/voicemail.module:44
+msgid "Voicemail"
+msgstr "Casella Vocale"
+
+#: ../modules/voicemail.module:163
+msgid "A folder must be selected before the message can be moved."
+msgstr ""
+"Prima di spostare un messaggio, selezionare una cartella di destinazione"
+
+#: ../modules/voicemail.module:177
+msgid "An extension must be selected before the message can be forwarded."
+msgstr "Prima di inoltrare un messaggio, selezionare l'interno di destinazione"
+
+#: ../modules/voicemail.module:321
+msgid "move_to"
+msgstr "sposta_verso"
+
+#: ../modules/voicemail.module:324
+msgid "Folder"
+msgstr "Cartella"
+
+#: ../modules/voicemail.module:328
+msgid "forward_to"
+msgstr "inoltra_a"
+
+#: ../modules/voicemail.module:345
+msgid "Priority"
+msgstr "Priorità"
+
+#: ../modules/voicemail.module:347
+msgid "Orig Mailbox"
+msgstr "Casella Orig"
+
+#: ../modules/voicemail.module:379
+msgid "Message"
+msgstr "Messaggio"
+
+#: ../modules/voicemail.module:394
+msgid "Voicemail recording(s) was not found."
+msgstr "Registrazioni Casella Vocale non trovate."
+
+#
+#: ../modules/voicemail.module:395
+#, php-format
+msgid ""
+"On settings page, change voicemail audio format. It is currently set to %s"
+msgstr ""
+"Nella pagina delle impostazioni, cambiare il formato dei messaggi vocali. "
+"Adesso è impostato su %s"
+
+#
+#: ../modules/voicemail.module:422
+msgid "Voicemail Login not found."
+msgstr "Login Casella Vocale non trovato"
+
+#: ../modules/voicemail.module:423
+msgid "No access to voicemail"
+msgstr "Accesso alla Casella Vocale disabilitato"
+
+#: ../modules/voicemail.module:429
+msgid "No Voicemail Recordings for Admin"
+msgstr "Nessuna Casella Vocale per Admin"
+
+#
+#: ../modules/voicemail.module:445
+#, php-format
+msgid "Voicemail for %s (%s)"
+msgstr "Casella Vocale di %s (%s)"
+
+#
+#: ../modules/voicemail.module:695
+##, fuzzy, php-format
+msgid "Could not create mailbox folder %s on the server"
+msgstr "Non posso creare la cartella %s sul server"
+
+#
+#: ../modules/voicemail.module:735
+#, php-format
+msgid "Permission denied on folder %s or %s"
+msgstr "Permessi negati nella cartella %s o %s"
+
+#: ../misc/recording_popup.php:39
+msgid "download"
+msgstr "scarica"
+
+msgid "Unconditional:"
+msgstr "Incondizionato:"
+
+msgid "Unavailable:"
+msgstr "Non disponibile:"
+
+msgid "Busy:"
+msgstr "Occupato:"
+
+#
+##, fuzzy
+msgid "Call Waiting"
+msgstr "Avviso di Chiamata"
+
+##, fuzzy
+msgid "Do Not Disturb"
+msgstr " Non-Disturbare"
+
+#
+##, fuzzy
+msgid "Passwords must be all numbers and at least 3 digits"
+msgstr "La Password deve essere di solo numeri e minimo di 3 cifre"
+
+#~ msgid "Directory"
+#~ msgstr "Directory"
+
+#~ msgid "Echo Test"
+#~ msgstr "Test Echo"
+
+#~ msgid "Weather"
+#~ msgstr "Meteo"
+
+#~ msgid "Schedule wakeup call"
+#~ msgstr "Sveglia"
+
+#~ msgid "festival test (your extension is XXX)"
+#~ msgstr "Test Festival (il tuo interno è XXX)"
+
+#~ msgid "Deactivate Call Waiting"
+#~ msgstr "Disattiva Avviso di Chiamata"
+
+#~ msgid "Disable Call Forwarding"
+#~ msgstr "Disattiva Inoltro di Chiamata"
+
+#
+#~ msgid "IVR Recording"
+#~ msgstr "Registrazione IVR"
+
+#~ msgid "Disable Do-Not-Disturb"
+#~ msgstr "Disattiva Non-Disturbare"
+
+#~ msgid "Disable Call Forward on Busy"
+#~ msgstr "Disattiva Inoltro di Chiamata su Occupato"
+
+##, fuzzy
+#~ msgid "Message Center (does not ask for extension)"
+#~ msgstr "Centro Messaggi (non chiede l'interno)"
+
+#~ msgid "Enter Message Center"
+#~ msgstr "Centro Messaggi"
+
+#~ msgid "Playback IVR Recording"
+#~ msgstr "Riproduce Registrazione IVR"
+
+#~ msgid "Test Fax"
+#~ msgstr "Test Fax"
+
+#~ msgid "Simulate incoming call"
+#~ msgstr "Simula chiamata entrante"
+
+#
+##, fuzzy
+#~ msgid "Conference for %s (%s%s)"
+#~ msgstr "Conferenza per %s (%s%s)"
+
+#~ msgid "Help"
+#~ msgstr "Aiuto"
+
+#
+#~ msgid "Pager Voicemail To:"
+#~ msgstr "Casella Vocale"
+
+#~ msgid "Passwords must be all numbers and only 4 digits"
+#~ msgstr "La Password deve essere di solo numeri e 4 cifre"
+
+msgid "Folders"
+msgstr "Cartelle"
+
+#~ msgid "Login used"
+#~ msgstr "Login utilizzato"
+
+#~ msgid "No Asterisk Manager Interface connection"
+#~ msgstr "Impossibile connettersi all'Asterisk Manager Interface"
+
+#~ msgid "Cannot connect to the"
+#~ msgstr "Impossibile connettersi al"
+
+#~ msgid "database"
+#~ msgstr "database"
+
+#~ msgid "not a directory or not readable"
+#~ msgstr "non è una directory o non è leggibile"
+
+#~ msgid "of"
+#~ msgstr "di"
+
+#~ msgid "Use your"
+#~ msgstr "Utilizzare il "
+
+#~ msgid "for"
+#~ msgstr "di"
+
+#~ msgid "Password must be all numbers and 4 digits"
+#~ msgstr "La Password deve essere di 4 numeri"
+
+#~ msgid "Check voicemail audio format on settings page to change from"
+#~ msgstr "Controllare il formato audio nella pagina delle impostazioni"
+
+#~ msgid "on the server"
+#~ msgstr "nel server"
+
+#~ msgid "No database connection"
+#~ msgstr "Connessione al database fallita"
+
+msgid "Email a notification, including audio file if indicated below. "
+msgstr "Invia una notifica per posta elettronica, incluso il file audio se impostato sotto."
+
+msgid "Email a short notification "
+msgstr "Invia una breve notifica"
+
+msgid "Phone Features for %s (%s)"
+msgstr "Servizi Telefonici per %s (%s)"
+
+msgid "User Portal"
+msgstr "Portale Utente" \ No newline at end of file
diff --git a/fs_selfservice/fri/locale/locale.txt b/fs_selfservice/fri/locale/locale.txt
new file mode 100644
index 000000000..6b93e2eb0
--- /dev/null
+++ b/fs_selfservice/fri/locale/locale.txt
@@ -0,0 +1,37 @@
+// To create the .po (write your translations to this file):
+$ find *.php ../includes/* ../modules/*.module ../misc/*.php ../theme/* | xargs xgettext -L PHP -o ari.po --keyword=_ -
+
+// To create the utf-8 .po
+$ iconv -f iso-8859-1 -t utf-8 -o ari.utf-8.po ari.po
+
+// To create the .mo:
+$ msgfmt -v ari.utf-8.po -o ari.mo
+
+// To update (assume both files to be merged are utf-8)
+$ msgmerge es_ES/LC_MESSAGES/ari.po ari.utf-8.po --output-file=es_ES/LC_MESSAGES/ari.po
+$ msgfmt -v es_ES/LC_MESSAGES/ari.po -o es_ES/LC_MESSAGES/ari.mo
+
+
+// script
+// for this to work all translated files need to be converted to utf-8 (use iconv)
+//
+find ../*.php ../includes/* ../modules/*.module ../misc/*.php ../theme/*.css | xargs xgettext -L PHP -o ari.po --keyword=_ -
+iconv -f iso-8859-1 -t utf-8 -o ari.utf-8.po ari.po
+msgmerge el_GR/LC_MESSAGES/ari.po ari.utf-8.po --output-file=el_GR/LC_MESSAGES/ari.po
+msgfmt -v el_GR/LC_MESSAGES/ari.po -o el_GR/LC_MESSAGES/ari.mo
+msgmerge es_ES/LC_MESSAGES/ari.po ari.utf-8.po --output-file=es_ES/LC_MESSAGES/ari.po
+msgfmt -v es_ES/LC_MESSAGES/ari.po -o es_ES/LC_MESSAGES/ari.mo
+msgmerge fr_FR/LC_MESSAGES/ari.po ari.utf-8.po --output-file=fr_FR/LC_MESSAGES/ari.po
+msgfmt -v fr_FR/LC_MESSAGES/ari.po -o fr_FR/LC_MESSAGES/ari.mo
+msgmerge he_IL/LC_MESSAGES/ari.po ari.utf-8.po --output-file=he_IL/LC_MESSAGES/ari.po
+msgfmt -v he_IL/LC_MESSAGES/ari.po -o he_IL/LC_MESSAGES/ari.mo
+msgmerge hu_HU/LC_MESSAGES/ari.po ari.utf-8.po --output-file=hu_HU/LC_MESSAGES/ari.po
+msgfmt -v hu_HU/LC_MESSAGES/ari.po -o hu_HU/LC_MESSAGES/ari.mo
+msgmerge it_IT/LC_MESSAGES/ari.po ari.utf-8.po --output-file=it_IT/LC_MESSAGES/ari.po
+msgfmt -v ot_IT/LC_MESSAGES/ari.po -o it_IT/LC_MESSAGES/ari.mo
+msgmerge pt_BR/LC_MESSAGES/ari.po ari.utf-8.po --output-file=pt_BR/LC_MESSAGES/ari.po
+msgfmt -v pt_BR/LC_MESSAGES/ari.po -o pt_BR/LC_MESSAGES/ari.mo
+msgmerge sv_SE/LC_MESSAGES/ari.po ari.po --output-file=sv_SE/LC_MESSAGES/ari.po
+msgfmt -v sv_SE/LC_MESSAGES/ari.po -o sv_SE/LC_MESSAGES/ari.mo
+
+
diff --git a/fs_selfservice/fri/locale/pt_BR/LC_MESSAGES/ari.mo b/fs_selfservice/fri/locale/pt_BR/LC_MESSAGES/ari.mo
new file mode 100644
index 000000000..baa1a113f
--- /dev/null
+++ b/fs_selfservice/fri/locale/pt_BR/LC_MESSAGES/ari.mo
Binary files differ
diff --git a/fs_selfservice/fri/locale/pt_BR/LC_MESSAGES/ari.po b/fs_selfservice/fri/locale/pt_BR/LC_MESSAGES/ari.po
new file mode 100644
index 000000000..0ab45fa35
--- /dev/null
+++ b/fs_selfservice/fri/locale/pt_BR/LC_MESSAGES/ari.po
@@ -0,0 +1,647 @@
+# Brazilian portuguese translation
+# Copyright (C) 2005 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# Arnaldo M. Pereira <arnaldo@ansi-c.org>, 2005.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-05-03 08:32-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: Arnaldo M. Pereira <arnaldo@ansi-c.org>\n"
+"Language-Team: Brazilian Portuguese <arnaldo@ansi-c.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../includes/asi.php:46
+msgid "Asterisk Call Manager not responding"
+msgstr "Asterisk Call Manager não responde"
+
+#: ../includes/asi.php:54
+msgid "Asterisk authentication failed:"
+msgstr "Autenticação no Asterisk falhou:"
+
+#: ../includes/asi.php:96 ../includes/asi.php:111
+#, fuzzy
+msgid "Asterisk command not understood"
+msgstr "Comando reload do Asterisk não compreendido"
+
+#: ../includes/bootstrap.php:123
+#, php-format
+msgid "To many directories in %s Not all files processed"
+msgstr ""
+
+#: ../includes/bootstrap.php:226
+msgid "ARI requires a version of PHP 4.3 or later"
+msgstr ""
+
+#: ../includes/bootstrap.php:245
+msgid ""
+"PHP PEAR must be installed. Visit http://pear.php.net for help with "
+"installation."
+msgstr ""
+
+#: ../includes/common.php:173
+#, fuzzy
+msgid "ARI does not appear to have access to the Asterisk Manager."
+msgstr "Não foi possível conectar ao Asterisk Manager"
+
+#: ../includes/common.php:174
+msgid ""
+"Check the ARI 'main.conf.php' configuration file to set the Asterisk Manager "
+"Account."
+msgstr ""
+
+#: ../includes/common.php:175
+msgid "Check /etc/asterisk/manager.conf for a proper Asterisk Manager Account"
+msgstr ""
+
+#: ../includes/common.php:176
+msgid ""
+"make sure [general] enabled = yes and a 'permit=' line for localhost or the "
+"webserver."
+msgstr ""
+
+#: ../includes/common.php:193 ../includes/common.php:208
+#, fuzzy
+msgid "Check AMP installation, asterisk, and ARI main.conf"
+msgstr ""
+"Verifique a instalação do AMP, do banco de dados do asterisk ou do main.conf "
+"do ARI"
+
+#: ../includes/common.php:344
+msgid "Logout"
+msgstr ""
+
+#: ../includes/common.php:349
+msgid "Page Not Found."
+msgstr "Página não encontrada."
+
+#: ../includes/display.php:92
+#, fuzzy
+msgid "Search"
+msgstr "Procurado"
+
+#: ../includes/display.php:135
+msgid "Searched for"
+msgstr "Procurado"
+
+#: ../includes/display.php:139
+#, fuzzy, php-format
+msgid "Results %d - %d of %d"
+msgstr "Resultados"
+
+#: ../includes/display.php:141
+#, fuzzy, php-format
+msgid "Results %d"
+msgstr "Resultados"
+
+#: ../includes/display.php:195
+msgid "First"
+msgstr "Primeiro"
+
+#: ../includes/display.php:208
+msgid "Last"
+msgstr ""
+
+#: ../includes/login.php:267
+msgid "Incorrect Password"
+msgstr "Senha incorreta"
+
+#: ../includes/login.php:279
+#, fuzzy
+msgid "Incorrect Username or Password"
+msgstr "Senha incorreta"
+
+#: ../includes/login.php:402 ../includes/login.php:411
+msgid "Login"
+msgstr ""
+
+#: ../includes/login.php:419
+#, fuzzy
+msgid "Password"
+msgstr "Senha incorreta"
+
+#: ../includes/login.php:428
+msgid "Submit"
+msgstr ""
+
+#: ../includes/login.php:436
+#, fuzzy
+msgid "Remember Password"
+msgstr "Voicemail para"
+
+#: ../includes/login.php:451
+#, fuzzy
+msgid "Use your <b>Voicemail Mailbox and Password</b>"
+msgstr "Mailbox e senha do Voicemail"
+
+#: ../includes/login.php:452
+msgid "This is the same password used for the phone"
+msgstr "Esta é a mesma senha utilizada para o telefone"
+
+#: ../includes/login.php:454
+msgid ""
+"For password maintenance or assistance, contact your Phone System "
+"Administrator."
+msgstr ""
+"Para manutenção e assistência, entre em contato com o Administrador de seu "
+"Sistema de Telefonia"
+
+#: ../includes/main.conf.php:152
+msgid "INBOX"
+msgstr ""
+
+#: ../includes/main.conf.php:154
+msgid "Family"
+msgstr ""
+
+#: ../includes/main.conf.php:156
+msgid "Friends"
+msgstr ""
+
+#: ../includes/main.conf.php:158
+msgid "Old"
+msgstr ""
+
+#: ../includes/main.conf.php:160
+msgid "Work"
+msgstr ""
+
+#: ../includes/main.conf.php:229
+msgid "Directory"
+msgstr ""
+
+#: ../includes/main.conf.php:230
+msgid "Echo Test"
+msgstr ""
+
+#: ../includes/main.conf.php:231 ../modules/callmonitor.module:161
+#: ../modules/voicemail.module:324
+msgid "Time"
+msgstr ""
+
+#: ../includes/main.conf.php:232
+msgid "Weather"
+msgstr ""
+
+#: ../includes/main.conf.php:233
+msgid "Schedule wakeup call"
+msgstr ""
+
+#: ../includes/main.conf.php:234
+msgid "festival test (your extension is XXX)"
+msgstr ""
+
+#: ../includes/main.conf.php:235
+msgid "Activate Call Waiting (deactivated by default)"
+msgstr ""
+
+#: ../includes/main.conf.php:236
+msgid "Deactivate Call Waiting"
+msgstr ""
+
+#: ../includes/main.conf.php:237
+msgid "Call Forwarding System"
+msgstr ""
+
+#: ../includes/main.conf.php:238
+msgid "Disable Call Forwarding"
+msgstr ""
+
+#: ../includes/main.conf.php:239
+msgid "IVR Recording"
+msgstr ""
+
+#: ../includes/main.conf.php:240
+msgid "Enable Do-Not-Disturb"
+msgstr ""
+
+#: ../includes/main.conf.php:241
+msgid "Disable Do-Not-Disturb"
+msgstr ""
+
+#: ../includes/main.conf.php:242
+msgid "Call Forward on Busy"
+msgstr ""
+
+#: ../includes/main.conf.php:243
+msgid "Disable Call Forward on Busy"
+msgstr ""
+
+#: ../includes/main.conf.php:244
+msgid "Message Center (does not ask for extension)"
+msgstr ""
+
+#: ../includes/main.conf.php:245
+msgid "Enter Message Center"
+msgstr ""
+
+#: ../includes/main.conf.php:246
+msgid "Playback IVR Recording"
+msgstr ""
+
+#: ../includes/main.conf.php:247
+msgid "Test Fax"
+msgstr ""
+
+#: ../includes/main.conf.php:248
+msgid "Simulate incoming call"
+msgstr ""
+
+#: ../includes/main.conf.php:289
+msgid "Email voicemail as attachment"
+msgstr ""
+
+#: ../includes/main.conf.php:290
+msgid "Say caller id in recording emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:291
+msgid "Say envelop (date/time) in recording emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:292
+msgid "Delete voicemail when emailed"
+msgstr ""
+
+#: ../includes/main.conf.php:293
+msgid "Play next message after deleting current message"
+msgstr ""
+
+#: ../includes/main.conf.php:294
+msgid "Ask caller to review their voicemail before sending"
+msgstr ""
+
+#: ../includes/main.conf.php:295
+msgid "Maximum time in seconds a voicemail will record"
+msgstr ""
+
+#: ../modules/callmonitor.module:37 ../modules/callmonitor.module:257
+#, fuzzy
+msgid "Call Monitor"
+msgstr "Monitor de ligações para"
+
+#: ../modules/callmonitor.module:132
+#, php-format
+msgid "Path is not a directory: %s"
+msgstr ""
+
+#: ../modules/callmonitor.module:141 ../modules/voicemail.module:301
+msgid "delete"
+msgstr ""
+
+#: ../modules/callmonitor.module:147
+msgid "duration"
+msgstr ""
+
+#: ../modules/callmonitor.module:150
+msgid "ignore"
+msgstr ""
+
+#: ../modules/callmonitor.module:159 ../modules/voicemail.module:322
+msgid "Date"
+msgstr ""
+
+#: ../modules/callmonitor.module:163 ../modules/voicemail.module:326
+msgid "Caller ID"
+msgstr ""
+
+#: ../modules/callmonitor.module:165
+msgid "Source"
+msgstr ""
+
+#: ../modules/callmonitor.module:167
+msgid "Destination"
+msgstr ""
+
+#: ../modules/callmonitor.module:169
+msgid "Context"
+msgstr ""
+
+#: ../modules/callmonitor.module:171 ../modules/voicemail.module:332
+msgid "Duration"
+msgstr ""
+
+#: ../modules/callmonitor.module:202
+#, fuzzy
+msgid "Monitor"
+msgstr "Monitor de ligações para"
+
+#: ../modules/callmonitor.module:222 ../modules/voicemail.module:373
+msgid "play"
+msgstr ""
+
+#: ../modules/callmonitor.module:259
+#, fuzzy, php-format
+msgid "Call Monitor for %s (%s)"
+msgstr "Monitor de ligações para"
+
+#: ../modules/callmonitor.module:311 ../modules/voicemail.module:475
+msgid "select"
+msgstr ""
+
+#: ../modules/callmonitor.module:312 ../modules/voicemail.module:476
+msgid "all"
+msgstr ""
+
+#: ../modules/callmonitor.module:313 ../modules/voicemail.module:477
+msgid "none"
+msgstr ""
+
+#: ../modules/callmonitor.module:533
+msgid "Only deletes recording files, not cdr log"
+msgstr ""
+
+#: ../modules/conference.module:55
+msgid "My Conference room"
+msgstr ""
+
+#: ../modules/conference.module:78
+#, fuzzy, php-format
+msgid "Conference for %s (%s%s)"
+msgstr "Voicemail para"
+
+#: ../modules/help.module:39 ../modules/help.module:68
+msgid "Help"
+msgstr ""
+
+#: ../modules/help.module:70
+#, fuzzy, php-format
+msgid "Help for %s (%s)"
+msgstr "Configurações para"
+
+#: ../modules/help.module:77
+msgid "Handset Feature Code"
+msgstr ""
+
+#: ../modules/help.module:80
+msgid "Action"
+msgstr ""
+
+#: ../modules/settings.module:61 ../modules/settings.module:667
+msgid "Settings"
+msgstr "Configurações"
+
+#: ../modules/settings.module:125
+msgid "Call forward number not changed"
+msgstr ""
+
+#: ../modules/settings.module:126
+#, php-format
+msgid ""
+"Number %s must contain dial numbers (characters like '(', '-', and ')' are "
+"ok)"
+msgstr ""
+
+#: ../modules/settings.module:151 ../modules/settings.module:156
+#: ../modules/settings.module:161 ../modules/settings.module:166
+#: ../modules/settings.module:176 ../modules/settings.module:181
+msgid "Voicemail password not changed"
+msgstr "Senha do Voicemail não alterada"
+
+#: ../modules/settings.module:152
+msgid "Password and password confirm must not be blank"
+msgstr "Senha e confirmação de senha não pode ser não pode estar em branco"
+
+#: ../modules/settings.module:157
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and greater than %d digits"
+msgstr "A senha deve conter apenas números e apenas 4 dígitos"
+
+#: ../modules/settings.module:162
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and only %d digits"
+msgstr "A senha deve conter apenas números e apenas 4 dígitos"
+
+#: ../modules/settings.module:167
+msgid "Password and password confirm do not match"
+msgstr "Senha e confirmação de senha não batem"
+
+#: ../modules/settings.module:177 ../modules/settings.module:182
+#: ../modules/settings.module:234 ../modules/settings.module:239
+#, fuzzy, php-format
+msgid "%s does not exist or is not writable"
+msgstr "não existe ou não tem permissão de escrita"
+
+#: ../modules/settings.module:223
+#, fuzzy
+msgid "Voicemail email and pager address not changed"
+msgstr "Senha do Voicemail não alterada"
+
+#: ../modules/settings.module:233 ../modules/settings.module:238
+#, fuzzy
+msgid "Voicemail email settings not changed"
+msgstr "Senha do Voicemail não alterada"
+
+#: ../modules/settings.module:385
+msgid "Language:"
+msgstr ""
+
+#: ../modules/settings.module:408
+#, fuzzy
+msgid "Call Routing"
+msgstr "Monitor de ligações para"
+
+#: ../modules/settings.module:411
+#, fuzzy
+msgid "Call Forwarding:"
+msgstr "Monitor de ligações para"
+
+#: ../modules/settings.module:419 ../modules/settings.module:507
+msgid "Enable"
+msgstr ""
+
+#: ../modules/settings.module:431
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and only %s digits"
+msgstr "A senha deve conter apenas números e apenas 4 dígitos"
+
+#: ../modules/settings.module:434
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and at least %s digits"
+msgstr "A senha deve conter apenas números e apenas 4 dígitos"
+
+#: ../modules/settings.module:439
+#, fuzzy
+msgid "Voicemail Password:"
+msgstr "Voicemail para"
+
+#: ../modules/settings.module:445
+msgid "Enter again to confirm:"
+msgstr ""
+
+#: ../modules/settings.module:492
+#, fuzzy
+msgid "Email Voicemail To:"
+msgstr "Voicemail para"
+
+#: ../modules/settings.module:498
+#, fuzzy
+msgid "Pager Voicemail To:"
+msgstr "Voicemail para"
+
+#: ../modules/settings.module:558
+msgid "Audio Format:"
+msgstr ""
+
+#: ../modules/settings.module:561
+msgid "Best Quality"
+msgstr ""
+
+#: ../modules/settings.module:562
+msgid "Smallest Download"
+msgstr ""
+
+#: ../modules/settings.module:570
+#, fuzzy
+msgid "Voicemail Settings"
+msgstr "Voicemail para"
+
+#: ../modules/settings.module:611
+#, fuzzy
+msgid "Call Monitor Settings"
+msgstr "Monitor de ligações para"
+
+#: ../modules/settings.module:614
+msgid "Record INCOMING:"
+msgstr ""
+
+#: ../modules/settings.module:616 ../modules/settings.module:624
+msgid "Always"
+msgstr ""
+
+#: ../modules/settings.module:617 ../modules/settings.module:625
+msgid "Never"
+msgstr ""
+
+#: ../modules/settings.module:618 ../modules/settings.module:626
+msgid "On-Demand"
+msgstr ""
+
+#: ../modules/settings.module:622
+msgid "Record OUTGOING:"
+msgstr ""
+
+#: ../modules/settings.module:669
+#, fuzzy, php-format
+msgid "Settings for %s (%s)"
+msgstr "Configurações para"
+
+#: ../modules/settings.module:705
+msgid "Update"
+msgstr ""
+
+#: ../modules/voicemail.module:45
+#, fuzzy
+msgid "Voicemail"
+msgstr "Voicemail para"
+
+#: ../modules/voicemail.module:164
+msgid "A folder must be selected before the message can be moved."
+msgstr "Uma pasta deve ser selecionada antes que a mensagem possa ser movida."
+
+#: ../modules/voicemail.module:178
+msgid "An extension must be selected before the message can be forwarded."
+msgstr ""
+"Uma extensão deve ser selecionada antes que a mensagem possa ser repassada."
+
+#: ../modules/voicemail.module:304
+msgid "move_to"
+msgstr ""
+
+#: ../modules/voicemail.module:307
+msgid "Folder"
+msgstr ""
+
+#: ../modules/voicemail.module:311
+msgid "forward_to"
+msgstr ""
+
+#: ../modules/voicemail.module:328
+msgid "Priority"
+msgstr ""
+
+#: ../modules/voicemail.module:330
+msgid "Orig Mailbox"
+msgstr ""
+
+#: ../modules/voicemail.module:362
+msgid "Message"
+msgstr ""
+
+#: ../modules/voicemail.module:377
+msgid "Voicemail recording(s) was not found."
+msgstr "Gravação do(s) Voicemail(s) não encontrada."
+
+#: ../modules/voicemail.module:378
+#, php-format
+msgid ""
+"On settings page, change voicemail audio format. It is currently set to %s"
+msgstr ""
+
+#: ../modules/voicemail.module:405
+#, fuzzy
+msgid "Voicemail Login not found."
+msgstr "Login do Voicemail não encontrado, utilizado login SIP"
+
+#: ../modules/voicemail.module:406
+msgid "No access to voicemail"
+msgstr "Sem acesso ao voicemail"
+
+#: ../modules/voicemail.module:412
+msgid "No Voicemail Recordings for Admin"
+msgstr "Sem gravações para Admin"
+
+#: ../modules/voicemail.module:428
+#, fuzzy, php-format
+msgid "Voicemail for %s (%s)"
+msgstr "Voicemail para"
+
+#: ../modules/voicemail.module:678
+#, fuzzy, php-format
+msgid "Could not create mailbox folder %s on the server"
+msgstr "Não foi possível criar caixa de mensagens"
+
+#: ../modules/voicemail.module:718
+#, php-format
+msgid "Permission denied on folder %s or %s"
+msgstr ""
+
+#: ../misc/recording_popup.php:39
+msgid "download"
+msgstr ""
+
+#, fuzzy
+#~ msgid "Passwords must be all numbers and only 4 digits"
+#~ msgstr "A senha deve conter apenas números e apenas 4 dígitos"
+
+#, fuzzy
+#~ msgid "No Asterisk Manager Interface connection"
+#~ msgstr "Asterisk Call Manager não responde"
+
+#~ msgid "not a directory or not readable"
+#~ msgstr "não é um diretório ou não pode ser lido"
+
+#~ msgid "of"
+#~ msgstr "de"
+
+#~ msgid "Use your"
+#~ msgstr "Use seu"
+
+#~ msgid "Password must be all numbers and 4 digits"
+#~ msgstr "A senha deve conter apenas números e apenas 4 dígitos"
+
+#~ msgid "Check voicemail audio format on settings page to change from"
+#~ msgstr ""
+#~ "Verifique o formato do audio do voicemail na página de configurações para "
+#~ "mudar de"
+
+#~ msgid "on the server"
+#~ msgstr "no servidor"
+
+#~ msgid "No database connection"
+#~ msgstr "Sem conexão com o banco de dados"
diff --git a/fs_selfservice/fri/locale/readme.txt b/fs_selfservice/fri/locale/readme.txt
new file mode 100644
index 000000000..24918654b
--- /dev/null
+++ b/fs_selfservice/fri/locale/readme.txt
@@ -0,0 +1,37 @@
+// To create the .po (write your translations to this file):
+$ find *.php ../includes/* ../modules/*.module ../misc/*.php ../theme/* | xargs xgettext -L PHP -o ari.po --keyword=_ -
+
+// To create the utf-8 .po
+$ iconv -f iso-8859-1 -t utf-8 -o ari.utf-8.po ari.po
+
+// To create the .mo:
+$ msgfmt -v ari.utf-8.po -o ari.mo
+
+// To update (assume both files to be merged are utf-8)
+$ msgmerge es_ES/LC_MESSAGES/ari.po ari.utf-8.po --output-file=es_ES/LC_MESSAGES/ari.po
+$ msgfmt -v es_ES/LC_MESSAGES/ari.po -o es_ES/LC_MESSAGES/ari.mo
+
+
+// script
+// for this to work all translated files need to be converted to utf-8 (use iconv)
+//
+find *.php ../includes/* ../modules/*.module ../misc/*.php ../theme/* | xargs xgettext -L PHP -o ari.po --keyword=_ -
+iconv -f iso-8859-1 -t utf-8 -o ari.utf-8.po ari.po
+msgmerge el_GR/LC_MESSAGES/ari.po ari.utf-8.po --output-file=el_GR/LC_MESSAGES/ari.po
+msgfmt -v el_GR/LC_MESSAGES/ari.po -o el_GR/LC_MESSAGES/ari.mo
+msgmerge es_ES/LC_MESSAGES/ari.po ari.utf-8.po --output-file=es_ES/LC_MESSAGES/ari.po
+msgfmt -v es_ES/LC_MESSAGES/ari.po -o es_ES/LC_MESSAGES/ari.mo
+msgmerge fr_FR/LC_MESSAGES/ari.po ari.utf-8.po --output-file=fr_FR/LC_MESSAGES/ari.po
+msgfmt -v fr_FR/LC_MESSAGES/ari.po -o fr_FR/LC_MESSAGES/ari.mo
+msgmerge he_IL/LC_MESSAGES/ari.po ari.utf-8.po --output-file=he_IL/LC_MESSAGES/ari.po
+msgfmt -v he_IL/LC_MESSAGES/ari.po -o he_IL/LC_MESSAGES/ari.mo
+msgmerge hu_HU/LC_MESSAGES/ari.po ari.utf-8.po --output-file=hu_HU/LC_MESSAGES/ari.po
+msgfmt -v hu_HU/LC_MESSAGES/ari.po -o hu_HU/LC_MESSAGES/ari.mo
+msgmerge it_IT/LC_MESSAGES/ari.po ari.utf-8.po --output-file=it_IT/LC_MESSAGES/ari.po
+msgfmt -v ot_IT/LC_MESSAGES/ari.po -o it_IT/LC_MESSAGES/ari.mo
+msgmerge pt_BR/LC_MESSAGES/ari.po ari.utf-8.po --output-file=pt_BR/LC_MESSAGES/ari.po
+msgfmt -v pt_BR/LC_MESSAGES/ari.po -o pt_BR/LC_MESSAGES/ari.mo
+msgmerge sv_SE/LC_MESSAGES/ari.po ari.utf-8.po --output-file=sv_SE/LC_MESSAGES/ari.po
+msgfmt -v sv_SE/LC_MESSAGES/ari.po -o sv_SE/LC_MESSAGES/ari.mo
+
+
diff --git a/fs_selfservice/fri/locale/sv_SE/LC_MESSAGES/ari.mo b/fs_selfservice/fri/locale/sv_SE/LC_MESSAGES/ari.mo
new file mode 100644
index 000000000..c8ea15216
--- /dev/null
+++ b/fs_selfservice/fri/locale/sv_SE/LC_MESSAGES/ari.mo
Binary files differ
diff --git a/fs_selfservice/fri/locale/sv_SE/LC_MESSAGES/ari.po b/fs_selfservice/fri/locale/sv_SE/LC_MESSAGES/ari.po
new file mode 100644
index 000000000..f8f0ad324
--- /dev/null
+++ b/fs_selfservice/fri/locale/sv_SE/LC_MESSAGES/ari.po
@@ -0,0 +1,678 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2006-05-03 08:32-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: Niklas Larsson <pnsystem@comhem.se>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../includes/asi.php:46
+msgid "Asterisk Call Manager not responding"
+msgstr "Asterisk Call Manager svara ej"
+
+#: ../includes/asi.php:54
+msgid "Asterisk authentication failed:"
+msgstr "Ej godk&auml;nd autentisering mot Asterisk:"
+
+#: ../includes/asi.php:96 ../includes/asi.php:111
+#, fuzzy
+msgid "Asterisk command not understood"
+msgstr "Asterisk f&ouml;rstod ej omladdningskommandot"
+
+#: ../includes/bootstrap.php:123
+#, php-format
+msgid "To many directories in %s Not all files processed"
+msgstr "F&ouml;r m&aring;nga mappar i %s Alla filer har inte behandlats"
+
+#: ../includes/bootstrap.php:226
+#, fuzzy
+msgid "ARI requires a version of PHP 4.3 or later"
+msgstr "ARI kr&auml;ver version 4.0 eller h&ouml;gre av PHP"
+
+#: ../includes/bootstrap.php:245
+msgid ""
+"PHP PEAR must be installed. Visit http://pear.php.net for help with "
+"installation."
+msgstr ""
+"PHP PEAR m&aring;ste installeras. G&aring; till http://pear.php.net, och "
+"installera."
+
+#: ../includes/common.php:173
+#, fuzzy
+msgid "ARI does not appear to have access to the Asterisk Manager."
+msgstr "Kan ej ansluta till Asterisk Manager"
+
+#: ../includes/common.php:174
+#, fuzzy
+msgid ""
+"Check the ARI 'main.conf.php' configuration file to set the Asterisk Manager "
+"Account."
+msgstr ""
+"Kontrollera ARI 'main.conf' filen och inst&auml;llningarna f&ouml;r Asterisk "
+"Manager kontot."
+
+#: ../includes/common.php:175
+#, fuzzy
+msgid "Check /etc/asterisk/manager.conf for a proper Asterisk Manager Account"
+msgstr ""
+"Kontrollera /etc/asterisk/manager.conf, se till att det finns ett korrekt "
+"Asterisk Manager konto"
+
+#: ../includes/common.php:176
+#, fuzzy
+msgid ""
+"make sure [general] enabled = yes and a 'permit=' line for localhost or the "
+"webserver."
+msgstr ""
+" som bla har [general] enabled = yes och en 'permit=' f&ouml;r localhost "
+"eller ip nummret f&ouml;r webservern"
+
+#: ../includes/common.php:193 ../includes/common.php:208
+#, fuzzy
+msgid "Check AMP installation, asterisk, and ARI main.conf"
+msgstr "Kontrollera AMP installationen, asterisk databas eller ARI main.conf"
+
+#: ../includes/common.php:344
+msgid "Logout"
+msgstr "Logga ut"
+
+#: ../includes/common.php:349
+msgid "Page Not Found."
+msgstr "Sidan hittas ej."
+
+#: ../includes/display.php:92
+msgid "Search"
+msgstr "S&ouml;k"
+
+#: ../includes/display.php:135
+msgid "Searched for"
+msgstr "S&ouml;kte efter"
+
+#: ../includes/display.php:139
+#, fuzzy, php-format
+msgid "Results %d - %d of %d"
+msgstr "Resultat %d av %d"
+
+#: ../includes/display.php:141
+#, fuzzy, php-format
+msgid "Results %d"
+msgstr "Resultat %d"
+
+#: ../includes/display.php:195
+msgid "First"
+msgstr "F&ouml;rst"
+
+#: ../includes/display.php:208
+msgid "Last"
+msgstr "Sist"
+
+#: ../includes/login.php:267
+msgid "Incorrect Password"
+msgstr "Felaktigt l&ouml;senord"
+
+#: ../includes/login.php:279
+msgid "Incorrect Username or Password"
+msgstr "Felaktigt l&ouml;senord"
+
+#: ../includes/login.php:402 ../includes/login.php:411
+msgid "Login"
+msgstr "Anv&auml;ndarnamn"
+
+#: ../includes/login.php:419
+msgid "Password"
+msgstr "L&ouml;senord"
+
+#: ../includes/login.php:428
+msgid "Submit"
+msgstr "Logga in"
+
+#: ../includes/login.php:436
+msgid "Remember Password"
+msgstr "Kom ih&aring;g l&ouml;senord"
+
+#: ../includes/login.php:451
+#, fuzzy
+msgid "Use your <b>Voicemail Mailbox and Password</b>"
+msgstr ""
+"Anv&auml;nd din <b>R&ouml;stbrevl&aring;das nummer och l&ouml;senord</b>"
+
+#: ../includes/login.php:452
+msgid "This is the same password used for the phone"
+msgstr "Det &auml;r samma l&ouml;senord som till din telefon"
+
+#: ../includes/login.php:454
+msgid ""
+"For password maintenance or assistance, contact your Phone System "
+"Administrator."
+msgstr ""
+"Om du har problem med l&ouml;senord eller beh&ouml;ver hj&auml;lp ska du "
+"kontakta din v&auml;xel ansvarig"
+
+#: ../includes/main.conf.php:152
+msgid "INBOX"
+msgstr "Inbox"
+
+#: ../includes/main.conf.php:154
+msgid "Family"
+msgstr "Familj"
+
+#: ../includes/main.conf.php:156
+msgid "Friends"
+msgstr "V&auml;nner"
+
+#: ../includes/main.conf.php:158
+msgid "Old"
+msgstr "Gamla"
+
+#: ../includes/main.conf.php:160
+msgid "Work"
+msgstr "Arbete"
+
+#: ../includes/main.conf.php:229
+msgid "Directory"
+msgstr "Katalog"
+
+#: ../includes/main.conf.php:230
+msgid "Echo Test"
+msgstr "Eko test"
+
+#: ../includes/main.conf.php:231 ../modules/callmonitor.module:161
+#: ../modules/voicemail.module:324
+msgid "Time"
+msgstr "Tid"
+
+#: ../includes/main.conf.php:232
+msgid "Weather"
+msgstr "V&auml;der"
+
+#: ../includes/main.conf.php:233
+msgid "Schedule wakeup call"
+msgstr "Schemal&auml;gg v&auml;ckningssamtal"
+
+#: ../includes/main.conf.php:234
+msgid "festival test (your extension is XXX)"
+msgstr "Festival test (din anknytning &auml;r XXX)"
+
+#: ../includes/main.conf.php:235
+msgid "Activate Call Waiting (deactivated by default)"
+msgstr "Aktivera Samtal V&auml;ntar"
+
+#: ../includes/main.conf.php:236
+msgid "Deactivate Call Waiting"
+msgstr "Avaktivera Samtal V&auml;ntar"
+
+#: ../includes/main.conf.php:237
+msgid "Call Forwarding System"
+msgstr "Vidarekoppla"
+
+#: ../includes/main.conf.php:238
+msgid "Disable Call Forwarding"
+msgstr "Avaktivera vidarekoppling"
+
+#: ../includes/main.conf.php:239
+#, fuzzy
+msgid "IVR Recording"
+msgstr "R&ouml;stmeny inspelning"
+
+#: ../includes/main.conf.php:240
+msgid "Enable Do-Not-Disturb"
+msgstr "Aktivera St&ouml;r Ej"
+
+#: ../includes/main.conf.php:241
+msgid "Disable Do-Not-Disturb"
+msgstr "Avaktivera St&ouml;r Ej"
+
+#: ../includes/main.conf.php:242
+msgid "Call Forward on Busy"
+msgstr "Vidarekoppla vid upptaget"
+
+#: ../includes/main.conf.php:243
+msgid "Disable Call Forward on Busy"
+msgstr "Avaktivera vidarekoppla vid upptaget"
+
+#: ../includes/main.conf.php:244
+#, fuzzy
+msgid "Message Center (does not ask for extension)"
+msgstr "R&ouml;stbrevl&aring;da (fr&aring;ga ej efter anknytning)"
+
+#: ../includes/main.conf.php:245
+msgid "Enter Message Center"
+msgstr "G&aring; till r&ouml;stbrevl&aring;dan"
+
+#: ../includes/main.conf.php:246
+msgid "Playback IVR Recording"
+msgstr "Spela upp r&ouml;stmeny"
+
+#: ../includes/main.conf.php:247
+msgid "Test Fax"
+msgstr "Fax test"
+
+#: ../includes/main.conf.php:248
+msgid "Simulate incoming call"
+msgstr "Simulera inkommande samtal"
+
+#: ../includes/main.conf.php:289
+msgid "Email voicemail as attachment"
+msgstr "Bifoga meddeladen i E-Post"
+
+#: ../includes/main.conf.php:290
+msgid "Say caller id in recording emailed"
+msgstr "L&auml;ser upp nummret i meddelandet"
+
+#: ../includes/main.conf.php:291
+#, fuzzy
+msgid "Say envelop (date/time) in recording emailed"
+msgstr "L&auml;ser upp informationen i meddelandet"
+
+#: ../includes/main.conf.php:292
+msgid "Delete voicemail when emailed"
+msgstr "Radera meddelandet n&auml;r det e-postats"
+
+#: ../includes/main.conf.php:293
+msgid "Play next message after deleting current message"
+msgstr "Spelar upp n&auml;sta eftera att ha raderat nuvarande"
+
+#: ../includes/main.conf.php:294
+msgid "Ask caller to review their voicemail before sending"
+msgstr ""
+
+#: ../includes/main.conf.php:295
+msgid "Maximum time in seconds a voicemail will record"
+msgstr ""
+
+#: ../modules/callmonitor.module:37 ../modules/callmonitor.module:257
+msgid "Call Monitor"
+msgstr "Samtalsregister"
+
+#: ../modules/callmonitor.module:132
+#, php-format
+msgid "Path is not a directory: %s"
+msgstr "S&oulm;kv&auml;gen leder ej till en mapp: %s"
+
+#: ../modules/callmonitor.module:141 ../modules/voicemail.module:301
+msgid "delete"
+msgstr "Radera"
+
+#: ../modules/callmonitor.module:147
+#, fuzzy
+msgid "duration"
+msgstr "L&auml;ngd"
+
+#: ../modules/callmonitor.module:150
+#, fuzzy
+msgid "ignore"
+msgstr "ignorera"
+
+#: ../modules/callmonitor.module:159 ../modules/voicemail.module:322
+msgid "Date"
+msgstr "Datum"
+
+#: ../modules/callmonitor.module:163 ../modules/voicemail.module:326
+msgid "Caller ID"
+msgstr "Nummerpresentation"
+
+#: ../modules/callmonitor.module:165
+msgid "Source"
+msgstr "K&auml;lla"
+
+#: ../modules/callmonitor.module:167
+msgid "Destination"
+msgstr "M&aring;l"
+
+#: ../modules/callmonitor.module:169
+msgid "Context"
+msgstr "Sammanhang"
+
+#: ../modules/callmonitor.module:171 ../modules/voicemail.module:332
+msgid "Duration"
+msgstr "L&auml;ngd"
+
+#: ../modules/callmonitor.module:202
+msgid "Monitor"
+msgstr "Inspelning"
+
+#: ../modules/callmonitor.module:222 ../modules/voicemail.module:373
+msgid "play"
+msgstr "spela"
+
+#: ../modules/callmonitor.module:259
+#, fuzzy, php-format
+msgid "Call Monitor for %s (%s)"
+msgstr "Samtalsregister f&ouml;r %s (%s)"
+
+#: ../modules/callmonitor.module:311 ../modules/voicemail.module:475
+msgid "select"
+msgstr "Val"
+
+#: ../modules/callmonitor.module:312 ../modules/voicemail.module:476
+msgid "all"
+msgstr "alla"
+
+#: ../modules/callmonitor.module:313 ../modules/voicemail.module:477
+msgid "none"
+msgstr "inga"
+
+#: ../modules/callmonitor.module:533
+msgid "Only deletes recording files, not cdr log"
+msgstr "Raderar endast inspelade filer, inte samtalsloggen"
+
+#: ../modules/conference.module:55
+msgid "My Conference room"
+msgstr ""
+
+#: ../modules/conference.module:78
+#, fuzzy, php-format
+msgid "Conference for %s (%s%s)"
+msgstr "R&ouml;stbrevl&aring;da f&ouml;r %s (%s)"
+
+#: ../modules/help.module:39 ../modules/help.module:68
+msgid "Help"
+msgstr "Hj&auml;lp"
+
+#: ../modules/help.module:70
+#, php-format
+msgid "Help for %s (%s)"
+msgstr "Hj&auml;lp f&ouml;r %s (%s)"
+
+#: ../modules/help.module:77
+msgid "Handset Feature Code"
+msgstr "Kortkoder"
+
+#: ../modules/help.module:80
+msgid "Action"
+msgstr "Utf&ouml;r"
+
+#: ../modules/settings.module:61 ../modules/settings.module:667
+msgid "Settings"
+msgstr "Inst&auml;llningar"
+
+#: ../modules/settings.module:125
+msgid "Call forward number not changed"
+msgstr "Vidarekopplingsnummret ej &auml;ndrat"
+
+#: ../modules/settings.module:126
+#, php-format
+msgid ""
+"Number %s must contain dial numbers (characters like '(', '-', and ')' are "
+"ok)"
+msgstr ""
+"Nummer %s ska inneh&aring;lla nummer (tecknen; '(', '-' och ')' &auml;r "
+"till&aring;tna"
+
+#: ../modules/settings.module:151 ../modules/settings.module:156
+#: ../modules/settings.module:161 ../modules/settings.module:166
+#: ../modules/settings.module:176 ../modules/settings.module:181
+msgid "Voicemail password not changed"
+msgstr "L&ouml;senord f&ouml;r r&ouml;stbrevl&aring;dan har inte &auml;ndrats"
+
+#: ../modules/settings.module:152
+msgid "Password and password confirm must not be blank"
+msgstr ""
+"L&ouml;senord och bekr&auml;fta l&ouml;senord f&aring;r inte vara tomma"
+
+#: ../modules/settings.module:157
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and greater than %d digits"
+msgstr "L&ouml;senordet m&aring;ste vara %d siffror"
+
+#: ../modules/settings.module:162
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and only %d digits"
+msgstr "L&ouml;senordet m&aring;ste vara %d siffror"
+
+#: ../modules/settings.module:167
+msgid "Password and password confirm do not match"
+msgstr "L&ouml;senord och bekr&auml;ftat l&ouml;senord st&auml;mmer inte"
+
+#: ../modules/settings.module:177 ../modules/settings.module:182
+#: ../modules/settings.module:234 ../modules/settings.module:239
+#, fuzzy, php-format
+msgid "%s does not exist or is not writable"
+msgstr "%s finns ej eller &auml;r ej l&auml;sbar"
+
+#: ../modules/settings.module:223
+#, fuzzy
+msgid "Voicemail email and pager address not changed"
+msgstr "L&ouml;senord f&ouml;r r&ouml;stbrevl&aring;dan har inte &auml;ndrats"
+
+#: ../modules/settings.module:233 ../modules/settings.module:238
+#, fuzzy
+msgid "Voicemail email settings not changed"
+msgstr "L&ouml;senord f&ouml;r r&ouml;stbrevl&aring;dan har inte &auml;ndrats"
+
+#: ../modules/settings.module:385
+msgid "Language:"
+msgstr "Spr&aring;k:"
+
+#: ../modules/settings.module:408
+#, fuzzy
+msgid "Call Routing"
+msgstr "Inst&auml;llningar f&ouml;r Vidarekoppling"
+
+#: ../modules/settings.module:411
+#, fuzzy
+msgid "Call Forwarding:"
+msgstr "Vidarekoppling"
+
+#: ../modules/settings.module:419 ../modules/settings.module:507
+#, fuzzy
+msgid "Enable"
+msgstr "Aktivera"
+
+#: ../modules/settings.module:431
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and only %s digits"
+msgstr "L&ouml;senordet m&aring;ste vara %s siffror"
+
+#: ../modules/settings.module:434
+#, fuzzy, php-format
+msgid "Passwords must be all numbers and at least %s digits"
+msgstr "L&ouml;senordet m&aring;ste vara %s siffror"
+
+#: ../modules/settings.module:439
+#, fuzzy
+msgid "Voicemail Password:"
+msgstr "L&ouml;senord f&ouml;r r&ouml;stbrevl&aring;da"
+
+#: ../modules/settings.module:445
+msgid "Enter again to confirm:"
+msgstr "Bekr&auml;fta:"
+
+#: ../modules/settings.module:492
+#, fuzzy
+msgid "Email Voicemail To:"
+msgstr "R&ouml;stbrevl&aring;da"
+
+#: ../modules/settings.module:498
+#, fuzzy
+msgid "Pager Voicemail To:"
+msgstr "R&ouml;stbrevl&aring;da"
+
+#: ../modules/settings.module:558
+msgid "Audio Format:"
+msgstr "Ljud format:"
+
+#: ../modules/settings.module:561
+msgid "Best Quality"
+msgstr "B&auml;sta kvaliten"
+
+#: ../modules/settings.module:562
+msgid "Smallest Download"
+msgstr "Minsta storlek"
+
+#: ../modules/settings.module:570
+msgid "Voicemail Settings"
+msgstr "Inst&auml;llningar f&ouml;r R&ouml;stbrevl&aring;da"
+
+#: ../modules/settings.module:611
+msgid "Call Monitor Settings"
+msgstr "Inst&auml;llningar f&ouml;r Samtalsregister"
+
+#: ../modules/settings.module:614
+msgid "Record INCOMING:"
+msgstr "Spela in inkommande samtal:"
+
+#: ../modules/settings.module:616 ../modules/settings.module:624
+msgid "Always"
+msgstr "Alltid"
+
+#: ../modules/settings.module:617 ../modules/settings.module:625
+msgid "Never"
+msgstr "Aldrig"
+
+#: ../modules/settings.module:618 ../modules/settings.module:626
+msgid "On-Demand"
+msgstr "Vid behov"
+
+#: ../modules/settings.module:622
+msgid "Record OUTGOING:"
+msgstr "Spela in utg&aring;ende samtal:"
+
+#: ../modules/settings.module:669
+#, fuzzy, php-format
+msgid "Settings for %s (%s)"
+msgstr "Inst&auml;llningar f&ouml;r %s (%s)"
+
+#: ../modules/settings.module:705
+msgid "Update"
+msgstr "Uppdatera"
+
+#: ../modules/voicemail.module:45
+msgid "Voicemail"
+msgstr "R&ouml;stbrevl&aring;da"
+
+#: ../modules/voicemail.module:164
+msgid "A folder must be selected before the message can be moved."
+msgstr "En mapp m&aring;sta v&auml;ljas innan meddelandet kan flyttas."
+
+#: ../modules/voicemail.module:178
+msgid "An extension must be selected before the message can be forwarded."
+msgstr ""
+"En anknytning m&aring;ste v&auml;ljas innan meddelandet kan vidarebefodras."
+
+#: ../modules/voicemail.module:304
+msgid "move_to"
+msgstr "Flytta till"
+
+#: ../modules/voicemail.module:307
+#, fuzzy
+msgid "Folder"
+msgstr "Mappar"
+
+#: ../modules/voicemail.module:311
+msgid "forward_to"
+msgstr "Vidarebefodra till"
+
+#: ../modules/voicemail.module:328
+msgid "Priority"
+msgstr "Prioritet"
+
+#: ../modules/voicemail.module:330
+msgid "Orig Mailbox"
+msgstr "Ursprunglig r&ouml;stbrevl&aring;da"
+
+#: ../modules/voicemail.module:362
+msgid "Message"
+msgstr "Meddelande"
+
+#: ../modules/voicemail.module:377
+msgid "Voicemail recording(s) was not found."
+msgstr "R&ouml;stmeddelande hittades inte."
+
+#: ../modules/voicemail.module:378
+#, php-format
+msgid ""
+"On settings page, change voicemail audio format. It is currently set to %s"
+msgstr ""
+"P&aring; inst&auml;llningssidan, &auml;ndra r&ouml;stbrevl&aring;dans "
+"ljudformat. Det &auml;r nu %s"
+
+#: ../modules/voicemail.module:405
+#, fuzzy
+msgid "Voicemail Login not found."
+msgstr "Hittar inte r&ouml;stbrevl&aring;da."
+
+#: ../modules/voicemail.module:406
+msgid "No access to voicemail"
+msgstr "Inget tilltr&auml;de till r&ouml;stbrevl&aring;dan"
+
+#: ../modules/voicemail.module:412
+msgid "No Voicemail Recordings for Admin"
+msgstr "Inga r&ouml;stmeddelande f&ouml;r Admin"
+
+#: ../modules/voicemail.module:428
+#, fuzzy, php-format
+msgid "Voicemail for %s (%s)"
+msgstr "R&ouml;stbrevl&aring;da f&ouml;r %s (%s)"
+
+#: ../modules/voicemail.module:678
+#, fuzzy, php-format
+msgid "Could not create mailbox folder %s on the server"
+msgstr "Kan inte skapa mapp f&ouml;r r&ouml;stbrevl&aring;da"
+
+#: ../modules/voicemail.module:718
+#, php-format
+msgid "Permission denied on folder %s or %s"
+msgstr "Saknar r&auml;ttigheter f&ouml;r mappen %s eller %s"
+
+#: ../misc/recording_popup.php:39
+msgid "download"
+msgstr "ladda ner"
+
+#~ msgid "Folders"
+#~ msgstr "Mappar"
+
+#~ msgid "Version"
+#~ msgstr "Version"
+
+#~ msgid "Passwords must be all numbers and only 4 digits"
+#~ msgstr "L&ouml;senordet m&aring;ste vara 4 siffror"
+
+#~ msgid "Unable to connect to Asterisk Manager"
+#~ msgstr "Kan ej ansluta till Asterisk Manager"
+
+#, fuzzy
+#~ msgid "No Asterisk Manager Interface connection"
+#~ msgstr "Asterisk Call Manager svara ej"
+
+#~ msgid "of"
+#~ msgstr "av"
+
+#~ msgid "Login used"
+#~ msgstr "Anv&auml;nd Login"
+
+#~ msgid "help"
+#~ msgstr "hj&auml;lp"
+
+#~ msgid "not a directory or not readable"
+#~ msgstr "inte en mapp eller ej l&auml;sbar"
+
+#~ msgid "Use your"
+#~ msgstr "Anv&auml;nd din"
+
+#~ msgid "for"
+#~ msgstr "f&ouml;r"
+
+#~ msgid "Password must be all numbers and 4 digits"
+#~ msgstr "L&ouml;senordet m&aring;ste vara 4 siffror"
+
+#~ msgid "Check voicemail audio format on settings page to change from"
+#~ msgstr ""
+#~ "&Auml;ndra inst&auml;llningar f&ouml;r r&ouml;stbrevl&aring;dans ljud "
+#~ "format f&ouml;r att &auml;ndra fr&aring;n"
+
+#~ msgid "on the server"
+#~ msgstr "p&aring; servern"
+
+#~ msgid "No database connection"
+#~ msgstr "Ingen kontakt med databasen"
diff --git a/fs_selfservice/fri/misc/audio.php b/fs_selfservice/fri/misc/audio.php
new file mode 100644
index 000000000..2dc355cb3
--- /dev/null
+++ b/fs_selfservice/fri/misc/audio.php
@@ -0,0 +1,61 @@
+<?php
+
+/**
+ * @file
+ * plays recording file
+ */
+
+
+
+if (isset($_GET['recording'])) {
+
+ chdir("..");
+ include_once("./includes/bootstrap.php");
+
+ global $ARI_CRYPT_PASSWORD;
+
+ $crypt = new Crypt();
+
+ $path = $crypt->decrypt($_GET['recording'],$ARI_CRYPT_PASSWORD);
+
+ // strip ".." from path for security
+ $path = preg_replace('/\.\./','',$path);
+
+ // See if the file exists
+ if (!is_file($path)) { die("<b>404 File not found!</b>"); }
+
+ // Gather relevent info about file
+ $size = filesize($path);
+ $name = basename($path);
+ $extension = strtolower(substr(strrchr($name,"."),1));
+
+ // This will set the Content-Type to the appropriate setting for the file
+ $ctype ='';
+ switch( $extension ) {
+ case "mp3": $ctype="audio/mpeg"; break;
+ case "wav": $ctype="audio/x-wav"; break;
+ case "Wav": $ctype="audio/x-wav"; break;
+ case "WAV": $ctype="audio/x-wav"; break;
+ case "gsm": $ctype="audio/x-gsm"; break;
+
+ // not downloadable
+ default: die("<b>404 File not found!</b>"); break ;
+ }
+
+ // need to check if file is mislabeled or a liar.
+ $fp=fopen($path, "rb");
+ if ($size && $ctype && $fp) {
+ header("Pragma: public");
+ header("Expires: 0");
+ header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
+ header("Cache-Control: public");
+ header("Content-Description: wav file");
+ header("Content-Type: " . $ctype);
+ header("Content-Disposition: attachment; filename=" . $name);
+ header("Content-Transfer-Encoding: binary");
+ header("Content-length: " . $size);
+ fpassthru($fp);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/fs_selfservice/fri/misc/popup.css b/fs_selfservice/fri/misc/popup.css
new file mode 100644
index 000000000..7a5352805
--- /dev/null
+++ b/fs_selfservice/fri/misc/popup.css
@@ -0,0 +1,10 @@
+/*
+ * popup
+ */
+
+.popup_download {
+ color: #105D90;
+ margin: 250px;
+ font-size: 12px;
+ text-align: right;
+} \ No newline at end of file
diff --git a/fs_selfservice/fri/misc/recording_popup.php b/fs_selfservice/fri/misc/recording_popup.php
new file mode 100644
index 000000000..1546adcc0
--- /dev/null
+++ b/fs_selfservice/fri/misc/recording_popup.php
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * @file
+ * popup window for playing recording
+ */
+
+chdir("..");
+include_once("./includes/bootstrap.php");
+
+?>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <TITLE>ARI</TITLE>
+ <link rel="stylesheet" href="popup.css" type="text/css">
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ </head>
+ <body>
+
+<?php
+
+ global $ARI_CRYPT_PASSWORD;
+
+ $crypt = new Crypt();
+
+ $path = $crypt->encrypt($_GET['recording'],$ARI_CRYPT_PASSWORD);
+
+ if (isset($path)) {
+ if (isset($_GET['date'])) {
+ echo($_GET['date'] . "<br>");
+ }
+ if (isset($_GET['time'])) {
+ echo($_GET['time'] . "<br>");
+ }
+ echo("<br>");
+ echo("<embed src='audio.php?recording=" . $path . "' width=300, height=20 autoplay=true loop=false></embed><br>");
+ echo("<a class='popup_download' href=/recordings/misc/audio.php?recording=" . $path . ">" . _("download") . "</a><br>");
+ }
+
+?>
+
+ </body>
+</html>
+
diff --git a/fs_selfservice/fri/modules.template/blank.module b/fs_selfservice/fri/modules.template/blank.module
new file mode 100644
index 000000000..a3676c433
--- /dev/null
+++ b/fs_selfservice/fri/modules.template/blank.module
@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * @file
+ * Functions for the interface to the help page
+ */
+
+/**
+ * Class for help
+ */
+class blank {
+
+ /*
+ * rank (for prioritizing modules)
+ */
+ function rank() {
+
+ $rank = 8;
+ return $rank;
+ }
+
+ /*
+ * init
+ */
+ function init() {
+ }
+
+ /*
+ * Adds menu item to nav menu
+ *
+ * @param $args
+ * Common arguments
+ */
+ function navMenu($args) {
+
+ $ret .= "<p><small><small><a href='" . $_SESSION['ARI_ROOT'] . "?m=blank&f=display'>" . _("Blank") . "</a></small></small></p><br>";
+
+ return $ret;
+ }
+
+ /*
+ * Displays stats page
+ *
+ * @param $args
+ * Common arguments
+ */
+ function display($args) {
+
+ global $ARI_HELP_FEATURE_CODES;
+
+ $display = new Display();
+
+ // args
+ $m = getArgument($args,'m');
+ $q = getArgument($args,'q');
+
+ $displayname = $_SESSION['ari_user']['displayname'];
+ $extension = $_SESSION['ari_user']['extension'];
+
+ // build page content
+ $ret .= checkErrorMessage();
+
+ $header_text = _("Blank");
+ if (!$_SESSION['ari_user']['admin_help']) {
+ $header_text .= sprintf(_(" for %s (%s)"), $displayname, $extension);
+ }
+
+ // build page content
+ $ret .= checkErrorMessage();
+
+ $ret .= $display->displayHeaderText($header_text);
+ $ret .= $display->displayLine();
+
+ $ret .= 'Blank goes here';
+
+ return $ret;
+ }
+
+}
+
+?>
diff --git a/fs_selfservice/fri/modules/VmX.module b/fs_selfservice/fri/modules/VmX.module
new file mode 100644
index 000000000..61ef653a2
--- /dev/null
+++ b/fs_selfservice/fri/modules/VmX.module
@@ -0,0 +1,661 @@
+<?php
+
+/**
+ * @file
+ * Functions for the interface to the call monitor recordings
+ */
+
+/**
+ * Class for Followme
+ */
+class VmX {
+
+ var $protocol_table;
+ var $protocol_config_files;
+
+ /*
+ * rank (for prioritizing modules)
+ */
+ function rank() {
+
+ $rank = 6;
+ return $rank;
+ }
+
+ /*
+ * init
+ */
+ function init() {
+
+ }
+
+ /*
+ * Adds menu item to nav menu
+ *
+ * @param $args
+ * Common arguments
+ */
+ function navMenu($args) {
+
+ global $SETTINGS_ALLOW_VMX_SETTINGS;
+ global $ARI_ADMIN_USERNAME;
+
+ $ret = "";
+
+ // We are only going to show the menu
+ // if VmX is allowed
+ if ($SETTINGS_ALLOW_VMX_SETTINGS) {
+
+ $exten = $_SESSION['ari_user']['extension'];
+
+ // and we are not logged in as admin
+ if ($exten!=$ARI_ADMIN_USERNAME) {
+
+ $vmx_enabled = $this->getVmxState($exten,'unavail');
+
+ // and vmx is enabled for this user
+ if ($vmx_enabled !== false)
+ $ret .= "<p><small><small><a href='" . $_SESSION['ARI_ROOT'] . "?m=VmX&f=display'>" . _("VmX&#8482 Locator") . "</a></small></small></p>";
+ }
+ }
+
+ return $ret;
+ }
+
+ /*
+ * Acts on the user settings
+ *
+ * @param $args
+ * Common arguments
+ * @param $a
+ * action
+ */
+ function action($args) {
+
+ global $STANDALONE;
+ global $ARI_ADMIN_USERNAME;
+ global $SETTINGS_ALLOW_VMX_SETTINGS;
+
+ // args
+ $m = getArgument($args,'m');
+ $a = getArgument($args,'a');
+
+ $follow_me_disabled = getArgument($args,'follow_me_disabled');
+
+ $vmx_option_0_number = getArgument($args, 'vmx_option_0_number');
+ $vmx_option_0_system_default = getArgument($args, 'vmx_option_0_system_default');
+ $vmx_option_1_number = getArgument($args, 'vmx_option_1_number');
+ $vmx_option_1_system_default = getArgument($args, 'vmx_option_1_system_default');
+ $vmx_option_2_number = getArgument($args, 'vmx_option_2_number');
+ $vmx_unavail_enabled = getArgument($args, 'vmx_unavail_enabled');
+ $vmx_busy_enabled = getArgument($args, 'vmx_busy_enabled');
+ $vmx_play_instructions = getArgument($args, 'vmx_play_instructions');
+ $vmx_disabled = getArgument($args, 'vmx_disabled');
+
+ $exten = $_SESSION['ari_user']['extension'];
+
+ // The action is 'update
+ if ($a=='update') {
+
+ $follow_me_disabled = ($this->getFollowMeListRingTime($exten) > 0)?0:1;
+
+
+ $vmx_disabled = $this->getVmxState($exten,'unavail');
+ if ($vmx_disabled === false) {
+ $vmx_disabled = true;
+ $SETTINGS_ALLOW_VMX_SETTINGS=false;
+ } else {
+ $vmx_disabled = false;
+ }
+ if ($vmx_disabled) {
+
+ setcookie("ari_vmx_disabled", $vmx_disabled, time()+365*24*60*60);
+ $vmx_disabled_delayed = $vmx_disabled;
+ $_SESSION['ari_error'] =
+ _("Your Premium VmX Locator service has been disabled, REFRESH your browser to remove this message") . "<br>" .
+ sprintf(_("Check with your Telephone System Administrator if you think there is a problem"));
+ }
+
+ if (! $vmx_disabled) {
+
+ // set database
+ $this->setVmxState($exten,'unavail',$vmx_unavail_enabled);
+ $this->setVmxState($exten,'busy',$vmx_busy_enabled);
+ $this->setVmxPlayInstructions($exten,'unavail',$vmx_play_instructions);
+ $this->setVmxPlayInstructions($exten,'busy',$vmx_play_instructions);
+
+ // store cookie
+ setcookie("ari_vmx_unavail_enabled", $vmx_unavail_enabled, time()+365*24*60*60);
+ setcookie("ari_vmx_busy_enabled", $vmx_busy_enabled, time()+365*24*60*60);
+ setcookie("ari_vmx_play_instructions", $vmx_play_instructions, time()+365*24*60*60);
+
+ $stripped_vmx_option_0_number = preg_replace('/-|\(|\)|\s/','',$vmx_option_0_number);
+
+ if ($vmx_option_0_system_default) {
+ $this->setVmxOptionNumber($exten,'0','unavail',"");
+ $this->setVmxOptionNumber($exten,'0','busy',"");
+ setcookie("ari_vmx_option_0_system_default", $vmx_option_0_system_default, time()+365*24*60*60);
+ if (is_numeric($stripped_vmx_option_0_number) || !$stripped_vmx_option_0_number) {
+ $stripped = preg_replace('/-|\(|\)|\s/','',$_COOKIE['ari_vmx_option_0_number']);
+ if ($vmx_option_0_number && $stripped!=$stripped_vmx_option_0_number) {
+ setcookie("ari_vmx_option_0_number", $call_vmx_option_0_number, time()+365*24*60*60);
+ }
+ }
+ } else {
+ if (!is_numeric($stripped_vmx_option_0_number) && $stripped_vmx_option_0_number) {
+ $_SESSION['ari_error'] =
+ _("Option 0 not changed") . "<br>" .
+ sprintf(_("Number %s must contain dial numbers (characters like '(', '-', and ')' are ok)"),$vmx_option_0_number);
+ }
+ else {
+
+ // set database
+ $this->setVmxOptionNumber($exten,'0','unavail',$stripped_vmx_option_0_number);
+ $this->setVmxOptionNumber($exten,'0','busy',$stripped_vmx_option_0_number);
+
+ // store cookie
+ $stripped = preg_replace('/-|\(|\)|\s/','',$_COOKIE['ari_vmx_option_0_number']);
+ if ($vmx_option_0_number && $stripped!=$stripped_vmx_option_0_number) {
+ setcookie("ari_vmx_option_0_number", $call_vmx_option_0_number, time()+365*24*60*60);
+ }
+ }
+ }
+
+ $stripped_vmx_option_1_number = preg_replace('/-|\(|\)|\s/','',$vmx_option_1_number);
+ if ($vmx_option_1_system_default && !$follow_me_disabled) {
+ $this->setVmxOptionFollowMe($exten,'1','unavail');
+ $this->setVmxOptionFollowMe($exten,'1','busy');
+ setcookie("ari_vmx_option_1_system_default", $vmx_option_1_system_default, time()+365*24*60*60);
+ if (is_numeric($stripped_vmx_option_1_number) || !$stripped_vmx_option_1_number) {
+ $stripped = preg_replace('/-|\(|\)|\s/','',$_COOKIE['ari_vmx_option_1_number']);
+ if ($vmx_option_1_number && $stripped!=$stripped_vmx_option_1_number) {
+ setcookie("ari_vmx_option_1_number", $call_vmx_option_1_number, time()+365*24*60*60);
+ }
+ }
+ }
+ else {
+
+ if (!is_numeric($stripped_vmx_option_1_number) && $stripped_vmx_option_1_number) {
+ $_SESSION['ari_error'] =
+ _("Option 1 not changed") . "<br>" .
+ sprintf(_("Number %s must contain dial numbers (characters like '(', '-', and ')' are ok)"),$vmx_option_1_number);
+ }
+ else {
+
+ // set database
+ $this->setVmxOptionNumber($exten,'1','unavail',$stripped_vmx_option_1_number);
+ $this->setVmxOptionNumber($exten,'1','busy',$stripped_vmx_option_1_number);
+
+ // store cookie
+ $stripped = preg_replace('/-|\(|\)|\s/','',$_COOKIE['ari_vmx_option_1_number']);
+ if ($vmx_option_1_number && $stripped!=$stripped_vmx_option_1_number) {
+ setcookie("ari_vmx_option_1_number", $call_vmx_option_1_number, time()+365*24*60*60);
+ }
+ }
+ }
+
+ $stripped_vmx_option_2_number = preg_replace('/-|\(|\)|\s/','',$vmx_option_2_number);
+ if (!is_numeric($stripped_vmx_option_2_number) && $stripped_vmx_option_2_number) {
+ $_SESSION['ari_error'] =
+ _("Option 2 not changed") . "<br>" .
+ sprintf(_("Number %s must contain dial numbers (characters like '(', '-', and ')' are ok)"),$vmx_option_2_number);
+ }
+ else {
+
+ // set database
+ $this->setVmxOptionNumber($exten,'2','unavail',$stripped_vmx_option_2_number);
+ $this->setVmxOptionNumber($exten,'2','busy',$stripped_vmx_option_2_number);
+
+ // store cookie
+ $stripped = preg_replace('/-|\(|\)|\s/','',$_COOKIE['ari_vmx_option_2_number']);
+ if ($vmx_option_2_number && $stripped!=$stripped_vmx_option_2_number) {
+ setcookie("ari_vmx_option_2_number", $call_vmx_option_2_number, time()+365*24*60*60);
+ }
+ }
+ } // vmx_disabled false
+ }
+
+ // redirect to see updated page
+ $ret .= "
+ <head>
+ <script>
+ <!--
+ window.location = \"" . $_SESSION['ARI_ROOT'] . "?m=" . $m . "\"
+ // -->
+ </script>
+ </head>";
+
+ return $ret;
+ }
+
+ /*
+ * Displays stats page
+ *
+ * @param $args
+ * Common arguments
+ */
+ function display($args) {
+ global $SETTINGS_ALLOW_VMX_SETTINGS;
+
+ global $loaded_modules;
+
+ // args
+ $m = getArgument($args,'m');
+ $q = getArgument($args,'q');
+ $start = getArgument($args,'start');
+ $span = getArgument($args,'span');
+
+ $displayname = $_SESSION['ari_user']['displayname'];
+ $exten = $_SESSION['ari_user']['extension'];
+
+ $display = new DisplaySearch();
+
+ $follow_me_listring_time = $this->getFollowMeListRingTime($exten);
+
+ //TODO: Set this better than this?
+ $follow_me_disabled = ($follow_me_listring_time > 0)?0:1;
+ setcookie("ari_follow_me_disabled", $follow_me_disabled, time()+365*24*60*60);
+
+
+ $vmx_unavail_enabled=$this->getVmxState($exten,'unavail');
+ if ($vmx_unavail_enabled === false) {
+ $vmx_disabled = true;
+ setcookie("ari_vmx_disabled", $vmx_disabled, time()+365*24*60*60);
+ $SETTINGS_ALLOW_VMX_SETTINGS=false;
+ } else {
+ $vmx_disabled = false;
+ setcookie("ari_vmx_disabled", false, time()+365*24*60*60);
+ $vmx_busy_enabled=$this->getVmxState($exten,'busy');
+ $vmx_play_instructions=$this->getVmxPlayInstructions($exten);
+ $vmx_option_0_number=$this->getVmxOptionNumber($exten,'0');;
+ $vmx_option_1_number=$this->getVmxOptionNumber($exten,'1');;
+ $vmx_option_2_number=$this->getVmxOptionNumber($exten,'2');;
+
+ if (is_numeric($vmx_option_0_number)) {
+ $vmx_option_0_system_default='';
+ $vmx_option_0_number_text_box_options='';
+ } else {
+ $vmx_option_0_system_default='checked';
+ $vmx_option_0_number_text_box_options="disabled style='background: #DDD;'";
+ }
+
+ // if follow-me is enabled then the options are a numberic value (dial a phone number)
+ // or a followme target (FMnnn) which should not be displayed but means the box is checked
+ // or otherwise blank (or garbage in which case blank it)
+ //
+ if (!$follow_me_disabled) {
+ $vmx_option_1_system_default=$this->getVmxOptionFollowMe($exten,'1');
+ if ($vmx_option_1_system_default) {
+ $vmx_option_1_number = '';
+ $vmx_option_1_number_text_box_options="disabled style='background: #DDD;'";
+ }
+ }
+ }
+
+ $set_vmx_text .=
+ "
+ <br>
+ <table class='settings'>
+ <tr>
+ <td><a href='#' class='info'>" . _("Use When:") . "<span>" . _("Menu options below are available during your personal voicemail greeting playback. <br/><br/>Check both to use at all times.") . "<br></span></a></td> <td>
+ <input " . $vmx_unavail_enabled . " type=checkbox name='vmx_unavail_enabled' value='checked'>
+ <small>" . _("unavailable") . "</small>
+ </td>
+ <td>
+ <input " . $vmx_busy_enabled . " type=checkbox name='vmx_busy_enabled' value='checked'>
+ <small>" . _("busy") . "</small>
+ </td>
+ </tr>
+ <tr>
+ <td><a href='#' class='info'>" . _("Voicemail Instructions:") ."<span>" . _("Uncheck to play a beep after your personal voicemail greeting.") . "<br></span></a></td>
+ <td>
+ <input " . $vmx_play_instructions . " type=checkbox name='vmx_play_instructions' value='checked'>
+ <small>" . _("Standard voicemail prompts.") . "</small>
+ </td>
+ </tr>
+ </table>
+ <br>
+ <br>
+ <table class='settings'>
+ <tr>
+ <td><a href='#' class='info'>" . _("Press 0:") . "<span>" . _("Pressing 0 during your personal voicemail greeing goes to the Operator.
+ Uncheck to enter another destination here.") . "<br></span></a>
+ </td>
+ <td>
+ <input " . $vmx_option_0_number_text_box_options . " name='vmx_option_0_number' type='text' size=24 value='" . $vmx_option_0_number . "'>
+ </td>
+ <td>
+ <input " . $vmx_option_0_system_default . " type=checkbox name='vmx_option_0_system_default' value='checked' OnClick=\"disable_fields(); return true;\">
+ <small>" . _("Go To Operator") . "</small>
+ </td>
+ </tr>
+ <tr>
+ <td><a href='#' class='info'>" . _("Press 1:") . "<span>";
+
+ if ($follow_me_disabled)
+ $set_vmx_text .= _("The remaining options can have internal extensions, ringgroups, queues and external numbers that may be rung. It is often used to include your cell phone. You should run a test to make sure that the number is functional any time a change is made so you don't leave a caller stranded or receiving invalid number messages.");
+ else
+ $set_vmx_text .= _("Enter an alternate number here, then change your personal voicemail greeting to let callers know to press 1 to reach that number. <br/><br/>If you'd like to use your Follow Me List, check \"Send to Follow Me\" and disable Follow Me above.");
+
+
+ $set_vmx_text .=
+ " <br></span></a>
+ </td>
+ <td>
+ <input " . $vmx_option_1_number_text_box_options . " name='vmx_option_1_number' type='text' size=24 value='" . $vmx_option_1_number . "'>
+ </td>
+ <td>";
+
+
+ if (!$follow_me_disabled)
+ $set_vmx_text .= "<input " . $vmx_option_1_system_default . " type=checkbox name='vmx_option_1_system_default' value='checked' OnClick=\"disable_fields(); return true;\"><small>" . _("Send to Follow-Me") . "</small>";
+
+
+ $set_vmx_text .=
+ "
+ </td>
+ </tr>
+ <tr>
+ <td><a href='#' class='info'>" . _("Press 2:") . "<span>" . _("Use any extensions, ringgroups, queues or external numbers. <br/><br/>Remember to re-record your personal voicemail greeting and include instructions. Run a test to make sure that the number is functional.") . "<br></span></a></td>
+ <td>
+ <input " . $vmx_option_2_number_text_box_options . " name='vmx_option_2_number' type='text' size=24 value='" . $vmx_option_2_number . "'>
+ </td>
+ </tr>
+ </table>
+ <br>
+ <br>
+ ";
+
+
+ // Now we should be ready to build the page
+ $ret .= checkErrorMessage();
+
+ $headerText = sprintf(_("VmX Locator&#8482; Settings for %s (%s)"),$displayname,$exten);
+
+ $ret .= $display->displayHeaderText($headerText);
+ $ret .= $display->displayLine();
+
+ $ret .=
+ "<SCRIPT LANGUAGE='JavaScript'>
+ <!-- Begin
+ function disable_fields() {
+
+ if (document.ari_settings.vmx_option_0_system_default.checked) {
+ document.ari_settings.vmx_option_0_number.style.backgroundColor = '#DDD';
+ document.ari_settings.vmx_option_0_number.disabled = true;
+ }
+ else {
+ document.ari_settings.vmx_option_0_number.style.backgroundColor = '#FFF';
+ document.ari_settings.vmx_option_0_number.disabled = false;
+ }";
+
+ if (!$follow_me_disabled) {
+ $ret .= "
+ if (document.ari_settings.vmx_option_1_system_default.checked) {
+ document.ari_settings.vmx_option_1_number.style.backgroundColor = '#DDD';
+ document.ari_settings.vmx_option_1_number.disabled = true;
+ }
+ else {
+ document.ari_settings.vmx_option_1_number.style.backgroundColor = '#FFF';
+ document.ari_settings.vmx_option_1_number.disabled = false;
+ }";
+ }
+ $ret .=
+ "}
+ // End -->
+ </script>";
+
+ $ret .=
+ "<form class='settings' name='ari_settings' action='' method='GET'>
+ <input type=hidden name=m value=" . $m . ">
+ <input type=hidden name=f value='action'>
+ <input type=hidden name=a value='update'>
+ " . $set_vmx_text . "
+ <br>
+ <input name='submit' type='submit' value='" . _("Update") . "'>
+ </form>";
+
+ return $ret;
+ }
+
+ /*
+ * Gets VMX option FollowMe
+ *
+ * @param $exten
+ * Extension to get information about
+ * @param $digit
+ * Option number to get
+ * @param $mode
+ * Mode to get (unavail/busy)
+ * @return $response
+ * checked if set to got to extesion's follow-me on this option
+ */
+ function getVmxOptionFollowMe($exten, $digit, $mode='unavail') {
+
+ global $asterisk_manager_interface;
+
+ $digit = trim($digit);
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database get AMPUSER $exten/vmx/$mode/$digit/ext\r\n\r\n");
+ return (($response == 'FM'.$exten) ? 'checked':'');
+ }
+
+ /*
+ * Sets VMX option FollowMe
+ *
+ * @param $exten
+ * Extension to set information about
+ * @param $digit
+ * Option number to set
+ * @param $mode
+ * Mode to set (unavail/busy)
+ * @param $context
+ * Context to set ext to (default from-findmefollow)
+ * @param $priority
+ * Priority to set ext to (default 1)
+ */
+ function setVmxOptionFollowMe($exten, $digit, $mode, $context='ext-findmefollow', $priority='1') {
+
+ global $asterisk_manager_interface;
+
+ $value_opt = "FM$exten";
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database put AMPUSER $exten/vmx/$mode/$digit/ext $value_opt\r\n\r\n");
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database put AMPUSER $exten/vmx/$mode/$digit/context $context\r\n\r\n");
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database put AMPUSER $exten/vmx/$mode/$digit/pri $priority\r\n\r\n");
+ }
+
+ /*
+ * Gets VMX option number
+ *
+ * @param $exten
+ * Extension to get information about
+ * @param $digit
+ * Option number to get
+ * @param $mode
+ * Mode to get (unavail/busy)
+ * @return $number
+ * Number to use or blank if disabled
+ */
+ function getVmxOptionNumber($exten, $digit, $mode='unavail') {
+
+ global $asterisk_manager_interface;
+
+ $number = '';
+ $digit = trim($digit);
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database get AMPUSER $exten/vmx/$mode/$digit/ext\r\n\r\n");
+ if (is_numeric($response)) {
+ $number = $response;
+ }
+
+ $stripped = preg_replace('/-|\(|\)|\s/','',$_COOKIE["ari_vmx_option_${digit}_number"]);
+ if ($stripped==$number) {
+ $number = $_COOKIE["ari_vmx_option_${digit}_number"];
+ }
+
+ return $number;
+ }
+
+ /*
+ * Sets VMX option number
+ *
+ * @param $exten
+ * Extension to set information about
+ * @param $digit
+ * Option number to set
+ * @param $mode
+ * Mode to set (unavail/busy)
+ * @param $number
+ * Number to set ext to (blank will delete it)
+ * @param $context
+ * Context to set ext to (default from-internal)
+ * @param $priority
+ * Priority to set ext to (default 1)
+ */
+ function setVmxOptionNumber($exten, $digit, $mode, $number, $context='from-internal', $priority='1') {
+
+ global $asterisk_manager_interface;
+
+ $value_opt = trim($number);
+
+ if (is_numeric($value_opt)) {
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database put AMPUSER $exten/vmx/$mode/$digit/ext $value_opt\r\n\r\n");
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database put AMPUSER $exten/vmx/$mode/$digit/context $context\r\n\r\n");
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database put AMPUSER $exten/vmx/$mode/$digit/pri $priority\r\n\r\n");
+ } else {
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database deltree AMPUSER $exten/vmx/$mode/$digit\r\n\r\n");
+ }
+ }
+
+ /*
+ * Sets VMX State
+ *
+ * @param $exten
+ * Extension to modify
+ * @param $mode
+ * Mode to set (unavail/busy)
+ * @param $vmx_state
+ * enabled/disabled state based on check box value
+ */
+ function setVmxState($exten,$mode,$vmx_state) {
+
+ global $asterisk_manager_interface;
+
+ $value_opt = ($vmx_state)?'enabled':'disabled';
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database put AMPUSER $exten/vmx/$mode/state $value_opt\r\n\r\n");
+ }
+
+ /*
+ * Gets VMX State
+ *
+ * @param $exten
+ * Extension to get information about
+ * @param $mode
+ * Mode to get (unavail/busy)
+ * @return $data
+ * state of variable (checked/blank) or false if no poper value
+ */
+ function getVmxState($exten, $mode='unavail') {
+
+ global $asterisk_manager_interface;
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database get AMPUSER $exten/vmx/$mode/state\r\n\r\n");
+
+ if (preg_match("/enabled/",$response)) {
+ $response='checked';
+ }
+ elseif (preg_match("/disabled/",$response)) {
+ $response='';
+ }
+ else {
+ $response = false;
+ }
+
+ //TODO: really need to check for a bogus response, see how other side does it
+ //
+ return $response;
+
+ }
+
+ /*
+ * Sets VMX Play Instructions
+ *
+ * @param $exten
+ * Extension to modify
+ * @param $vmx_play_instructions
+ * play instructions or just beep (checked, blank)
+ * @param $mode
+ * Mode to set (unavail/busy)
+ */
+ function setVmxPlayInstructions($exten,$mode,$vmx_play_instructions) {
+
+ global $asterisk_manager_interface;
+
+ $value_opt = ($vmx_play_instructions)?'""':'s';
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database put AMPUSER $exten/vmx/$mode/vmxopts/timeout $value_opt\r\n\r\n");
+ }
+
+ /*
+ * Get VMX Play Instructions
+ *
+ * @param $exten
+ * Extension to get information about
+ * @param $mode
+ * Mode to get (unavail/busy)
+ * @return $data
+ * state of variable (checked/blank) or false if no poper value
+ */
+ function getVmxPlayInstructions($exten, $mode='unavail') {
+
+ global $asterisk_manager_interface;
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database get AMPUSER $exten/vmx/$mode/vmxopts/timeout\r\n\r\n");
+
+ if (preg_match("/s/",$response)) {
+ $response='';
+ }
+ else {
+ $response='checked';
+ }
+
+ //TODO: really need to check for a bogus response, see how other side does it
+ //
+ return $response;
+
+ }
+
+
+ /*
+ * Gets Follow Me List-Ring Time if set
+ *
+ * @param $exten
+ * Extension to get information about
+ * @return $number
+ * follow me list-ring time returned if set
+ */
+ function getFollowMeListRingTime($exten) {
+
+ global $asterisk_manager_interface;
+
+ $number = '';
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database get AMPUSER $exten/followme/grptime\r\n\r\n");
+ if (is_numeric($response)) {
+ $number = $response;
+ }
+
+ $stripped = preg_replace('/-|\(|\)|\s/','',$_COOKIE['ari_follow_me_listring_time']);
+ if ($stripped==$number) {
+ $number = $_COOKIE['ari_follow_me_listring_time'];
+ }
+
+ return $number;
+ }
+
+
+} // class
+
+?>
diff --git a/fs_selfservice/fri/modules/billing.module b/fs_selfservice/fri/modules/billing.module
new file mode 100644
index 000000000..6ef16e57d
--- /dev/null
+++ b/fs_selfservice/fri/modules/billing.module
@@ -0,0 +1,250 @@
+<?php
+
+/**
+ * @file
+ * Functions for the interface to the help page
+ */
+
+/**
+ * Class for help
+ */
+class billing {
+
+ /*
+ * rank (for prioritizing modules)
+ */
+ function rank() {
+
+ $rank = -2;
+ return $rank;
+ }
+
+ /*
+ * init
+ */
+ function init() {
+ }
+
+ /*
+ * Adds menu item to nav menu
+ *
+ * @param $args
+ * Common arguments
+ */
+ function navMenu($args) {
+
+ $ret .= "<p><small><small><a href='" . $_SESSION['ARI_ROOT'] . "?m=billing&f=display'>" . _("Billing") . "</a></small></small></p><br>";
+
+ return $ret;
+ }
+
+ /*
+ * Displays stats page
+ *
+ * @param $args
+ * Common arguments
+ */
+ function display($args) {
+
+ $display = new Display();
+
+ // args
+ $m = getArgument($args,'m');
+ $q = getArgument($args,'q');
+
+ $displayname = $_SESSION['ari_user']['displayname'];
+ $extension = $_SESSION['ari_user']['extension'];
+
+ // build page content
+ $ret .= checkErrorMessage();
+
+ $header_text = _("Billing");
+ if (!$_SESSION['ari_user']['admin_help']) {
+ $header_text .= sprintf(_(" for %s (%s)"), $displayname, $extension);
+ }
+
+ // build page content
+ $ret .= checkErrorMessage();
+
+ $ret .= $display->displayHeaderText($header_text);
+ $ret .= $display->displayLine();
+
+
+ $freeside = new FreesideSelfService();
+
+ $fs_info = $freeside->customer_info( array(
+ 'session_id' => $_SESSION['freeside_session_id'],
+ ) );
+ $error = $fs_info['error'];
+ if ( $error ) {
+ //$_SESSION['ari_error'] = _("Incorrect Username or Password");
+ $_SESSION['ari_error'] = $error; #// XXX report as ari_error???!
+ }
+
+ //$ret .= $fs_info['small_custview'];
+ //$ret .= '<BR>';
+
+ $ret .= 'Balance: <b>$'. $fs_info['balance']. '</b><BR><BR>';
+
+ if ( $fs_info['balance'] > 0 ) {
+
+ #$ret .= '<B><A HREF="'. $_SESSION['ARI_ROOT'].
+ # '?m=billing&f=make_payment">Make a payment</A></B><BR><BR>';
+ $ret .= '<B><A HREF="/selfservice/selfservice.cgi?session='.
+ $_SESSION['freeside_session_id'].
+ ';action=make_payment">Make a payment</A></B><BR><BR>';
+
+ }
+
+ // XXX count() ???
+ if ( count($fs_info['open_invoices']) ) {
+
+ $ret .= '<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=2 BGCOLOR="#eeeeee">'.
+ '<TR><TH BGCOLOR="#ff6666" COLSPAN=5>Open Invoices</TH></TR>';
+ $link = '<A HREF="'. $_SESSION['ARI_ROOT'].
+ '?m=billing&f=view_invoice&invnum=';
+
+ $col1 = "eeeeee";
+ $col2 = "cccccc";
+ $col = $col1;
+
+ while ( $i = each($fs_info['open_invoices']) ) {
+
+ $invoice = $i[value];
+
+ $td = '<TD BGCOLOR="#'. $col. '">';
+ $a = $link. $invoice['invnum']. '">';
+ $ret .=
+ "<TR>$td$a". 'Invoice #'. $invoice['invnum']. "</A></TD>$td</TD>".
+ "$td$a". $invoice['date']. "</A></TD>$td</TD>".
+ '<TD BGCOLOR="#'. $col. '" ALIGN="right">'. $a. '$'. $invoice['owed'].
+ '</A></TD>'.
+ '</TR>';
+
+ if ( $col == $col1 ) {
+ $col = $col2;
+ } else {
+ $col = $col1;
+ }
+
+ }
+
+ $ret .= '</TABLE><BR>';
+ } else {
+ $ret .= 'You have no outstanding invoices.<BR><BR>';
+ }
+
+ #$fs_info = $freeside->customer_info( array(
+ # 'session_id' => $_SESSION['freeside_session_id'],
+ #) );
+ #$error = $fs_info['error'];
+ #if ( $error ) {
+ # //$_SESSION['ari_error'] = _("Incorrect Username or Password");
+ # $_SESSION['ari_error'] = $error; #// XXX report as ari_error???!
+ #}
+
+ // $ret .= 'Billing goes here';
+ // XXX navigate to make payment, view invoice,
+ // & myaccount change payment info
+
+ $ret .= '<B><A HREF="/selfservice/selfservice.cgi?session='.
+ $_SESSION['freeside_session_id'].
+ ';action=make_payment">Make a credit card payment</A></B><BR><BR>';
+ $ret .= '<B><A HREF="/selfservice/selfservice.cgi?session='.
+ $_SESSION['freeside_session_id'].
+ ';action=make_payment">Make an electronic check payment</A></B><BR><BR>';
+ $ret .= '<B><A HREF="/selfservice/selfservice.cgi?session='.
+ $_SESSION['freeside_session_id'].
+ ';action=make_payment">Use a prepaid card</A></B><BR><BR>';
+
+ return $ret;
+
+ }
+
+ function make_payment($args) {
+
+ $display = new Display();
+
+ // args
+ $m = getArgument($args,'m');
+ $q = getArgument($args,'q');
+
+ $displayname = $_SESSION['ari_user']['displayname'];
+ $extension = $_SESSION['ari_user']['extension'];
+
+ // build page content
+ $ret .= checkErrorMessage();
+
+ $header_text = _("Billing");
+ if (!$_SESSION['ari_user']['admin_help']) {
+ $header_text .= sprintf(_(" for %s (%s)"), $displayname, $extension);
+ }
+
+ // build page content
+ $ret .= checkErrorMessage();
+
+ $ret .= $display->displayHeaderText($header_text);
+ $ret .= $display->displayLine();
+
+
+ #$freeside = new FreesideSelfService();
+
+ $ret .= 'Make payment goes here';
+
+ return $ret;
+
+ }
+
+ function view_invoice($args) {
+
+ $display = new Display();
+
+ // args
+ $m = getArgument($args,'m');
+ $q = getArgument($args,'q');
+
+ $displayname = $_SESSION['ari_user']['displayname'];
+ $extension = $_SESSION['ari_user']['extension'];
+
+ // build page content
+ $ret .= checkErrorMessage();
+
+ $header_text = _("Billing");
+ if (!$_SESSION['ari_user']['admin_help']) {
+ $header_text .= sprintf(_(" for %s (%s)"), $displayname, $extension);
+ }
+
+ // build page content
+ $ret .= checkErrorMessage();
+
+ $ret .= $display->displayHeaderText($header_text);
+ #$ret .= $display->displayLine();
+
+ $invnum = getArgument($args, 'invnum');
+
+ $freeside = new FreesideSelfService();
+ $invoice = $freeside->invoice( array(
+ 'session_id' => $_SESSION['freeside_session_id'],
+ 'invnum' => $invnum,
+ ) );
+ $error = $invoice['error'];
+ if ( $error ) {
+ //$_SESSION['ari_error'] = _("Incorrect Username or Password");
+ $_SESSION['ari_error'] = $error; // XXX report as ari_error???!
+ }
+
+ $html = $invoice['invoice_html']->scalar;
+ $html = str_replace( "\xA0", '&nbsp;', $html); // XX doh
+ error_log($html);
+
+ $ret .= '<TABLE BGCOLOR="#000000" BORDER=0><TR><TD>'.
+ $html.
+ '</TD></TR></TABLE>';
+
+ return $ret;
+
+ }
+
+}
+
+?>
diff --git a/fs_selfservice/fri/modules/callmonitor.module b/fs_selfservice/fri/modules/callmonitor.module
new file mode 100644
index 000000000..36f5f285a
--- /dev/null
+++ b/fs_selfservice/fri/modules/callmonitor.module
@@ -0,0 +1,675 @@
+<?php
+
+/**
+ * @file
+ * Functions for the interface to the call monitor recordings
+ */
+
+/**
+ * Class for Callmonitor
+ */
+class Callmonitor {
+
+ /*
+ * rank (for prioritizing modules)
+ */
+ function rank() {
+
+ $rank = 2;
+ return $rank;
+ }
+
+ /*
+ * init
+ */
+ function init() {
+ }
+
+ /*
+ * Adds menu item to nav menu
+ *
+ * @param $args
+ * Common arguments
+ */
+ function navMenu($args) {
+
+ $ret .= "<p><small><small><a href='" . $_SESSION['ARI_ROOT'] . "?m=Callmonitor&f=display'>" . _("Call History") . "</a></small></small></p><br>";
+
+ return $ret;
+ }
+
+ /*
+ * Acts on the selected call monitor recordings in the method indicated by the action and updates page
+ *
+ * @param $args
+ * Common arguments
+ */
+ function recAction($args) {
+
+ // args
+ $m = getArgument($args,'m');
+ $a = getArgument($args,'a');
+ $q = getArgument($args,'q');
+ $start = getArgument($args,'start');
+ $span = getArgument($args,'span');
+ $order = getArgument($args,'order');
+ $sort = getArgument($args,'sort');
+ $duration_filter = getArgument($args,'duration_filter');
+
+ // get files
+ $files = array();
+ foreach($_REQUEST as $key => $value) {
+ if (preg_match('/selected/',$key)) {
+ array_push($files, $value);
+ }
+ }
+
+ if ($a=='delete') {
+ $this->deleteRecData($files);
+ }
+
+ if ($a=='ignore') {
+
+ $start = 0;
+
+ setcookie("ari_duration_filter", $duration_filter, time()+365*24*60*60);
+ }
+
+ // redirect to see updated page
+ $ret .= "
+ <head>
+ <script>
+ <!--
+ window.location = \"" . $_SESSION['ARI_ROOT'] . "?m=" . $m . "&q=" . $q . "&start=" . $start . "&span=" . $span . "&order=" . $order . "&sort=" . $sort . "&duration_filter=" . $duration_filter . "\"
+ // -->
+ </script>
+ </head>";
+
+ return $ret;
+ }
+
+ /*
+ * Displays stats page
+ *
+ * @param $args
+ * Common arguments
+ */
+ function display($args) {
+
+ global $ASTERISK_CALLMONITOR_PATH;
+ global $CALLMONITOR_ALLOW_DELETE;
+ global $AJAX_PAGE_REFRESH_ENABLE;
+
+ $display = new DisplaySearch();
+
+ // get the search string
+ $m = getArgument($args,'m');
+ $f = getArgument($args,'f');
+ $q = getArgument($args,'q');
+ $start = getArgument($args,'start');
+ $span = getArgument($args,'span');
+ $order = getArgument($args,'order');
+ $sort = getArgument($args,'sort');
+ $duration_filter = getArgument($args,'duration_filter');
+
+ $start = $start=='' ? 0 : $start;
+ $span = $span=='' ? 15 : $span;
+ $order = $order=='' ? 'calldate' : $order;
+ $sort = $sort=='' ? 'desc' : $sort;
+
+ $displayname = $_SESSION['ari_user']['displayname'];
+ $extension = $_SESSION['ari_user']['extension'];
+
+ // get data
+ $record_count = $this->getCdrCount($q,$duration_filter);
+ $data = $this->getCdrData($q,$duration_filter,$start,$span,$order,$sort);
+
+ // get the call monitor recording files
+ $paths = split(';',$ASTERISK_CALLMONITOR_PATH);
+ foreach($paths as $key => $path) {
+ if (!is_dir($path)) {
+ $_SESSION['ari_error'] .= sprintf(_("Path is not a directory: %s"),$path) . "<br>";
+ }
+ }
+ $recordings = $this->getRecordings($ASTERISK_CALLMONITOR_PATH,$data);
+
+ // build controls
+ if ($CALLMONITOR_ALLOW_DELETE) {
+ $controls .= "
+ <button class='infobar' type='submit' onclick=\"document.callmonitor_form.a.value='delete'\">
+ " . _("delete") . "
+ </button>
+ &nbsp;";
+ }
+
+ $controls .= "
+ <small>" . _("duration") . "</small>
+ <input name='duration_filter' type='text' size=4 maxlength=8 value='" . $_COOKIE['ari_duration_filter'] . "'>
+ <button class='infobar' type='submit' onclick=\"document.callmonitor_form.a.value='ignore'\">
+ " . _("ignore") . "
+ </button>";
+
+ // table header
+ if ($CALLMONITOR_ALLOW_DELETE) {
+ $recording_delete_header = "<th></th>";
+ }
+
+ $fields[0]['field'] = "calldate";
+ $fields[0]['text'] = _("Date");
+ $fields[1]['field'] = "calldate";
+ $fields[1]['text'] = _("Time");
+ $fields[2]['field'] = "clid";
+ $fields[2]['text'] = _("Caller ID");
+ $fields[3]['field'] = "src";
+ $fields[3]['text'] = _("Source");
+ $fields[4]['field'] = "dst";
+ $fields[4]['text'] = _("Destination");
+ $fields[5]['field'] = "dcontext";
+ $fields[5]['text'] = _("Context");
+ $fields[6]['field'] = "duration";
+ $fields[6]['text'] = _("Duration");
+
+ $i = 0;
+ while ($fields[$i]) {
+
+ $field = $fields[$i]['field'];
+ $text = $fields[$i]['text'];
+ if ($order==$field) {
+ if ($sort=='asc') {
+ $currentSort = 'desc';
+ $arrowImg = "<img src='theme/images/arrow-asc.gif' alt='sort'>";
+ }
+ else {
+ $currentSort = 'asc';
+ $arrowImg = "<img src='theme/images/arrow-desc.gif' alt='sort'>";
+ }
+
+ if ($i==1) {
+ $arrowImg = '';
+ }
+ }
+ else {
+ $arrowImg = '';
+ $currentSort = 'desc';
+ }
+
+ $unicode_q = urlencode($q);
+ $recording_header .= "<th><a href=" . $_SESSION['ARI_ROOT'] . "?m=" . $m . "&f=" . $f . "&q=" . $unicode_q . "&order=" . $field . "&sort=" . $currentSort . ">" . $text . $arrowImg . "</a></th>";
+
+ $i++;
+ }
+ $recording_header .= "<th>" . _("Monitor") . "</th>";
+
+ // table body
+ foreach($data as $key=>$value) {
+
+ // recording file
+ $recording = $recordings[$value['uniqueid'] . $value['calldate']];
+
+ // date and time
+ $buf = split(' ', $value[calldate]);
+ $date = $buf[0];
+ $time = $buf[1];
+
+ // recording delete checkbox
+ if ($CALLMONITOR_ALLOW_DELETE) {
+ $recording_delete_checkbox = "<td class='checkbox'><input type=checkbox name='selected" . ++$i . "' value=" . $recording . "></td>";
+ }
+
+ $recordingLink = '';
+ if (is_file($recordings[$value['uniqueid'] . $value['calldate']])) {
+ $recordingLink = "<a href='#' onClick=\"javascript:popUp('misc/recording_popup.php?recording=" . $recording . "&date=" . $date . "&time=" . $time . "'); return false;\">" . _("play") . "</a>";
+ }
+
+ $recording_body .= "<tr>
+ " . $recording_delete_checkbox . "
+ <td width=70>" . $date . "</td>
+ <td>" . $time . "</td>
+ <td>" . $value[clid] . "</td>
+ <td>" . $value[src] . "</td>
+ <td>" . $value[dst] . "</td>
+ <td>" . $value[dcontext] . "</td>
+ <td width=90>" . $value[duration] . " sec</td>
+ <td>" . $recordingLink . "</td>
+ </tr>";
+ }
+ if (!count($data)) {
+ $recording_body .= "<tr></tr>";
+ }
+
+ // options
+ $url_opts = array();
+ $url_opts['sort'] = $sort;
+ $url_opts['order'] = $order;
+ $url_opts['duration_filter'] = $duration_filter;
+
+ // build page content
+ $ret .= checkErrorMessage();
+
+ // ajax page refresh script
+ if ($AJAX_PAGE_REFRESH_ENABLE) {
+ // $ret .= ajaxRefreshScript($args);
+ }
+
+ // header
+ if ($_SESSION['ari_user']['admin_callmonitor']) {
+ $header_text = _("Call History");
+ } else {
+ $header_text = sprintf(_("Call History for %s (%s)"),$displayname,$extension);
+ }
+ $ret .= $display->displayHeaderText($header_text);
+ $ret .= $display->displaySearchBlock('left',$m,$q,$url_opts,true);
+
+ // start form
+ if ($CALLMONITOR_ALLOW_DELETE) {
+
+ $ret .= "
+ <form name='callmonitor_form' action='" . $_SESSION['ARI_ROOT'] . "' method='GET'>
+ <input type=hidden name=m value=" . $m . ">
+ <input type=hidden name=f value=recAction>
+ <input type=hidden name=a value=''>
+ <input type=hidden name=q value=" . $q . ">
+ <input type=hidden name=start value=" . $start . ">
+ <input type=hidden name=span value=" . $span . ">
+ <input type=hidden name=order value=" . $order . ">
+ <input type=hidden name=sort value=" . $sort . ">";
+ }
+
+ $ret .= $display->displayInfoBarBlock($controls,$q,$start,$span,$record_count);
+
+ // javascript for popup and message actions
+ $ret .= "
+ <SCRIPT LANGUAGE='JavaScript'>
+ <!-- Begin
+ function popUp(URL) {
+ eval(\"page = window.open(URL, 'play', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=1,width=324,height=110');\");
+ }
+
+ function checkAll(form,set) {
+ var elem = 0;
+ var i = 0;
+ while (elem = form.elements[i]) {
+ if (set) {
+ elem.checked = true;
+ } else {
+ elem.checked = false;
+ }
+ i++;
+ }
+ return true;
+ }
+ // End -->
+ </script>";
+
+ // call monitor delete recording controls
+ if ($CALLMONITOR_ALLOW_DELETE) {
+ $ret .= "
+ <table>
+ <tr>
+ <td>
+ <small>" . _("select") . ": </small>
+ <small><a href='' OnClick=\"checkAll(document.callmonitor_form,true); return false;\">" . _("all") . "</a></small>
+ <small><a href='' OnClick=\"checkAll(document.callmonitor_form,false); return false;\">" . _("none") . "</a></small>
+ </td>
+ </tr>
+ </table>";
+ }
+ else {
+ $ret .= "<br>";
+ }
+
+ // table
+ $ret .= "
+ <table class='callmonitor'>
+ <tr>
+ " . $recording_delete_header . "
+ " . $recording_header . "
+ </tr>
+ " . $recording_body . "
+ </table>";
+
+ $start = getArgument($args,'start');
+ $span = getArgument($args,'span');
+ $order = getArgument($args,'order');
+ $sort = getArgument($args,'sort');
+
+ // end form
+ if ($CALLMONITOR_ALLOW_DELETE) {
+ $ret .= "</form>";
+ }
+
+ $ret .= $display->displaySearchBlock('center',$m,$q,$url_opts,false);
+ $ret .= $display->displayNavigationBlock($m,$q,$url_opts,$start,$span,$record_count);
+
+ return $ret;
+ }
+
+ /*
+ * Checks for a recording file
+ *
+ * @param $asterisk_callmonitor_path
+ * path call monitor recording directory on the asterisk server
+ * @param $data
+ * current call monitor recordings on the asterisk server
+ * @return $recording
+ * returns an array of $recording file names if found
+ */
+ function getRecordings($asterisk_callmonitor_path,$data) {
+
+ global $CALLMONITOR_ONLY_EXACT_MATCHING;
+ global $CALLMONITOR_AGGRESSIVE_MATCHING;
+
+ $recordings = array();
+
+ $extension = $_SESSION['ari_user']['extension'];
+
+ $paths = split(';',$asterisk_callmonitor_path);
+ foreach($paths as $key => $path) {
+ $paths[$key] = fixPathSlash($paths[$key]);
+ }
+
+ $files = array();
+ if (!$CALLMONITOR_ONLY_EXACT_MATCHING) {
+ $filter = '';
+ $recursiveMax = 6;
+ $recursiveCount = 0;
+ foreach($paths as $key => $path) {
+ $path_files = getFiles($path,$filter,$recursiveMax,$recursiveCount);
+ if ($path_files) {
+ $files = array_merge($files,$path_files);
+ }
+ }
+ rsort($files);
+ }
+
+ foreach($data as $data_key => $data_value) {
+
+ $recording='';
+
+ $calldate = $data_value['calldate'];
+ $duration = $data_value['duration'];
+ $lastdata = $data_value['lastdata'];
+ $uniqueid = $data_value['uniqueid'];
+ $userfield = $data_value['userfield'];
+
+ // timestamps
+ $st = trim(strtotime($calldate));
+ $et = trim(strtotime($calldate) + $duration); // for on-demand call recordings
+
+ // unique file key
+ if ($uniqueid) {
+ $buf = preg_replace('/\-|\:/', '', $calldate);
+ $calldate_key = preg_replace('/\s+/', '-', $buf);
+ $unique_file_key = $calldate_key . "-" . $uniqueid;
+ }
+ if ($unique_file_key=='') {
+ $buf = preg_split("/\|/", $lastdata);
+ $unique_file_key = $buf[1];
+ }
+
+ $recordingLink = '';
+ foreach($paths as $callmonitor_key => $path) {
+
+ // try to find an exact match using the uniqueid
+ if (isset($uniqueid)) {
+
+ $check_files = array();
+ array_push($check_files,$path . $uniqueid . ".WAV");
+ array_push($check_files,$path . $uniqueid . ".wav");
+ array_push($check_files,$path . $uniqueid . ".gsm");
+
+ array_push($check_files,$path . $unique_file_key . ".WAV");
+ array_push($check_files,$path . $unique_file_key . ".wav");
+ array_push($check_files,$path . $unique_file_key . ".gsm");
+
+ array_push($check_files,$path . "g" . $extension . "-" . $unique_file_key . ".WAV");
+ array_push($check_files,$path . "g" . $extension . "-" . $unique_file_key . ".wav");
+ array_push($check_files,$path . "g" . $extension . "-" . $unique_file_key . ".gsm");
+
+ array_push($check_files,$path . "q" . $extension . "-" . $unique_file_key . ".WAV");
+ array_push($check_files,$path . "q" . $extension . "-" . $unique_file_key . ".wav");
+ array_push($check_files,$path . "q" . $extension . "-" . $unique_file_key . ".gsm");
+
+ array_push($check_files,$path . "OUT" . $extension . "-" . $unique_file_key . ".WAV");
+ array_push($check_files,$path . "OUT" . $extension . "-" . $unique_file_key . ".wav");
+ array_push($check_files,$path . "OUT" . $extension . "-" . $unique_file_key . ".gsm");
+
+ array_push($check_files,$path . $userfield);
+
+ // try to match
+ foreach($check_files as $check_file) {
+ if (is_file($check_file)) {
+ $recording = $check_file;
+ break;
+ }
+ }
+ }
+
+ // if found do not need to check the rest of the paths
+ if ($recording!='') {
+ break;
+ }
+ }
+
+ // get all the callmonitor recordings on server and try to find a non-exact match for this log entry
+ if (!$CALLMONITOR_ONLY_EXACT_MATCHING) {
+
+ // try to find a file using the uniqueid
+ if (!$recording) {
+
+ // try and match the unique id
+ if (!$recording) {
+ foreach($files as $key => $path) {
+ if (strlen($uniqueid)>1 && strpos($path,$uniqueid)!==FALSE) {
+ $recording = $path;
+ $files[$key] = ''; // remove it from the recording files so it will not be matched twice
+ break;
+ }
+ }
+ }
+ }
+
+ // try and match a file using the calldate (if no unique number from database)
+ if (!$recording) {
+
+ foreach($files as $key => $path) {
+ $parts = split("-", $path);
+ if (strlen($st)>1 &&
+ (strpos($path,$st)!==FALSE) ||
+ (strpos($path,"auto")!==FALSE && $parts[1] >= $st && $parts[1] <= $et)) {
+ $recording = $path;
+ $files[$key] = ''; // remove it from the recording files so it will not be matched twice
+ break;
+ }
+ }
+ }
+
+ if ($CALLMONITOR_AGGRESSIVE_MATCHING) {
+
+ // one last stab at finding a recording by adding one or two seconds to the call time
+ if (!$recording) {
+ $st_1 = trim($st+1);
+ $st_2 = trim($st+2);
+ $et_1 = trim($et+1);
+ $et_2 = trim($et+2);
+ foreach($files as $key => $path) {
+ $split = explode("-", $path);
+ if (strlen($st)>1
+ && ((strpos($path,$st_1)!==FALSE) ||
+ (strpos($path,$st_2)!==FALSE) ||
+ (strpos($path,"auto")!==FALSE && $parts[1] >= $st_1 && $parts[1] <= $et_1) ||
+ (strpos($path,"auto")!==FALSE && $parts[1] >= $st_2 && $parts[1] <= $et_2))) {
+ $recording = $path;
+ $files[$key] = ''; // remove it from the recording files so it will not be matched twice
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // add to array to be returned
+ if ($recording) {
+ $recordings[$uniqueid . $calldate] = $recording;
+ }
+ }
+
+ return $recordings;
+ }
+
+ /*
+ * Deletes selected call monitor recordings
+ *
+ * @param $files
+ * Array of files to delete
+ */
+ function deleteRecData($files) {
+
+ foreach($files as $key => $file) {
+ if (is_writable($file)) {
+ unlink($file);
+ } else {
+ $_SESSION['ari_error'] = _("Only deletes recording files, not cdr log");
+ }
+ }
+ }
+
+ /*
+ * Gets cdr record count
+ *
+ * @param $q
+ * query text
+ */
+ function getSearchText($q,$duration_filter) {
+
+ // search text
+ if ($q!='*' && $q!=NULL) {
+ $searchText .= "WHERE ";
+ $tok = strtok($q," \n\t");
+ while ($tok) {
+ $searchText .= " (calldate regexp '" . $tok . "'
+ OR clid regexp '" . $tok . "'
+ OR src regexp '" . $tok . "'
+ OR dst regexp '" . $tok . "'
+ OR dstchannel regexp '" . $tok . "'
+ OR dcontext regexp '" . $tok . "'
+ OR duration regexp '" . $tok . "'
+ OR disposition regexp '" . $tok . "'
+ OR uniqueid regexp '" . $tok . "'
+ OR userfield regexp '" . $tok . "'
+ )";
+ $tok = strtok(" \n\t");
+ if ($tok) {
+ $searchText .= " AND";
+ }
+ }
+ }
+
+ // duration_filter
+ if ($duration_filter) {
+ if (!$searchText) {
+ $searchText .= "WHERE ";
+ } else {
+ $searchText .= "AND ";
+ }
+ $searchText .= "duration>" . $duration_filter . " ";
+ }
+
+ // admin
+ if (!$_SESSION['ari_user']['admin_callmonitor']) {
+ if (!$searchText) {
+ $searchText .= "WHERE ";
+ } else {
+ $searchText .= "AND ";
+ }
+
+ // allow entries to be viewed with users extension
+ $searchText .= "(src = '" . $_SESSION['ari_user']['extension'] . "'
+ OR dst = '" . $_SESSION['ari_user']['extension'] . "'
+
+ OR channel LIKE 'IAX2/" . $_SESSION['ari_user']['extension'] ."-%'
+ OR dstchannel LIKE 'IAX2/" . $_SESSION['ari_user']['extension'] ."-%'
+
+ OR channel LIKE 'SIP/" . $_SESSION['ari_user']['extension'] ."-%'
+ OR dstchannel LIKE 'SIP/" . $_SESSION['ari_user']['extension'] ."-%')";
+
+ // allow entries to be viewed with users outbound CID
+ if (isset($_SESSION['ari_user']['outboundCID']) && trim($_SESSION['ari_user']['outboundCID']) != '') {
+ $searchText .= "OR (src = '" . $_SESSION['ari_user']['outboundCID'] . "'
+ OR dst = '" . $_SESSION['ari_user']['outboundCID'] . "')";
+ }
+ }
+
+ return $searchText;
+ }
+
+ /*
+ * Gets cdr record count
+ *
+ * @param $q
+ * query text
+ * @return $count
+ * Number of cdr records counted
+ */
+ function getCdrCount($q,$duration_filter) {
+
+ global $ASTERISKCDR_DBTABLE;
+
+ $searchText = $this->getSearchText($q,$duration_filter);
+
+ $dbh = $_SESSION['dbh_cdr'];
+ $sql = "SELECT count(*)
+ FROM " . $ASTERISKCDR_DBTABLE . "
+ " . $searchText;
+
+ $result = $dbh->getAll($sql);
+ if (DB::isError($result)) {
+ $_SESSION['ari_error'] = $result->getMessage();
+ return;
+ }
+ $count = $result[0][0];
+
+ return $count;
+ }
+
+ /*
+ * Gets cdr data
+ *
+ * @param $q
+ * query text
+ * @param $start
+ * start record
+ * @param $span
+ * number of records to return
+ * @return $data
+ * cdr data to be returned
+ */
+ function getCdrData($q,$duration_filter,$start,$span,$order,$sort) {
+
+ global $ASTERISKCDR_DBTABLE;
+
+ $data = array();
+
+ $searchText = $this->getSearchText($q,$duration_filter);
+
+ $dbh = $_SESSION['dbh_cdr'];
+ $sql = "SELECT *
+ FROM " . $ASTERISKCDR_DBTABLE . "
+ " . $searchText . "
+ ORDER BY " . $order . " " . $sort . "
+ LIMIT " . $start . "," . $span;
+ $result = $dbh->getAll($sql,DB_FETCHMODE_ASSOC);
+ if (DB::isError($result)) {
+ $_SESSION['ari_error'] = $result->getMessage();
+ return;
+ }
+ $data = $result;
+
+ return $data;
+ }
+
+
+}
+
+
+?>
diff --git a/fs_selfservice/fri/modules/dashboard.module b/fs_selfservice/fri/modules/dashboard.module
new file mode 100644
index 000000000..62d6de46a
--- /dev/null
+++ b/fs_selfservice/fri/modules/dashboard.module
@@ -0,0 +1,166 @@
+<?php
+
+/**
+ * @file
+ * Functions for the interface to the help page
+ */
+
+/**
+ * Class for help
+ */
+class dashboard {
+
+ /*
+ * rank (for prioritizing modules)
+ */
+ function rank() {
+
+ $rank = -4;
+ return $rank;
+ }
+
+ /*
+ * init
+ */
+ function init() {
+ }
+
+ /*
+ * Adds menu item to nav menu
+ *
+ * @param $args
+ * Common arguments
+ */
+ function navMenu($args) {
+
+ $ret .= "<p><small><small><a href='" . $_SESSION['ARI_ROOT'] . "?m=dashboard&f=display'>" . _("Dashboard") . "</a></small></small></p><br>";
+
+ return $ret;
+ }
+
+ /*
+ * Displays stats page
+ *
+ * @param $args
+ * Common arguments
+ */
+ function display($args) {
+
+ $display = new Display();
+
+ // args
+ $m = getArgument($args,'m');
+ $q = getArgument($args,'q');
+
+ $displayname = $_SESSION['ari_user']['displayname'];
+ $extension = $_SESSION['ari_user']['extension'];
+
+ // build page content
+ $ret .= checkErrorMessage();
+
+ $header_text = _("Dashboard");
+ if (!$_SESSION['ari_user']['admin_help']) {
+ $header_text .= sprintf(_(" for %s (%s)"), $displayname, $extension);
+ }
+
+ // build page content
+ $ret .= checkErrorMessage();
+
+ $ret .= $display->displayHeaderText($header_text);
+ $ret .= $display->displayLine();
+
+ $freeside = new FreesideSelfService();
+ $fs_info = $freeside->customer_info( array(
+ 'session_id' => $_SESSION['freeside_session_id'],
+ ) );
+ $error = $fs_info['error'];
+ if ( $error ) {
+ //$_SESSION['ari_error'] = _("Incorrect Username or Password");
+ $_SESSION['ari_error'] = $error; #// XXX report as ari_error???!
+ }
+
+ $ret .= $fs_info['small_custview'];
+ $ret .= '<BR>';
+
+ if ( $fs_info['balance'] > 0 ) {
+
+ #$ret .= '<B><A HREF="'. $_SESSION['ARI_ROOT'].
+ # '?m=billing&f=make_payment">Make a payment</A></B><BR><BR>';
+ $ret .= '<B><A HREF="/selfservice/selfservice.cgi?session='.
+ $_SESSION['freeside_session_id'].
+ ';action=make_payment">Make a payment</A></B><BR><BR>';
+
+ }
+
+ // XXX count() ???
+ if ( count($fs_info['open_invoices']) ) {
+
+ $ret .= '<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=2 BGCOLOR="#eeeeee">'.
+ '<TR><TH BGCOLOR="#ff6666" COLSPAN=5>Open Invoices</TH></TR>';
+ $link = '<A HREF="'. $_SESSION['ARI_ROOT'].
+ '?m=billing&f=view_invoice&invnum=';
+
+ $col1 = "eeeeee";
+ $col2 = "cccccc";
+ $col = $col1;
+
+ while ( $i = each($fs_info['open_invoices']) ) {
+
+ $invoice = $i[value];
+
+ $td = '<TD BGCOLOR="#'. $col. '">';
+ $a = $link. $invoice['invnum']. '">';
+ $ret .=
+ "<TR>$td$a". 'Invoice #'. $invoice['invnum']. "</A></TD>$td</TD>".
+ "$td$a". $invoice['date']. "</A></TD>$td</TD>".
+ '<TD BGCOLOR="#'. $col. '" ALIGN="right">'. $a. '$'. $invoice['owed'].
+ '</A></TD>'.
+ '</TR>';
+
+ if ( $col == $col1 ) {
+ $col = $col2;
+ } else {
+ $col = $col1;
+ }
+
+ }
+
+ $ret .= '</TABLE><BR>';
+ } else {
+ $ret .= 'You have no outstanding invoices.<BR><BR>';
+ }
+
+ #$ret .= 'Received calls (10)<br><br>';
+ #$ret .= 'Placed calls (10)';
+
+// if ( @tickets ) {
+// $OUT .= '<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=2 BGCOLOR="#eeeeee">'.
+// '<TR><TH BGCOLOR="#ff6666" COLSPAN=5>Open Tickets</TH></TR>'.
+// '<TR><TH>#</TH><TH>Subject</TH><TH>Priority</TH><TH>Queue</TH>'.
+// '<TH>Status</TH></TR>';
+// my $col1 = "ffffff";
+// my $col2 = "dddddd";
+// my $col = $col1;
+//
+// foreach my $ticket ( @tickets ) {
+// my $td = qq!<TD BGCOLOR="#$col">!;
+// $OUT .=
+// "<TR>$td". $ticket->{'id'}. "</TD>".
+// $td. $ticket->{'subject'}. "</TD>".
+// $td. ($ticket->{'content'} || $ticket->{'priority'}). "</TD>".
+// $td. $ticket->{'name'}. "</TD>".
+// $td. $ticket->{'status'}. "</TD>".
+// '</TR>';
+// $col = $col eq $col1 ? $col2 : $col1;
+// }
+// $OUT .= '</TABLE>';
+// } else {
+// $OUT .= '';
+// }
+
+ return $ret;
+ }
+
+}
+
+?>
diff --git a/fs_selfservice/fri/modules/featurecodes.module b/fs_selfservice/fri/modules/featurecodes.module
new file mode 100644
index 000000000..75d1d5c4e
--- /dev/null
+++ b/fs_selfservice/fri/modules/featurecodes.module
@@ -0,0 +1,152 @@
+<?php
+
+/**
+ * @file
+ * Functions for the interface to the help page
+ */
+
+/**
+ * Class for help
+ */
+class featurecodes {
+
+ /*
+ * rank (for prioritizing modules)
+ */
+ function rank() {
+
+ $rank = 7;
+ return $rank;
+ }
+
+ /*
+ * init
+ */
+ function init() {
+ }
+
+ /*
+ * Adds menu item to nav menu
+ *
+ * @param $args
+ * Common arguments
+ */
+ function navMenu($args) {
+
+ $ret .= "<p><small><small><a href='" . $_SESSION['ARI_ROOT'] . "?m=featurecodes&f=display'>" . _("Feature Codes") . "</a></small></small></p><br>";
+
+ return $ret;
+ }
+
+ /*
+ * Displays stats page
+ *
+ * @param $args
+ * Common arguments
+ */
+ function display($args) {
+
+ global $ARI_HELP_FEATURE_CODES;
+
+ $display = new Display();
+
+ // args
+ $m = getArgument($args,'m');
+ $q = getArgument($args,'q');
+
+ $displayname = $_SESSION['ari_user']['displayname'];
+ $extension = $_SESSION['ari_user']['extension'];
+
+ // build page content
+ $ret .= checkErrorMessage();
+
+ $header_text = _("Feature Codes");
+ if (!$_SESSION['ari_user']['admin_help']) {
+ $header_text .= sprintf(_(" for %s (%s)"), $displayname, $extension);
+ }
+
+ // handset feature code header
+ $handset_feature_codes_header =
+ "<tr>
+ <th class='feature_codes'>
+ " . _("Handset Feature Code") . "
+ </th>
+ <th>
+ " . _("Action") . "
+ </th>
+ </tr>";
+
+ // handset feature code body
+ if (isset($_SESSION['dbh_asterisk'])) {
+
+ $sql = "
+ SELECT keycode, description
+ FROM (
+ SELECT modulename, description, defaultcode keycode
+ FROM featurecodes
+ WHERE customcode IS NULL
+ AND enabled = '1'
+ UNION ALL SELECT modulename, description, customcode keycode
+ FROM featurecodes
+ WHERE customcode IS NOT NULL
+ AND enabled = '1'
+ )c
+ WHERE modulename NOT
+ IN ( 'core', 'recordings', 'infoservices', 'polycomreassign')
+ ORDER BY modulename, keycode
+ ";
+
+ $results = $_SESSION['dbh_asterisk']->getAll($sql, DB_FETCHMODE_ASSOC);
+ if(DB::IsError($results)) {
+ $_SESSION['ari_error'] = $results->getMessage();
+ }
+ else {
+ foreach ($results as $item ) {
+ $handset_feature_codes_body .=
+ "<tr>
+ <td class='feature_codes'>
+ " . $item['keycode'] . "
+ </td>
+ <td>
+ " . $item['description'] . "
+ </td>
+ </tr>";
+ }
+ }
+ }
+ else {
+
+ // handset feature code body
+ foreach($ARI_HELP_FEATURE_CODES as $key => $feature_code) {
+
+ $handset_feature_codes_body .=
+ "<tr>
+ <td class='feature_codes'>
+ " . $key . "
+ </td>
+ <td>
+ " . $feature_code . "
+ </td>
+ </tr>";
+ }
+ }
+
+ // build page content
+ $ret .= checkErrorMessage();
+
+ $ret .= $display->displayHeaderText($header_text);
+ $ret .= $display->displayLine();
+
+ // table
+ $ret .= "
+ <table class='help'>
+ " . $handset_feature_codes_header . "
+ " . $handset_feature_codes_body . "
+ </table>";
+
+ return $ret;
+ }
+
+}
+
+?>
diff --git a/fs_selfservice/fri/modules/followme.module b/fs_selfservice/fri/modules/followme.module
new file mode 100644
index 000000000..85a1f3776
--- /dev/null
+++ b/fs_selfservice/fri/modules/followme.module
@@ -0,0 +1,678 @@
+<?php
+
+/**
+ * @file
+ * Functions for the interface to the call monitor recordings
+ */
+
+/**
+ * Class for Followme
+ */
+class followme {
+
+ var $protocol_table;
+ var $protocol_config_files;
+
+ /*
+ * rank (for prioritizing modules)
+ */
+ function rank() {
+
+ $rank = 5;
+ return $rank;
+ }
+
+ /*
+ * init
+ */
+ function init() {
+
+ }
+
+ /*
+ * Adds menu item to nav menu
+ *
+ * @param $args
+ * Common arguments
+ */
+ function navMenu($args) {
+ global $ARI_ADMIN_USERNAME;
+
+ $exten = $_SESSION['ari_user']['extension'];
+ if ($exten!=$ARI_ADMIN_USERNAME) {
+ $ret .= "<p><small><small><a href='" . $_SESSION['ARI_ROOT'] . "?m=followme&f=display'>" . _("Follow Me") . "</a></small></small></p>";
+ }
+
+ return $ret;
+ }
+
+ /*
+ * Acts on the user settings
+ *
+ * @param $args
+ * Common arguments
+ * @param $a
+ * action
+ */
+ function action($args) {
+
+ global $STANDALONE;
+ global $ARI_ADMIN_USERNAME;
+ global $SETTINGS_ALLOW_VMX_SETTINGS;
+
+ // args
+ $m = getArgument($args,'m');
+ $a = getArgument($args,'a');
+
+ $lang_code = getArgument($args,'lang_code');
+
+ $follow_me_prering_time = getArgument($args,'follow_me_prering_time');
+ $follow_me_listring_time = getArgument($args,'follow_me_listring_time');
+ $follow_me_list = getArgument($args,'follow_me_list');
+ $follow_me_confirm = getArgument($args,'follow_me_confirm');
+ $follow_me_ddial = getArgument($args,'follow_me_ddial');
+ $follow_me_disabled = getArgument($args,'follow_me_disabled');
+
+ $language = new Language();
+
+ // Lets see if we can make heads or tails of this code?!?
+
+ // The action is 'update
+ if ($a=='update') {
+
+ // Get the extension and make sure we are not in
+ // admin mode
+ $exten = $_SESSION['ari_user']['extension'];
+ if ($exten!=$ARI_ADMIN_USERNAME) {
+
+
+ // Make sure Follow-Me setup has not been deleted for this user since the last refresh
+ $follow_me_disabled_delayed = $_COOKIE['ari_follow_me_disabled'];
+ if (! $_COOKIE['ari_follow_me_disabled']) {
+
+ $follow_me_disabled = ($this->getFollowMeListRingTime($exten) > 0)?0:1;
+
+ if ($follow_me_disabled) {
+
+ setcookie("ari_follow_me_disabled", $follow_me_disabled, time()+365*24*60*60);
+ $follow_me_disabled_delayed = $follow_me_disabled;
+ $_SESSION['ari_error'] =
+ _("Your Follow-Me has been disabled, REFRESH your browser to remove this message") . "<br>" .
+ sprintf(_("Check with your Telephone System Administrator if you think there is a problem"));
+ }
+ }
+
+
+
+ if (! $follow_me_disabled_delayed) {
+
+ // assume no errors, don't update SQL if errors occured
+ $follow_me_update_succeeded=1;
+
+ // update follow me pre-ring time
+ if (!$STANDALONE['use']) {
+
+ $stripped_follow_me_prering_time = preg_replace('/-|\s/','',$follow_me_prering_time);
+ if (!is_numeric($stripped_follow_me_prering_time)) {
+ $_SESSION['ari_error'] =
+ _("Follow-Me pre-ring time not changed") . "<br>" .
+ sprintf(_("Number %s must be an interger number of seconds"),$follow_me_prering_time);
+ $follow_me_update_succeeded=0;
+ }
+ else {
+
+ // set database
+ $this->setFollowMePreRingTime($exten,$stripped_follow_me_prering_time);
+
+ // store cookie
+ $stripped = preg_replace('/-|\s/','',$_COOKIE['ari_follow_me_prering_time']);
+ if ($follow_me_prering_time && $stripped!=$stripped_follow_me_prering_time) {
+ setcookie("ari_follow_me_prering_time", $follow_me_prering_time, time()+365*24*60*60);
+ }
+ }
+ }
+
+ // update follow me list ring time
+ if (!$STANDALONE['use']) {
+
+ $stripped_follow_me_listring_time = preg_replace('/-|\s/','',$follow_me_listring_time);
+ if (!is_numeric($stripped_follow_me_listring_time)) {
+ $_SESSION['ari_error'] =
+ _("Follow-Me list ring time not changed") . "<br>" .
+ sprintf(_("Number %s must be an interger number of seconds"),$follow_me_listring_time);
+ $follow_me_update_succeeded=0;
+ }
+ else {
+
+ // set database
+ $this->setFollowMeListRingTime($exten,$stripped_follow_me_listring_time);
+
+ // store cookie
+ $stripped = preg_replace('/-|\s/','',$_COOKIE['ari_follow_me_listring_time']);
+ if ($follow_me_listring_time && $stripped!=$stripped_follow_me_listring_time) {
+ setcookie("ari_follow_me_listring_time", $follow_me_listring_time, time()+365*24*60*60);
+ }
+ }
+ }
+
+ // update follow me list
+ if (!$STANDALONE['use']) {
+
+ $grplist = explode("\n", $follow_me_list);
+
+ if (!$grplist) {
+ $grplist = null;
+ }
+
+ foreach (array_keys($grplist) as $key) {
+ //trim it
+ $grplist[$key] = trim($grplist[$key]);
+
+ // Lookup the extension and append hash if not a user, and remove invalid chars
+ $grplist[$key] = $this->lookupSetExtensionFormat($grplist[$key]);
+
+ // remove blanks
+ if ($grplist[$key] == "") unset($grplist[$key]);
+ }
+
+ // check for duplicates, and re-sequence
+ $grplist = array_values(array_unique($grplist));
+
+ $stripped_follow_me_list = implode("-",$grplist);
+
+ if ($stripped_follow_me_list == "") {
+ $_SESSION['ari_error'] =
+ _("Follow-Me list must contain at least one valid number") . "<br>" .
+ sprintf(_("The following: %s is not valid"),$follow_me_list);
+ $follow_me_update_succeeded=0;
+ }
+ else {
+
+ // set database
+ $this->setFollowMeList($exten,$stripped_follow_me_list);
+
+ // store cookie
+ $stripped = preg_replace('/|\(|\)|\s/','',$_COOKIE['ari_follow_me_list']);
+ if ($follow_me_list && $stripped!=$stripped_follow_me_list) {
+ setcookie("ari_follow_me_list", $follow_me_list, time()+365*24*60*60);
+ }
+ }
+ }
+
+ // update follow me confirm
+ if (!$STANDALONE['use']) {
+
+ // set database
+ $this->setFollowMeConfirm($exten,$follow_me_confirm);
+ $this->setFollowMeDDial($exten,$follow_me_ddial);
+
+ // store cookie
+ setcookie("ari_follow_me_confirm", $follow_me_confirm, time()+365*24*60*60);
+ setcookie("ari_follow_me_ddial", $follow_me_ddial, time()+365*24*60*60);
+ }
+
+ //If no errors than update the SQL table to keep in sync
+ if ($follow_me_update_succeeded) {
+ $this->setFollowMeMySQL($exten, $follow_me_prering_time, $follow_me_listring_time, $follow_me_list, $follow_me_confirm);
+ }
+
+ } //if !follow_me_disabled
+ }
+ }
+
+ // redirect to see updated page
+ $ret .= "
+ <head>
+ <script>
+ <!--
+ window.location = \"" . $_SESSION['ARI_ROOT'] . "?m=" . $m . "\"
+ // -->
+ </script>
+ </head>";
+
+ return $ret;
+ }
+
+ /*
+ * Displays stats page
+ *
+ * @param $args
+ * Common arguments
+ */
+ function display($args) {
+
+ global $STANDALONE;
+ global $ARI_ADMIN_USERNAME;
+ global $SETTINGS_PRERING_LOW;
+ global $SETTINGS_PRERING_HIGH;
+ global $SETTINGS_LISTRING_LOW;
+ global $SETTINGS_LISTRING_HIGH;
+
+ global $SETTINGS_FOLLOW_ME_LIST_MAX;
+
+ global $loaded_modules;
+
+ // args
+ $m = getArgument($args,'m');
+ $q = getArgument($args,'q');
+ $start = getArgument($args,'start');
+ $span = getArgument($args,'span');
+
+ $displayname = $_SESSION['ari_user']['displayname'];
+ $exten = $_SESSION['ari_user']['extension'];
+
+ $language = new Language();
+ $display = new DisplaySearch();
+
+ // build controls
+ if ($exten!=$ARI_ADMIN_USERNAME) {
+
+ // call forward settings
+ if (!$STANDALONE['use']) {
+
+ $follow_me_prering_time = $this->getFollowMePreRingTime($exten);
+ $follow_me_listring_time = $this->getFollowMeListRingTime($exten);
+ $follow_me_list = explode("-", $this->getFollowMeList($exten) );
+ $follow_me_confirm = $this->getFollowMeConfirm($exten);
+ $follow_me_ddial = $this->getFollowMeDDial($exten);
+
+ $FOLLOW_ME_LIST_MAX = (count($follow_me_list) > $SETTINGS_FOLLOW_ME_LIST_MAX) ? count($follow_me_list):$SETTINGS_FOLLOW_ME_LIST_MAX;
+
+ //TODO: Set this better than this?
+ $follow_me_disabled = ($follow_me_listring_time > 0)?0:1;
+ setcookie("ari_follow_me_disabled", $follow_me_disabled, time()+365*24*60*60);
+
+ $followme_text.= "<table class='settings'>";
+
+ if (!$follow_me_disabled) {
+ // $followme_text .= "<tr><td><h3><br>" . _("Follow Me") . "</h3></td></tr>";
+ $followme_text .= "<tr><td>&nbsp;</td></tr>"; // Blank Line
+
+ $followme_text .= "<tr><td><a href='#' class='info'>" . _("Enable") . "<span>";
+ $followme_text .= _( "Dial-by-name Directory, IVR, and internal
+ calls will ring the numbers in the FollowMe
+ List. Any FreePBX routes that directly
+ reference a FollowMe are unaffected by this
+ enable/disable setting.");
+ $followme_text .= "<br></span></a></td>";
+
+ $followme_text .= "<td><input " . $follow_me_ddial . " type=checkbox name='follow_me_ddial' value='checked'></td></tr>";
+
+ $followme_text .= "<tr><td>&nbsp;</td></tr>"; // Blank Line
+ $followme_text .= "<tr><td valign='top'><a href='#' class='info'>" . _("Follow Me List:");
+ $followme_text .= "<span>" . sprintf(_("Extensions and outside numbers to ring next.")) ."<br/><br/>";
+ $followme_text .= sprintf(_("Include %s to keep it ringing."),"<strong>".$exten."</strong>") . "<br></span></a></td>";
+ $followme_text .= "<td><textarea " . $follow_me_list_options . " id='follow_me_list' name='follow_me_list' type='text' cols='20' rows='".$FOLLOW_ME_LIST_MAX."' value='' onKeyUp='rowCounter(this.form.follow_me_list, ".$FOLLOW_ME_LIST_MAX.");' onKeyDown='rowCounter(this.form.follow_me_list, ".$FOLLOW_ME_LIST_MAX.");'>".implode("\n",$follow_me_list)."</textarea>";
+ $followme_text .= "</td></tr>";
+
+ $followme_text .= "<tr><td>&nbsp;</td></tr>"; // Blank Line
+ $followme_text .= "<tr><td><a href='#' class='info'>";
+ $followme_text .= sprintf(_("Ring %s First For:"), $exten);
+ $followme_text .= "<span>" . sprintf( _("Time to ring extension %s before ringing the %s Follow Me List %s"), "<strong>".$exten."</strong>","<strong>","</strong>");
+ $followme_text .= "<br></span></a></td><td>";
+
+ $followme_text .= "<select " . $follow_me_prering_time_text_box_options . " name='follow_me_prering_time'/>";
+ $default_prering = $follow_me_prering_time;
+ for ($i=$SETTINGS_PRERING_LOW; $i <= $SETTINGS_PRERING_HIGH; $i++) {
+ $followme_text .= '<option value="'.$i.'" '.($i == $default_prering ? 'SELECTED' : '').'>'.$i.'</option>';
+ }
+ $followme_text .= "</select>";
+
+ $followme_text .= "<small>" . _("seconds") . "</small>";
+ $followme_text .= "</td></tr>";
+
+ $followme_text .= "<tr><td><a href='#' class='info'>" . _("Ring Followme List for:") . "<span>" . _("Time to ring the Follow Me List.") . "<br></span></a></td>";
+ $followme_text .= "<td>";
+
+ $followme_text .= "<select " . $follow_me_listring_time_text_box_options . " name='follow_me_listring_time'/>";
+ $default_listring = $follow_me_listring_time;
+ for ($i=$SETTINGS_LISTRING_LOW; $i <= $SETTINGS_LISTRING_HIGH; $i++) {
+ $followme_text .= '<option value="'.$i.'" '.($i == $default_listring ? 'SELECTED' : '').'>'.$i.'</option>';
+ }
+ $followme_text .= "</select>";
+
+ $followme_text .= "<small>" . _("seconds") . "</small></td></tr>";
+
+
+ $followme_text .= "<tr><td>&nbsp;</td></tr>"; // Blank Line
+
+ $followme_text .= "<tr><td><a href='#' class='info'>" . _("Use Confirmation:") . "<span>". _("Outside lines that are part of the Follow Me List will be called and offered a menu:<br/><br/> \"You have an incoming call. Press 1 to accept or 2 to decline.\"<br/><br/> This keeps calls from ending up in external voicemail. Make sure that the List Ring Time is long enough to allow for you to hear and react to this message.");
+ $followme_text .= "<br></span></a></td><td>";
+ $followme_text .= "<input " . $follow_me_confirm . " type=checkbox name='follow_me_confirm' value='checked'>";
+ $followme_text .= "<small>" . _("Enable") . "</small></td></tr>";
+ $followme_text .= "<tr><td>&nbsp;</td></tr>"; // Blank Line
+ $followme_text .= "</table>";
+ }
+ }
+
+ }
+
+ // build page content
+ $ret .= checkErrorMessage();
+
+ if ($_SESSION['ari_user']['admin_settings']) {
+ $headerText = _("Followme Settings");
+ } else {
+ $headerText = sprintf(_("Followme Settings for %s (%s)"),$displayname,$exten);
+ }
+
+ $ret .= $display->displayHeaderText($headerText);
+ $ret .= $display->displayLine();
+
+ $ret .=
+ "\n<SCRIPT LANGUAGE='JavaScript'>
+ <!-- Begin
+ function rowCounter(field, maxlimit) {
+ temp = field.value.split('\u000A',maxlimit+1)
+ field.value = temp.join('\u000A')
+ if (temp.length == maxlimit+1) {
+ field.value = field.value.substring(0, field.value.length-1)
+ }
+ }
+ // End -->
+ </script>\n";
+
+ $ret .=
+ "<form class='settings' name='ari_settings' action='' method='GET'>
+ <input type=hidden name=m value=" . $m . ">
+ <input type=hidden name=f value='action'>
+ <input type=hidden name=a value='update'>
+ " . $followme_text . "
+ <br>
+ <input name='submit' type='submit' value='" . _("Update") . "'>
+ </form>";
+
+ return $ret;
+ }
+
+
+ /*
+ * Sets Follow Me Pre-Ring Time
+ *
+ * @param $exten
+ * Extension to modify
+ * @param $follow_me_prering_time
+ * Pre-Ring Time to ring
+ */
+ function setFollowMePreRingTime($exten,$follow_me_prering_time) {
+
+ global $asterisk_manager_interface;
+
+ $value_opt = $follow_me_prering_time;
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database put AMPUSER $exten/followme/prering $value_opt\r\n\r\n");
+ }
+
+ /*
+ * Gets Follow Me Pre-Ring Time if set
+ *
+ * @param $exten
+ * Extension to get information about
+ * @return $number
+ * follow me pre-ring time returned if set
+ */
+ function getFollowMePreRingTime($exten) {
+
+ global $asterisk_manager_interface;
+
+ $number = '';
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database get AMPUSER $exten/followme/prering\r\n\r\n");
+ if (is_numeric($response)) {
+ $number = $response;
+ }
+
+ $stripped = preg_replace('/-|\(|\)|\s/','',$_COOKIE['ari_follow_me_prering_time']);
+ if ($stripped==$number) {
+ $number = $_COOKIE['ari_follow_me_prering_time'];
+ }
+
+ return $number;
+ }
+
+ /*
+ * Sets Follow Me List Ring Time
+ *
+ * @param $exten
+ * Extension to modify
+ * @param $follow_me_listring_time
+ * List Ring Time to ring
+ */
+ function setFollowMeListRingTime($exten,$follow_me_listring_time) {
+
+ global $asterisk_manager_interface;
+
+ $value_opt = $follow_me_listring_time;
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database put AMPUSER $exten/followme/grptime $value_opt\r\n\r\n");
+ }
+
+ /*
+ * Gets Follow Me List-Ring Time if set
+ *
+ * @param $exten
+ * Extension to get information about
+ * @return $number
+ * follow me list-ring time returned if set
+ */
+ function getFollowMeListRingTime($exten) {
+
+ global $asterisk_manager_interface;
+
+ $number = '';
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database get AMPUSER $exten/followme/grptime\r\n\r\n");
+ if (is_numeric($response)) {
+ $number = $response;
+ }
+
+ $stripped = preg_replace('/-|\(|\)|\s/','',$_COOKIE['ari_follow_me_listring_time']);
+ if ($stripped==$number) {
+ $number = $_COOKIE['ari_follow_me_listring_time'];
+ }
+
+ return $number;
+ }
+
+ /*
+ * Sets Follow Me List
+ *
+ * @param $exten
+ * Extension to modify
+ * @param $follow_me_list
+ * Follow Me List
+ */
+ function setFollowMeList($exten,$follow_me_list) {
+
+ global $asterisk_manager_interface;
+
+ $value_opt = $follow_me_list;
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database put AMPUSER $exten/followme/grplist $value_opt\r\n\r\n");
+ }
+
+ /*
+ * Gets Follow Me List if set
+ *
+ * @param $exten
+ * Extension to get information about
+ * @return $data
+ * follow me list if set
+ */
+ function getFollowMeList($exten) {
+
+ global $asterisk_manager_interface;
+
+ $number = '';
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database get AMPUSER $exten/followme/grplist\r\n\r\n");
+
+ //TODO: really need to check for a bogus response, see how other side does it
+ //
+ return preg_replace("/[^0-9*\-]/", "", $response);
+ }
+
+ /*
+ * Sets Follow Confirmation Setting
+ *
+ * @param $exten
+ * Extension to modify
+ * @param $follow_me_cofirm
+ * Follow Me Confirm Setting
+ */
+ function setFollowMeConfirm($exten,$follow_me_confirm) {
+
+ global $asterisk_manager_interface;
+
+ $value_opt = ($follow_me_confirm)?'ENABLED':'DISABLED';
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database put AMPUSER $exten/followme/grpconf $value_opt\r\n\r\n");
+ }
+
+ /*
+ * Gets Follow Me Confirmation Setting
+ *
+ * @param $exten
+ * Extension to get information about
+ * @return $data
+ * follow me confirm setting
+ */
+ function getFollowMeConfirm($exten) {
+
+ global $asterisk_manager_interface;
+
+ $number = '';
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database get AMPUSER $exten/followme/grpconf\r\n\r\n");
+
+ if (preg_match("/ENABLED/",$response)) {
+ $response='checked';
+ }
+ else {
+ $response='';
+ }
+
+ //TODO: really need to check for a bogus response, see how other side does it
+ //
+ return $response;
+
+ }
+
+ /*
+ * Sets Follow Ddial Setting
+ *
+ * @param $exten
+ * Extension to modify
+ * @param $follow_me_ddial
+ * Follow Me Ddial Setting
+ */
+ function setFollowMeDDial($exten,$follow_me_ddial) {
+
+ global $asterisk_manager_interface;
+
+ $value_opt = ($follow_me_ddial)?'DIRECT':'EXTENSION';
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database put AMPUSER $exten/followme/ddial $value_opt\r\n\r\n");
+ }
+
+ /*
+ * Gets Follow Me Ddial Setting
+ *
+ * @param $exten
+ * Extension to get information about
+ * @return $data
+ * follow me ddial setting
+ */
+ function getFollowMeDDial($exten) {
+
+ global $asterisk_manager_interface;
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database get AMPUSER $exten/followme/ddial\r\n\r\n");
+
+ if (preg_match("/EXTENSION/",$response)) {
+ $response='';
+ }
+ else {
+ $response='checked';
+ }
+
+ //TODO: really need to check for a bogus response, see how other side does it
+ //
+ return $response;
+
+ }
+
+
+
+
+
+ /*
+ * Gets FreePBX Version
+ */
+ function getFreePBXVersion() {
+
+ if (isset($_SESSION['dbh_asterisk'])) {
+ $sql = "SELECT * FROM admin WHERE variable = 'version'";
+ $results = $_SESSION['dbh_asterisk']->getAll($sql);
+ if(DB::IsError($results)) {
+ $_SESSION['ari_error'] = $results->getMessage();
+ }
+
+ return $results[0][1];
+ }
+ }
+
+ /*
+ * Sets Follow-Me Settings in FreePBX MySQL Database
+ *
+ * @param $exten
+ * Extension to modify
+ * @param $follow_me_prering_time
+ * Pre-Ring Time to ring
+ * @param $follow_me_listring_time
+ * List Ring Time to ring
+ * @param $follow_me_list
+ * Follow Me List
+ * @param $follow_me_list
+ * Follow Me Confirm Setting
+ *
+ */
+ function setFollowMeMySQL($exten, $follow_me_prering_time, $follow_me_listring_time, $follow_me_list, $follow_me_confirm) {
+
+ if (isset($_SESSION['dbh_asterisk'])) {
+
+ //format for SQL database
+ $follow_me_confirm = ($follow_me_confirm)?'CHECKED':'';
+
+ $sql = "UPDATE findmefollow SET grptime = '" . $follow_me_listring_time . "', grplist = '".
+ str_replace("'", "''", trim($follow_me_list)) . "', pre_ring = '" . $follow_me_prering_time .
+ "', needsconf = '" . $follow_me_confirm . "' WHERE grpnum = $exten LIMIT 1";
+ $results = $_SESSION['dbh_asterisk']->query($sql);
+
+ if(DB::IsError($results)) {
+ $_SESSION['ari_error'] = $results->getMessage();
+ }
+
+ return 1;
+ }
+ }
+
+ function lookupSetExtensionFormat($exten) {
+
+ if (trim($exten) == "") return $exten;
+
+ $exten = preg_replace("/[^0-9*]/", "", $exten);
+
+ $sql = "SELECT extension FROM users WHERE extension = '".$exten."'";
+ $asa = $_SESSION['dbh_asterisk']->getrow($sql, DB_FETCHMODE_ASSOC);
+ if (!is_array($asa)) {
+ return $exten.'#';
+ } else {
+ return $exten;
+ }
+ }
+
+
+} // class
+
+?>
diff --git a/fs_selfservice/fri/modules/myaccount.module b/fs_selfservice/fri/modules/myaccount.module
new file mode 100644
index 000000000..6b7cb839b
--- /dev/null
+++ b/fs_selfservice/fri/modules/myaccount.module
@@ -0,0 +1,109 @@
+<?php
+
+/**
+ * @file
+ * Functions for the interface to the help page
+ */
+
+/**
+ * Class for help
+ */
+class myaccount {
+
+ /*
+ * rank (for prioritizing modules)
+ */
+ function rank() {
+
+ $rank = 9;
+ return $rank;
+ }
+
+ /*
+ * init
+ */
+ function init() {
+ }
+
+ /*
+ * Adds menu item to nav menu
+ *
+ * @param $args
+ * Common arguments
+ */
+ function navMenu($args) {
+
+ $ret .= "<p><small><small><a href='" . $_SESSION['ARI_ROOT'] . "?m=myaccount&f=display'>" . _("My Account") . "</a></small></small></p><br>";
+
+ return $ret;
+ }
+
+ /*
+ * Displays stats page
+ *
+ * @param $args
+ * Common arguments
+ */
+ function display($args) {
+
+ global $ARI_HELP_FEATURE_CODES;
+
+ $display = new Display();
+
+ // args
+ $m = getArgument($args,'m');
+ $q = getArgument($args,'q');
+
+ $displayname = $_SESSION['ari_user']['displayname'];
+ $extension = $_SESSION['ari_user']['extension'];
+
+ // build page content
+ $ret .= checkErrorMessage();
+
+ $header_text = _("My Account");
+ if (!$_SESSION['ari_user']['admin_help']) {
+ $header_text .= sprintf(_(" for %s (%s)"), $displayname, $extension);
+ }
+
+ // build page content
+ $ret .= checkErrorMessage();
+
+ $ret .= $display->displayHeaderText($header_text);
+ $ret .= $display->displayLine();
+
+ $freeside = new FreesideSelfService();
+ $fs_info = $freeside->customer_info( array(
+ 'session_id' => $_SESSION['freeside_session_id'],
+ ) );
+ $error = $fs_info['error'];
+ if ( $error ) {
+ //$_SESSION['ari_error'] = _("Incorrect Username or Password");
+ $_SESSION['ari_error'] = $error; #// XXX report as ari_error???!
+ }
+
+ $ret .= $fs_info['small_custview'];
+ $ret .= '<BR>';
+
+
+ $ret .= '<B><A HREF="/selfservice/selfservice.cgi?session='.
+ $_SESSION['freeside_session_id'].
+ ';action=change_bill">Change billing address</A></B>';
+
+ $ret .= '&nbsp;&nbsp;|&nbsp;&nbsp;';
+
+ $ret .= '<B><A HREF="/selfservice/selfservice.cgi?session='.
+ $_SESSION['freeside_session_id'].
+ ';action=change_ship">Change service address</A></B>';
+
+ $ret .= '<BR><BR>';
+
+ $ret .= '<B><A HREF="/selfservice/selfservice.cgi?session='.
+ $_SESSION['freeside_session_id'].
+ ';action=change_pay">Change payment information</A></B><BR><BR>';
+
+ return $ret;
+ }
+
+}
+
+?>
diff --git a/fs_selfservice/fri/modules/phonefeatures.module b/fs_selfservice/fri/modules/phonefeatures.module
new file mode 100644
index 000000000..89dc903bf
--- /dev/null
+++ b/fs_selfservice/fri/modules/phonefeatures.module
@@ -0,0 +1,342 @@
+<?php
+//*****************************************************************************
+class PhoneFeatures {
+//*****************************************************************************
+ function rank() {
+
+ $rank = 4;
+ return $rank;
+ }
+
+//*****************************************************************************
+ function init() {
+ }
+//*****************************************************************************
+ function navMenu($args) {
+
+ global $ARI_NO_LOGIN;
+ global $SETTINGS_ALLOW_PHONE_SETTINGS;
+ global $SETTINGS_ALLOW_CALLFORWARD_SETTINGS;
+
+ // If we're not allowing call forwarding AND PHONE SETTINGS get out of here
+ if (!$SETTINGS_ALLOW_PHONE_SETTINGS && !$SETTINGS_ALLOW_CALLFORWARD_SETTINGS) return "";
+
+ $ret .= "
+ <p><small><small><a href='" . $_SESSION['ARI_ROOT'] . "?m=PhoneFeatures&f=display'>" . _("Phone Features") . "</a></small></small></p>";
+
+ return $ret;
+ }
+//*****************************************************************************
+ function action($args) {
+
+ global $ARI_ADMIN_USERNAME;
+ global $SETTINGS_ALLOW_PHONE_SETTINGS;
+ global $SETTINGS_ALLOW_CALLFORWARD_SETTINGS;
+
+ // args
+ $m = getArgument($args,'m');
+ $a = getArgument($args,'a');
+ $lang_code = getArgument( $args,'lang_code');
+ $exten = $_SESSION['ari_user']['extension'];
+
+ if ($a=='update') {
+
+ if ($SETTINGS_ALLOW_PHONE_SETTINGS) {
+ if ($exten!=$ARI_ADMIN_USERNAME) {
+ $this->storePhoneSetting( $args, $exten, 'call_waiting', 'CW', 'ENABLED');
+ $this->storePhoneSetting( $args, $exten, 'do_not_disturb', 'DND', 'YES');
+ }
+ }
+
+ if ($SETTINGS_ALLOW_CALLFORWARD_SETTINGS) {
+ if ($exten!=$ARI_ADMIN_USERNAME) {
+ $this->storeCallForwardNumber( $args, $exten, 'call_forward', 'CF');
+ $this->storeCallForwardNumber( $args, $exten, 'call_forward_busy', 'CFB');
+ $this->storeCallForwardNumber( $args, $exten, 'call_forward_unavailable', 'CFU');
+ }
+ }
+ }
+
+ // redirect to see updated page
+ $ret .= "
+ <head>
+ <script>
+ <!--
+ window.location = \"" . $_SESSION['ARI_ROOT'] . "?m=" . $m . "\"
+ // -->
+ </script>
+ </head>";
+
+ return $ret;
+ }
+//*****************************************************************************
+function display($args) {
+
+ global $STANDALONE;
+ global $ARI_ADMIN_USERNAME;
+ global $SETTINGS_ALLOW_PHONE_SETTINGS;
+ global $SETTINGS_ALLOW_CALLFORWARD_SETTINGS;
+
+ // args
+ $m = getArgument($args,'m');
+ $a = getArgument($args,'a');
+ $lang_code = getArgument( $args,'lang_code');
+ $exten = $_SESSION['ari_user']['extension'];
+
+ $displayname = $_SESSION['ari_user']['displayname'];
+ $exten = $_SESSION['ari_user']['extension'];
+
+ $display = new DisplaySearch();
+
+ // build controls
+ if ($exten!=$ARI_ADMIN_USERNAME) {
+
+ if ($SETTINGS_ALLOW_PHONE_SETTINGS) {
+ $dnd_cw_text = "<table class='settings'>";
+ $dnd_cw_text.= "<tr><td><h3>" . _("Phone Features") . "</h3></td></tr>";
+
+ $dnd_cw_text.= $this->displayPhoneControls( $exten, 'call_waiting', 'CW', "Call Waiting");
+ $dnd_cw_text.= $this->displayPhoneControls( $exten, 'do_not_disturb', 'DND', "Do Not Disturb");
+
+ $dnd_cw_text .= "</table>";
+ }
+
+ if ($SETTINGS_ALLOW_CALLFORWARD_SETTINGS) {
+
+ $set_call_forward_text .= "<SCRIPT LANGUAGE='JavaScript'>
+ <!-- Begin
+ function rowCounter(field, maxlimit) {
+ temp = field.value.split('\u000A',maxlimit+1)
+ field.value = temp.join('\u000A')
+ if (temp.length == maxlimit+1) {
+ field.value = field.value.substring(0, field.value.length-1)
+ }
+ }
+
+ function disable_fields() {
+
+ if (document.ari_settings.call_forward_enable.checked) {
+ document.ari_settings.call_forward_number.style.backgroundColor = '#FFF';
+ document.ari_settings.call_forward_number.disabled = false;
+ }
+ else {
+ document.ari_settings.call_forward_number.style.backgroundColor = '#DDD';
+ document.ari_settings.call_forward_number.disabled = true;
+ }
+
+ if (document.ari_settings.call_forward_busy_enable.checked) {
+ document.ari_settings.call_forward_busy_number.style.backgroundColor = '#FFF';
+ document.ari_settings.call_forward_busy_number.disabled = false;
+ }
+ else {
+ document.ari_settings.call_forward_busy_number.style.backgroundColor = '#DDD';
+ document.ari_settings.call_forward_busy_number.disabled = true;
+ }
+
+ if (document.ari_settings.call_forward_unavailable_enable.checked) {
+ document.ari_settings.call_forward_unavailable_number.style.backgroundColor = '#FFF';
+ document.ari_settings.call_forward_unavailable_number.disabled = false;
+ }
+ else {
+ document.ari_settings.call_forward_unavailable_number.style.backgroundColor = '#DDD';
+ document.ari_settings.call_forward_unavailable_number.disabled = true;
+ }
+ }
+ // End -->
+ </script>";
+
+ $set_call_forward_text.= "<table class='settings'>";
+ $set_call_forward_text.= "<tr><td><h3>" . _("Call Forwarding") . "</h3></td></tr>";
+
+ $set_call_forward_text.= $this->displayCallForwardControls( $exten, 'call_forward', 'CF', "Unconditional:");
+ $set_call_forward_text.= $this->displayCallForwardControls( $exten, 'call_forward_unavailable', 'CFU', "Unavailable:");
+ $set_call_forward_text.= $this->displayCallForwardControls( $exten, 'call_forward_busy', 'CFB', "Busy:");
+
+ $set_call_forward_text .= "</table>";
+ }
+ }
+
+ // build page content
+ $ret .= checkErrorMessage();
+
+ if ($_SESSION['ari_user']['admin_settings']) {
+ $headerText = _("Phone Features");
+ } else {
+ $headerText = sprintf(_("Phone Features for %s (%s)"),$displayname,$exten);
+ }
+
+ $ret .= $display->displayHeaderText($headerText);
+ $ret .= $display->displayLine();
+ $ret .= "
+ <form class='settings' name='ari_settings' action='' method='GET'>
+ <input type=hidden name=m value=" . $m . ">
+ <input type=hidden name=f value='action'>
+ <input type=hidden name=a value='update'>
+ <br>
+ " . $dnd_cw_text . "
+ <br>
+ " . $set_call_forward_text . "
+ <br>
+ <input name='submit' type='submit' value='" . _("Update") . "'>
+ </form>";
+
+return $ret;
+}
+//*****************************************************************************
+ function setPhoneSetting( $databaseCallFwdType, $exten, $state_value) {
+
+ global $asterisk_manager_interface;
+
+ $type_opt = ($state_value != "") ? "put":"del";
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database $type_opt $databaseCallFwdType $exten $state_value\r\n\r\n");
+ }
+
+//*****************************************************************************
+ function getPhoneSetting($exten, $databaseCallFwdType) {
+
+ global $asterisk_manager_interface;
+ $number = '';
+
+ $result = false;
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database get $databaseCallFwdType $exten\r\n\r\n");
+ if (stristr($response, 'ENABLED')) {
+ $result = true;
+ }
+ elseif (stristr($response, 'YES')) {
+ $result = true;
+ }
+
+ return $result;
+ }
+//*****************************************************************************
+ function storePhoneSetting( $args, $exten, $settingType, $databaseCallFwdType, $state_value)
+ {
+ $setting_enable = getArgument( $args, $settingType . '_enable');
+
+ $this->setPhoneSetting( $databaseCallFwdType, $exten, ($setting_enable == 'checked')?$state_value:"");
+ }
+
+//*****************************************************************************
+ function displayPhoneControls( $exten, $callFwdType, $databaseCallFwdType, $title)
+ {
+
+ $phone_setting_enable = ($this->getPhoneSetting($exten, $databaseCallFwdType)) ? 'checked':'';
+
+ $ret = "\n<tr>";
+ $ret.= "<td>";
+ $ret.= "<label><input " . $phone_setting_enable . " type=checkbox name='" . $callFwdType . "_enable' value='checked' >";
+ $ret.= "<small>" . _($title) . "</small></label>";
+ $ret.= "</td>";
+ $ret.= "</tr>\n";
+
+ return $ret;
+ }
+//*****************************************************************************
+ /*
+ * Sets Asterisk call forward setting
+ *
+ * @param $exten
+ * Extension to modify
+ * @param $state
+ * Call forward enable or disable
+ * @param $call_forward_number
+ * Call forward number
+ * @param $variable_opt
+ * Call forward type (CF, CFU, CFB)
+ */
+ function setCallForward($exten,$state,$call_forward_number, $variable_opt = "CF") {
+
+ global $asterisk_manager_interface;
+
+ if ($state) {
+ $type_opt = "put";
+ $value_opt = $call_forward_number;
+ }
+ else {
+ $type_opt = "del";
+ }
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database $type_opt $variable_opt $exten $value_opt\r\n\r\n");
+ }
+
+ /*
+ * Gets call forward number if set
+ *
+ * @param $exten
+ * Extension to get information about
+ * @return $number
+ * call forward number returned if set
+ * @param $variable_opt
+ * Call forward type (CF, CFU, CFB)
+ */
+ function getCallForwardNumber($exten, $variable_opt = "CF") {
+
+ global $asterisk_manager_interface;
+
+ $number = '';
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database get $variable_opt $exten\r\n\r\n");
+ if (is_numeric($response)) {
+ $number = $response;
+ }
+
+ $stripped = preg_replace('/-|\(|\)|\s/','',$_COOKIE['ari_call_forward_number']);
+ if ($stripped==$number) {
+ $number = $_COOKIE['ari_call_forward_number'];
+ }
+
+ return $number;
+ }
+
+
+ function storeCallForwardNumber( $args, $exten, $callFwdType, $databaseCallFwdType)
+ {
+ $call_forward_enable = getArgument($args, $callFwdType . '_enable');
+ $call_forward_number = getArgument($args, $callFwdType . '_number');
+
+ $stripped_call_forward_number = preg_replace('/-|\(|\)|\s/','',$call_forward_number);
+
+ if ($call_forward_enable && !is_numeric($stripped_call_forward_number)) {
+ $_SESSION['ari_error'] = _("Call forward number not changed") . "<br>" .
+ sprintf(_("Number %s must contain dial numbers (characters like '(', '-', and ')' are ok)"), $call_forward_number);
+ }
+ else {
+ $this->setCallForward( $exten, $call_forward_enable, $stripped_call_forward_number, $databaseCallFwdType);
+
+ // store cookie
+ $stripped = preg_replace('/-|\(|\)|\s/','',$_COOKIE['ari_' . $callFwdType]);
+ if ($call_forward_number && $stripped!=$stripped_call_forward_number) {
+ setcookie('ari_' . $callFwdType, $call_forward_number, time()+365*24*60*60);
+ }
+ }
+ }
+
+ function displayCallForwardControls( $exten, $callFwdType, $databaseCallFwdType, $title)
+ {
+ $call_forward_number = $this->getCallForwardNumber($exten, $databaseCallFwdType);
+
+ // If we have a value, we want the item checked
+ if ($call_forward_number) {
+ $call_forward_enable = 'checked';
+ }
+ else {
+ $call_forward_number = $_COOKIE['ari_' . $callFwdType ];
+ $call_forward_text_box_options = "disabled style='background: #DDD;'";
+ }
+
+ $ret = "\n<tr>";
+ $ret.= "<td>" . _($title) . "</td>";
+ $ret.= "<td>";
+ $ret.= "<input " . $call_forward_text_box_options . " name='" . $callFwdType . "_number' type='text' size=24 value='" . $call_forward_number . "'>";
+ $ret.= "</td>";
+ $ret.= "<td>";
+ $ret.= "<input " . $call_forward_enable . " type=checkbox name='" . $callFwdType . "_enable' value='checked' OnClick=\"disable_fields(); return true;\">";
+ $ret.= "<small>" . _("Enable") . "</small>";
+ $ret.= "</td>";
+ $ret.= "</tr>\n";
+
+ return $ret;
+ }
+} // class
+?>
diff --git a/fs_selfservice/fri/modules/settings.module b/fs_selfservice/fri/modules/settings.module
new file mode 100644
index 000000000..f20eb0253
--- /dev/null
+++ b/fs_selfservice/fri/modules/settings.module
@@ -0,0 +1,813 @@
+<?php
+
+/**
+ * @file
+ * Functions for the interface to the call monitor recordings
+ */
+
+/**
+ * Class for settings
+ */
+class Settings {
+
+ var $protocol_table;
+ var $protocol_config_files;
+
+ /*
+ * rank (for prioritizing modules)
+ */
+ function rank() {
+
+ $rank = 9;
+ return $rank;
+ }
+
+ /*
+ * init
+ */
+ function init() {
+
+ // determine what protocol user is using
+ global $ASTERISK_PROTOCOLS;
+
+ foreach ($ASTERISK_PROTOCOLS as $protocol => $value) {
+ $data = $this->getProtocolRecordSettings($value['table'],$_SESSION['ari_user']['extension']);
+ if (count($data)) {
+ $this->protocol_table = $value['table'];
+ $this->protocol_config_files = $value['config_files'];
+ break;
+ }
+ }
+ }
+
+ /*
+ * Adds menu item to nav menu
+ *
+ * @param $args
+ * Common arguments
+ */
+ function navMenu($args) {
+
+ $ret = "";
+ $exten = $_SESSION['ari_user']['extension'];
+
+ // and we are not logged in as admin
+ if ($exten!=$ARI_ADMIN_USERNAME) {
+ $ret .= "<p><small><small><a href='" . $_SESSION['ARI_ROOT'] . "?m=Settings&f=display'>" . _("Phone Settings") . "</a></small></small></p><br>";
+ }
+
+ return $ret;
+ }
+
+ /*
+ * Acts on the user settings
+ *
+ * @param $args
+ * Common arguments
+ * @param $a
+ * action
+ */
+ function action($args) {
+
+ global $ARI_ADMIN_USERNAME;
+ global $ASTERISK_VOICEMAIL_CONF;
+ global $SETTINGS_ALLOW_VOICEMAIL_SETTINGS;
+ global $SETTINGS_ALLOW_VOICEMAIL_PASSWORD_SET;
+ global $SETTINGS_VOICEMAIL_PASSWORD_LENGTH;
+ global $SETTINGS_VOICEMAIL_PASSWORD_EXACT;
+ global $SETTINGS_ALLOW_CALL_RECORDING_SET;
+
+ // args
+ $m = getArgument($args,'m');
+ $a = getArgument($args,'a');
+
+ $voicemail_password = getArgument($args,'voicemail_password');
+ $voicemail_password_confirm = getArgument($args,'voicemail_password_confirm');
+ $voicemail_email_address = getArgument($args,'voicemail_email_address');
+ $voicemail_pager_address = getArgument($args,'voicemail_pager_address');
+ $voicemail_email_enable = getArgument($args,'voicemail_email_enable');
+ $voicemail_audio_format = getArgument($args,'voicemail_audio_format');
+ $record_in = getArgument($args,'record_in');
+ $record_out = getArgument($args,'record_out');
+
+ if (isset($_SESSION['ari_user']['voicemail_email'])) {
+ foreach (array_keys($_SESSION['ari_user']['voicemail_email']) as $key) {
+ $var = "voicemail_email_$key";
+ $$var = getArgument($args,$var);
+ }
+ }
+
+ if ($a=='update') {
+
+ $exten = $_SESSION['ari_user']['extension'];
+ if ($exten!=$ARI_ADMIN_USERNAME) {
+
+ // Make sure Follow-Me setup has not been deleted for this user since the last refresh
+ $follow_me_disabled_delayed = $_COOKIE['ari_follow_me_disabled'];
+
+ // voicemail settings
+ if ($SETTINGS_ALLOW_VOICEMAIL_SETTINGS && $_SESSION['ari_user']['voicemail_enabled']==1) {
+
+
+ // update voicemail password
+ if ($SETTINGS_ALLOW_VOICEMAIL_PASSWORD_SET) {
+
+ // update voicemail password
+ if ($voicemail_password=='' || $voicemail_password_confirm=='') {
+ $_SESSION['ari_error'] =
+ _("Voicemail password not changed") . "<br>" .
+ _("Password and password confirm must not be blank");
+ }
+ else if ((strlen($voicemail_password)<$SETTINGS_VOICEMAIL_PASSWORD_LENGTH) || !is_numeric($voicemail_password)) {
+ $_SESSION['ari_error'] =
+ _("Voicemail password not changed") . "<br>" .
+ sprintf(_("Passwords must be all numbers and greater than %d digits"),$SETTINGS_VOICEMAIL_PASSWORD_LENGTH);
+ }
+ else if (strlen($voicemail_password)!=$SETTINGS_VOICEMAIL_PASSWORD_LENGTH && $SETTINGS_VOICEMAIL_PASSWORD_EXACT || !is_numeric($voicemail_password)) {
+ $_SESSION['ari_error'] =
+ _("Voicemail password not changed") . "<br>" .
+ sprintf(_("Passwords must be all numbers and only %d digits"),$SETTINGS_VOICEMAIL_PASSWORD_LENGTH);
+ }
+ else if ($voicemail_password!=$voicemail_password_confirm) {
+ $_SESSION['ari_error'] =
+ _("Voicemail password not changed") . "<br>" .
+ _("Password and password confirm do not match");
+ }
+ else {
+
+ // check for writable the files
+ $temp_file = $ASTERISK_VOICEMAIL_CONF . ".tmp";
+ $fp = fopen($temp_file, "w");
+ if (!$fp) {
+ $_SESSION['ari_error'] =
+ _("Voicemail password not changed") . "<br>" .
+ sprintf(_("%s does not exist or is not writable"),$temp_file);
+ }
+ else if (!is_writable($ASTERISK_VOICEMAIL_CONF)) {
+ $_SESSION['ari_error'] =
+ _("Voicemail password not changed") . "<br>" .
+ sprintf(_("%s does not exist or is not writable"),$ASTERISK_VOICEMAIL_CONF);
+ }
+ else {
+
+ // update session
+ $_SESSION['ari_user']['voicemail_password'] = $voicemail_password;
+
+ // save password
+ $lines = file($ASTERISK_VOICEMAIL_CONF);
+ foreach ($lines as $key => $line) {
+ unset($value);
+ list($var,$value) = split('=>',$line);
+ $var = trim($var);
+ if ($var==$exten && $value) {
+
+ // write out line with password change
+ $buf = split(',',$value);
+ $buf[0] = $voicemail_password;
+ $line = $var . " => " . join(',', $buf);
+
+ fwrite($fp, $line);
+ }
+ else {
+ // write out original line with no changes
+ fwrite($fp, $line);
+ }
+ }
+ fclose($fp);
+ unlink($ASTERISK_VOICEMAIL_CONF);
+ rename($temp_file,$ASTERISK_VOICEMAIL_CONF);
+
+ $voicemail_reload = 1;
+ }
+ }
+
+ // voicemail email address
+ if ($voicemail_email_enable &&
+ ($voicemail_email_address && !preg_match('/@/',$voicemail_email_address) ||
+ ($voicemail_pager_address && !preg_match('/@/',$voicemail_pager_address)))) {
+ $_SESSION['ari_error'] =
+ _("Voicemail email and pager address not changed") . "<br>" .
+ ("'$voicemail_email_address' and '$voicemail_pager_address' must be a valid email addresses");
+ }
+ else {
+
+ // check for writable the files
+ $temp_file = $ASTERISK_VOICEMAIL_CONF . ".tmp";
+ $fp = fopen($temp_file, "w");
+ if (!$fp) {
+ $_SESSION['ari_error'] =
+ _("Voicemail email settings not changed") . "<br>" .
+ sprintf(_("%s does not exist or is not writable"),$temp_file);
+ }
+ else if (!is_writable($ASTERISK_VOICEMAIL_CONF)) {
+ $_SESSION['ari_error'] =
+ _("Voicemail email settings not changed") . "<br>" .
+ sprintf(_("%s does not exist or is not writable"),$ASTERISK_VOICEMAIL_CONF);
+ }
+ else {
+
+ // store cookie
+ if ($voicemail_email_enable) {
+ setcookie("ari_voicemail_email_address", $voicemail_email_address, time()+365*24*60*60);
+ setcookie("ari_voicemail_pager_address", $voicemail_pager_address, time()+365*24*60*60);
+ foreach (array_keys($_SESSION['ari_user']['voicemail_email']) as $key) {
+ $var = "voicemail_email_$key";
+ $var_cookie = "ari_" . $var;
+ setcookie("$var_cookie", $$var, time()+365*24*60*60);
+ }
+ }
+
+ // update session
+ $_SESSION['ari_user']['voicemail_email_enable'] = $voicemail_email_enable;
+ if ($voicemail_email_enable) {
+ $_SESSION['ari_user']['voicemail_email_address'] = $voicemail_email_address;
+ $_SESSION['ari_user']['voicemail_pager_address'] = $voicemail_pager_address;
+ foreach (array_keys($_SESSION['ari_user']['voicemail_email']) as $key) {
+ $option = "voicemail_email_$key";
+ $_SESSION['ari_user']['voicemail_email'][$key] = $$option;
+ }
+ }
+
+ // save settings
+ if (!$voicemail_email_enable) {
+ $voicemail_email_address = '';
+ $voicemail_pager_address = '';
+ }
+
+ $lines = file($ASTERISK_VOICEMAIL_CONF);
+ foreach ($lines as $key => $line) {
+ unset($value);
+ list($var,$value) = split('=>',$line);
+ $var = trim($var);
+ if ($var==$exten && $value) {
+
+ // write out line with voicemail email change
+ $buf = split(',',$value);
+ $buf[2] = $voicemail_email_address;
+ $buf[3] = $voicemail_pager_address;
+
+ foreach ($_SESSION['ari_user']['voicemail_email'] as $key => $value) {
+ $option = "voicemail_email_$key";
+ if ($$option && $key) {
+ $options .= $key . "=" . $value;
+ }
+ else {
+ $options .= $key . "=no";
+ }
+ $options .= "|";
+ }
+ $buf[4] = substr($options, 0, -1);
+
+ $line = $var . " =>" . join(',', $buf);
+ if (substr($line, 0, -1)!="\n") {
+ $line .= "\n";
+ }
+
+ fwrite($fp, $line);
+ }
+ else {
+
+ // write out original line with no changes
+ fwrite($fp, $line);
+ }
+ }
+ fclose($fp);
+ unlink($ASTERISK_VOICEMAIL_CONF);
+ rename($temp_file,$ASTERISK_VOICEMAIL_CONF);
+
+ $voicemail_reload = 1;
+ }
+ }
+
+ // reload asterisk voicemail
+ if ($voicemail_reload) {
+ $this->reloadAsteriskVoicemail();
+ }
+ }
+
+ // update voicemail audio format setting
+ setcookie("ari_voicemail_audio_format", $voicemail_audio_format, time()+365*24*60*60);
+ }
+
+ // update call monitor record setting
+ if ($SETTINGS_ALLOW_CALL_RECORDING_SET) {
+ if ($record_in && $record_out) {
+ $this->setRecordSettings($exten,$record_in,$record_out);
+ }
+ }
+ }
+ }
+
+ // redirect to see updated page
+ $ret .= "
+ <head>
+ <script>
+ <!--
+ window.location = \"" . $_SESSION['ARI_ROOT'] . "?m=" . $m . "\"
+ // -->
+ </script>
+ </head>";
+
+ return $ret;
+ }
+
+ /*
+ * Displays stats page
+ *
+ * @param $args
+ * Common arguments
+ */
+ function display($args) {
+ global $SETTINGS_ALLOW_VOICEMAIL_SETTINGS;
+ global $SETTINGS_ALLOW_VOICEMAIL_PASSWORD_SET;
+ global $SETTINGS_VOICEMAIL_PASSWORD_LENGTH;
+ global $SETTINGS_VOICEMAIL_EMAIL_OPTION_DESCRIPTIONS;
+ global $ARI_VOICEMAIL_AUDIO_FORMAT_DEFAULT;
+ global $SETTINGS_ALLOW_CALL_RECORDING_SET;
+
+ global $loaded_modules;
+
+ // args
+ $m = getArgument($args,'m');
+ $q = getArgument($args,'q');
+ $start = getArgument($args,'start');
+ $span = getArgument($args,'span');
+
+ $displayname = $_SESSION['ari_user']['displayname'];
+ $exten = $_SESSION['ari_user']['extension'];
+
+ $language = new Language();
+ $display = new DisplaySearch();
+
+ // get data
+ $data = $this->getRecordSettings($_SESSION['ari_user']['extension']);
+
+ // lang setting options
+ if (extension_loaded('gettext')) {
+ $setLangText = "<p class='lang'>" . _("Language:") . " " . $language->GetForm() . "</p>";
+ }
+
+
+ // voicemail settings
+ if ($SETTINGS_ALLOW_VOICEMAIL_SETTINGS && $_SESSION['ari_user']['voicemail_enabled']==1 &&
+ in_array('voicemail',array_keys($loaded_modules))) {
+ if ($SETTINGS_ALLOW_VOICEMAIL_PASSWORD_SET) {
+
+ if ($SETTINGS_VOICEMAIL_PASSWORD_EXACT) {
+ $voicemail_password_length_message = sprintf(_("Passwords must be all numbers and only %s digits"),$SETTINGS_VOICEMAIL_PASSWORD_LENGTH);
+ }
+ else {
+ $voicemail_password_length_message = sprintf(_("Passwords must be all numbers and at least %s digits"),$SETTINGS_VOICEMAIL_PASSWORD_LENGTH);
+ }
+
+ $set_voicemail_password_text = "
+ <tr>
+ <td>" . _("Voicemail Password:") . "</td>
+ <td>
+ <input name='voicemail_password' type='password' size=16 value=" . $_SESSION['ari_user']['voicemail_password'] . ">
+ </td>
+ </tr>
+ <tr>
+ <td>" . _("Enter again to confirm:") . "</td>
+ <td>
+ <input name='voicemail_password_confirm' type='password' size=16 value=" . $_SESSION['ari_user']['voicemail_password'] . ">
+ </td>
+ </tr>
+ <tr>
+ <td class='note' colspan=2><small>" . $voicemail_password_length_message . "</small></td>
+ </tr>";
+ }
+
+ if (isset($_SESSION['ari_user']['voicemail_email'])) {
+
+ if ($_SESSION['ari_user']['voicemail_email_enable']) {
+ $voicemail_email_address = $_SESSION['ari_user']['voicemail_email_address'];
+ $voicemail_pager_address = $_SESSION['ari_user']['voicemail_pager_address'];
+ $voicemail_email_enable = 'checked';
+
+ foreach (array_keys($_SESSION['ari_user']['voicemail_email']) as $key) {
+ $var = "voicemail_email_$key";
+ $var_enable = $var . "enable";
+ if ($_SESSION['ari_user']['voicemail_email'][$key]=='yes') {
+ $$var_enable = 'checked';
+ }
+ }
+ }
+ else {
+
+ $voicemail_email_address = $_COOKIE['ari_voicemail_email_address'];
+ $voicemail_email_text_box_options = "disabled style='background: #DDD;'";
+ $voicemail_pager_address = $_COOKIE['ari_voicemail_pager_address'];
+ $voicemail_pager_text_box_options = "disabled style='background: #DDD;'";
+
+ foreach ($_SESSION['ari_user']['voicemail_email'] as $key => $value) {
+ $var = "voicemail_email_$key";
+ $var_cookie = "ari_" . $var;
+ $var_enable = $var . "enable";
+ $var_text_box_options = $var . "text_box_options";
+
+ $$var_text_box_options = "disabled";
+ if ($_COOKIE[$var_cookie]=='yes') {
+ $$var_enable = 'checked';
+ }
+ }
+ }
+
+ $set_voicemail_email_text = "
+
+ <tr>
+ <td> " . _("Email Notification") . " <input " . $voicemail_email_enable . " type=checkbox name='voicemail_email_enable' value='1' OnClick=\"disable_fields(); return true;\">
+ <small> " ._("Enable") . " </small>
+ </td>
+ </tr><tr>
+ <td><a href='#' class='info'>" . _("Email Voicemail To:") . "<span>" . ("Email a notification, including audio file if indicated below.") . " </span></a></td>
+ <td>
+ <input " . $voicemail_email_text_box_options . " name='voicemail_email_address' type='text' size=48 value='" . $voicemail_email_address . "'>
+ </td>
+ </tr>
+ <tr>
+ <td><a href='#' class='info'>" . _("Pager Email Notification To:") . "<span>" . ("Email a short notification") . " </span></a></td>
+ <td>
+ <input " . $voicemail_pager_text_box_options . " name='voicemail_pager_address' type='text' size=48 value='" . $voicemail_pager_address . "'>
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ </tr>";
+
+ foreach ($_SESSION['ari_user']['voicemail_email'] as $key => $value) {
+
+ $var = "voicemail_email_$key";
+ $var_enable = $var . "enable";
+ $var_text_box_options = $var . "text_box_options";
+ if ($SETTINGS_VOICEMAIL_EMAIL_OPTION_DESCRIPTIONS[$key]) {
+ $var_text = $SETTINGS_VOICEMAIL_EMAIL_OPTION_DESCRIPTIONS[$key];
+ }
+ else {
+ $var_text = $key;
+ }
+
+ if ($value != 'yes' && $value != 'no' && $value !='') {
+
+ $size = strlen($value) - 1;
+ $set_voicemail_email_text .= "
+ <tr>
+ <td></td>
+ <td>
+ <input type=text size='" . $size . "' name='" . $var . "' value='" . $value . "' OnClick=\"disable_fields(); return true;\">
+ <small>" . $var_text . "</small>
+ </td>
+ </tr>";
+ }
+ else {
+
+ $set_voicemail_email_text .= "
+ <tr>
+ <td></td>
+ <td>
+ <input " . $$var_enable . " " . $$var_text_box_options . " type=checkbox name='" . $var . "' value='yes' OnClick=\"disable_fields(); return true;\">
+ <small>" . $var_text . "</small>
+ </td>
+ </tr>";
+ }
+ }
+ }
+
+ $wav_enable = 'selected';
+ if ($_COOKIE['ari_voicemail_audio_format']=='.gsm'||
+ ($_COOKIE['ari_voicemail_audio_format']=='' && $ARI_VOICEMAIL_AUDIO_FORMAT_DEFAULT='.gsm')) {
+ $wav_enable = '';
+ $gsm_enable = 'selected';
+ }
+
+ $set_voicemail_audio_format_text = "
+ <tr>
+ <td>" . _("Audio Format:") . "</td>
+ <td>
+ <select name='voicemail_audio_format'>
+ <option value='.wav' " . $wav_enable . ">" . _("Best Quality") . " (.wav)</option>
+ <option value='.gsm' " . $gsm_enable . ">" . _("Smallest Download") . " (.gsm)</option>
+ </select>
+ </td>
+ </tr>";
+
+ $set_voicemail_text = "
+ <table class='settings'>
+ <tr>
+ <td><h3>" . _("Voicemail Settings") . "</h3></td>
+ </tr>
+ " . $set_voicemail_password_text . "
+ " . $set_voicemail_email_text . "
+ " . $set_voicemail_audio_format_text . "
+ </table>";
+ }
+
+ // call monitor settings
+ if ($this->getFreePBXVersion() &&
+ $SETTINGS_ALLOW_CALL_RECORDING_SET &&
+ in_array('callmonitor',array_keys($loaded_modules))) {
+
+ foreach($data as $key=>$value) {
+ if ($key=='record_in') {
+ if ($value=='Always') {
+ $ri_always = 'checked=checked';
+ }
+ elseif ($value=='Never') {
+ $ri_never = 'checked=checked';
+ }
+ elseif ($value=='Adhoc') {
+ $ri_on_demand = 'checked=checked';
+ }
+ }
+ if ($key=='record_out') {
+ if ($value=='Always') {
+ $ro_always = 'checked=checked';
+ }
+ elseif ($value=='Never') {
+ $ro_never = 'checked=checked';
+ }
+ elseif ($value=='Adhoc') {
+ $ro_on_demand = 'checked=checked';
+ }
+ }
+ }
+
+ $set_callmonitor_text = "
+ <table class='settings'>
+ <tr>
+ <td><h3>" . _("Call Monitor Settings") . "</h3></td>
+ </tr>
+ <tr>
+ <td>" . _("Record INCOMING:") . " </td>
+ <td>
+ <input type='radio' name='record_in' value='Always' " . $ri_always . "/> " . _("Always") . "
+ <input type='radio' name='record_in' value='Never' " . $ri_never . "/> " . _("Never") . "
+ <input type='radio' name='record_in' value='Adhoc' " . $ri_on_demand . "/> " . _("On-Demand") . "
+ </td>
+ </tr>
+ <tr>
+ <td>" . _("Record OUTGOING:") . " </td>
+ <td>
+ <input type='radio' name='record_out' value='Always' " . $ro_always . "/> " . _("Always") . "
+ <input type='radio' name='record_out' value='Never' " . $ro_never . "/> " . _("Never") . "
+ <input type='radio' name='record_out' value='Adhoc' " . $ro_on_demand . "/> " . _("On-Demand") . "
+ </td>
+ </tr>
+ </table>";
+ }
+
+ // javascript enable options
+ if (isset($_SESSION['ari_user']['voicemail_email']) &&
+ in_array('voicemail',array_keys($loaded_modules))) {
+ foreach ($_SESSION['ari_user']['voicemail_email'] as $key => $value) {
+ $var = "voicemail_email_$key";
+ $js_voicemail_email_disable .= "
+ document.ari_settings.$var.disabled = false;";
+ $js_voicemail_email_enable .= "
+ document.ari_settings.$var.disabled = true;";
+ }
+
+ $js_voicemail_script = "
+ if (document.ari_settings.voicemail_email_enable.checked) {
+ document.ari_settings.voicemail_email_address.style.backgroundColor = '#FFF';
+ document.ari_settings.voicemail_email_address.disabled = false;
+ document.ari_settings.voicemail_email_address.value='" . $voicemail_email_address . "';
+ document.ari_settings.voicemail_pager_address.style.backgroundColor = '#FFF';
+ document.ari_settings.voicemail_pager_address.disabled = false;
+ document.ari_settings.voicemail_pager_address.value='" . $voicemail_pager_address . "';
+ " . $js_voicemail_email_disable . "
+ }
+ else {
+ document.ari_settings.voicemail_email_address.style.backgroundColor = '#DDD';
+ document.ari_settings.voicemail_email_address.disabled = true;
+ document.ari_settings.voicemail_pager_address.style.backgroundColor = '#DDD';
+ document.ari_settings.voicemail_pager_address.disabled = true;
+ " . $js_voicemail_email_enable . "
+ }";
+ }
+
+ // build page content
+ $ret .= checkErrorMessage();
+
+ $headerText = sprintf(_("Phone Settings for %s (%s)"),$displayname,$exten);
+
+ $ret .= $display->displayHeaderText($headerText);
+ $ret .= $display->displayLine();
+
+ $ret .= "
+ <SCRIPT LANGUAGE='JavaScript'>
+ <!-- Begin
+ function rowCounter(field, maxlimit) {
+ temp = field.value.split('\u000A',maxlimit+1)
+ field.value = temp.join('\u000A')
+ if (temp.length == maxlimit+1) {
+ field.value = field.value.substring(0, field.value.length-1)
+ }
+ }
+
+ function disable_fields() {";
+ $ret .= $js_voicemail_script . "
+ }
+ // End -->
+ </script>";
+
+ $ret .= "
+ " . $setLangText . "
+ <form class='settings' name='ari_settings' action='' method='GET'>
+ <input type=hidden name=m value=" . $m . ">
+ <input type=hidden name=f value='action'>
+ <input type=hidden name=a value='update'>
+ <br>
+ " . $set_voicemail_text . "
+ <br>
+ " . $set_callmonitor_text . "
+ <br>
+ <input name='submit' type='submit' value='" . _("Update") . "'>
+ </form>";
+
+ return $ret;
+ }
+
+
+
+
+
+
+ /*
+ * Sets Asterisk call recording setting
+ *
+ * @param $exten
+ * Extension to modify
+ * @param $direction
+ * Call direction
+ * @param $state
+ * State to set to
+ */
+ function setRecordSettings($exten,$state_in,$state_out) {
+
+ global $asterisk_manager_interface;
+
+ if (version_compare($this->getFreePBXVersion(), '1.10', '<')) {
+
+ if ($state_in=="Always") {
+ $type_opt = "put";
+ $value_opt = " " . "ENABLED";
+ }
+ elseif ($state_in=="Never") {
+ $type_opt = "put";
+ $value_opt = " " . "DISABLED";
+ }
+ else {
+ $type_opt = "del";
+ $value_opt = "";
+ }
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database $type_opt RECORD-IN $exten $value_opt\r\n\r\n");
+
+ if ($state_out=="Always") {
+ $type_opt = "put";
+ $value_opt = " " . "ENABLED";
+ }
+ elseif ($state_out=="Never") {
+ $type_opt = "put";
+ $value_opt = " " . "DISABLED";
+ }
+ else {
+ $type_opt = "del";
+ $value_opt = "";
+ }
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database $type_opt RECORD-OUT $exten $value_opt\r\n\r\n");
+ }
+ else {
+
+ $value_opt= "out=".$state_out."|in=".$state_in;
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database put AMPUSER $exten/recording $value_opt\r\n\r\n");
+ }
+ }
+
+ /*
+ * Gets record settings for a protocol
+ *
+ * @param $table
+ * Table to pull information from
+ * @param $exten
+ * Extension to get information about
+ * @return $data
+ * call monitor record settings
+ */
+ function getProtocolRecordSettings($table,$exten) {
+
+ global $asterisk_manager_interface;
+
+ $data = array();
+
+ if (version_compare($this->getFreePBXVersion(), '1.10', '<')) {
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database get RECORD-IN $exten\r\n\r\n");
+ if (preg_match("/ENABLED/",$response)) {
+ $data['record_in'] = 'Always';
+ }
+ elseif (preg_match("/DISABLED/",$response)) {
+ $data['record_in'] = 'Never';
+ }
+ else {
+ $data['record_in'] = 'Adhoc';
+ }
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database get RECORD-OUT $exten\r\n\r\n");
+ if (preg_match("/ENABLED/",$response)) {
+ $data['record_out'] = 'Always';
+ }
+ elseif (preg_match("/DISABLED/",$response)) {
+ $data['record_out'] = 'Never';
+ }
+ else {
+ $data['record_out'] = 'Adhoc';
+ }
+ }
+ else {
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: database get AMPUSER $exten/recording\r\n\r\n");
+ if (strstr($response,"in=Always")) {
+ $data['record_in'] = 'Always';
+ }
+ elseif (strstr($response,"in=Never")) {
+ $data['record_in'] = 'Never';
+ }
+ else {
+ $data['record_in'] = 'Adhoc';
+ }
+ if (strstr($response,"out=Always")) {
+ $data['record_out'] = 'Always';
+ }
+ elseif (strstr($response,"out=Never")) {
+ $data['record_out'] = 'Never';
+ }
+ else {
+ $data['record_out'] = 'Adhoc';
+ }
+ }
+
+ return $data;
+ }
+
+ /*
+ * Gets record settings
+ *
+ * @param $exten
+ * Extension to get information about
+ * @param $data
+ * Reference to the variable to store the data in
+ */
+ function getRecordSettings($exten) {
+
+ // check protocol tables first
+ $data = $this->getProtocolRecordSettings($this->protocol_table,$exten);
+
+ return $data;
+ }
+
+ /*
+ * Reloads Asterisk Configuration
+ */
+ function reloadAsteriskVoicemail() {
+
+ global $asterisk_manager_interface;
+
+ $response = $asterisk_manager_interface->Command("Action: Command\r\nCommand: Reload app_voicemail.so\r\n\r\n");
+ }
+
+ /*
+ * Gets FreePBX Version
+ */
+ function getFreePBXVersion() {
+
+ if (isset($_SESSION['dbh_asterisk'])) {
+ $sql = "SELECT * FROM admin WHERE variable = 'version'";
+ $results = $_SESSION['dbh_asterisk']->getAll($sql);
+ if(DB::IsError($results)) {
+ $_SESSION['ari_error'] = $results->getMessage();
+ }
+
+ return $results[0][1];
+ }
+ }
+
+ function lookupSetExtensionFormat($exten) {
+
+ if (trim($exten) == "") return $exten;
+
+ $exten = preg_replace("/[^0-9*]/", "", $exten);
+
+ $sql = "SELECT extension FROM users WHERE extension = '".$exten."'";
+ $asa = $_SESSION['dbh_asterisk']->getrow($sql, DB_FETCHMODE_ASSOC);
+ if (!is_array($asa)) {
+ return $exten.'#';
+ } else {
+ return $exten;
+ }
+ }
+
+
+} // class
+
+?>
diff --git a/fs_selfservice/fri/modules/voicemail.module b/fs_selfservice/fri/modules/voicemail.module
new file mode 100644
index 000000000..aad14564f
--- /dev/null
+++ b/fs_selfservice/fri/modules/voicemail.module
@@ -0,0 +1,805 @@
+<?php
+
+/**
+ * @file
+ * Functions for the interface to the voicemail recordings
+ */
+
+/**
+ * Class for voicemail
+ */
+class Voicemail {
+
+ /*
+ * rank (for prioritizing modules)
+ */
+ function rank() {
+
+ $rank = 1;
+ return $rank;
+ }
+
+ /*
+ * init
+ */
+ function init() {
+ }
+
+ /*
+ * Adds menu item to nav menu
+ *
+ * @param $args
+ * Common arguments
+ */
+ function navMenu($args) {
+
+ global $ARI_NO_LOGIN;
+
+ // check logout
+ if ($_SESSION['ari_user'] && !$ARI_NO_LOGIN) {
+ $logout = 1;
+ }
+
+ if ($logout!='') {
+ $ret .= "<p><small><small><a href='" . $_SESSION['ARI_ROOT'] . "?m=Voicemail&f=display'>" . _("Voicemail") . "</a></small></small></p>";
+ }
+
+ return $ret;
+ }
+
+ /*
+ * Deletes selected voicemails and updates page
+ *
+ * @param $args
+ * Common arguments
+ */
+ function navSubMenu($args) {
+
+ global $ASTERISK_VOICEMAIL_PATH;
+ global $ASTERISK_VOICEMAIL_FOLDERS;
+
+ // args
+ $m = getArgument($args,'m');
+ $q = getArgument($args,'q');
+ $current_folder = getArgument($args,'folder');
+
+ $context = $_SESSION['ari_user']['context'];
+ $extension = $_SESSION['ari_user']['extension'];
+
+ // check for voicemail enabled or admin
+ if ($_SESSION['ari_user']['voicemail_enabled']!=1 ||
+ $extension=='admin') {
+ return;
+ }
+
+ // make folder list
+ $paths = split(';',$ASTERISK_VOICEMAIL_PATH);
+ $i = 0;
+ while ($ASTERISK_VOICEMAIL_FOLDERS[$i]) {
+
+ $f = $ASTERISK_VOICEMAIL_FOLDERS[$i]['folder'];
+ $fn = $ASTERISK_VOICEMAIL_FOLDERS[$i]['name'];
+
+ foreach($paths as $key => $path) {
+
+ $path = appendPath($path,$context);
+ $path = appendPath($path,$extension);
+
+ if (is_dir($path) && is_readable($path)) {
+ $dh = opendir($path);
+ while (false!== ($folder = readdir($dh))) {
+
+ $folder_path = AppendPath($path,$folder);
+
+ if($folder!="." && $folder!=".." &&
+ filetype($folder_path)=='dir') {
+
+ if ($f==$folder) {
+
+ // get message count
+ $indexes = $this->getVoicemailIndex($folder_path,$q,$order,$sort);
+ $record_count = 0;
+ $record_count += $this->getVoicemailCount($indexes);
+
+ // set current folder color
+ $class='';
+ if ($current_folder==$folder ||
+ ($current_folder=='' && $ASTERISK_VOICEMAIL_FOLDERS[0]['folder']==$folder)) {
+ $class = "class='current'";
+ }
+
+ // add folder to list
+ $ret .= "<p><small><small>
+ <a " . $class . " href='" . $_SESSION['ARI_ROOT'] . "?m=Voicemail&q=" . $q . "&folder=" . $f. "'>
+ " . $fn . " (" . $record_count . ")" . "
+ </a>
+ </small></small></p>";
+ }
+ }
+ }
+ }
+ }
+ $i++;
+ }
+
+ return $ret;
+ }
+
+ /*
+ * Acts on the selected voicemails in the method indicated by the action and updates page
+ *
+ * @param $args
+ * Common arguments
+ */
+ function msgAction($args) {
+
+ global $ASTERISK_VOICEMAIL_FOLDERS;
+
+ // args
+ $m = getArgument($args,'m');
+ $a = getArgument($args,'a');
+ $folder = getArgument($args,'folder');
+ $q = getArgument($args,'q');
+ $start = getArgument($args,'start');
+ $span = getArgument($args,'span');
+ $order = getArgument($args,'order');
+ $sort = getArgument($args,'sort');
+
+ // get files
+ $files = array();
+ foreach($_REQUEST as $key => $value) {
+ if (preg_match('/selected/',$key)) {
+ array_push($files, $value);
+ }
+ }
+
+ if ($a=='delete') {
+ $this->deleteVoicemailData($files);
+ }
+ else if ($a=='move_to') {
+ $folder_rx = getArgument($args,'folder_rx');
+ if ($folder_rx=='') {
+ $_SESSION['ari_error']
+ = _("A folder must be selected before the message can be moved.");
+ }
+ else {
+ $context = $_SESSION['ari_user']['context'];
+ $extension = $_SESSION['ari_user']['extension'];
+ $this->moveVoicemailData($files, $context, $extension, $folder_rx);
+ }
+ }
+ else if ($a=='forward_to') {
+
+ $mailbox_rx = getArgument($args,'mailbox_rx');
+ list($context_rx,$extension_rx) = split('/',$mailbox_rx);
+ if ($extension_rx=='') {
+ $_SESSION['ari_error']
+ = _("An extension must be selected before the message can be forwarded.");
+ }
+ else {
+ $folder_rx = $ASTERISK_VOICEMAIL_FOLDERS[0]['folder'];
+ $this->moveVoicemailData($files, $context_rx, $extension_rx, $folder_rx);
+ }
+ }
+
+ // redirect to see updated page
+ $ret .= "
+ <head>
+ <script>
+ <!--
+ window.location = \"" . $_SESSION['ARI_ROOT'] . "?m=" . $m . "&folder=" . $folder . "&q=" . $q . "&start=" . $start . "&span=" . $span . "&order=" . $order . "&sort=" . $sort . "\"
+ // -->
+ </script>
+ </head>";
+
+ return $ret;
+ }
+
+ /*
+ * Displays stats page
+ *
+ * @param $args
+ * Common arguments
+ */
+ function display($args) {
+
+ global $ASTERISK_VOICEMAIL_CONF;
+ global $ASTERISK_VOICEMAIL_PATH;
+ global $ASTERISK_VOICEMAIL_FOLDERS;
+ global $AJAX_PAGE_REFRESH_ENABLE;
+
+ $voicemail_audio_format = $_COOKIE['ari_voicemail_audio_format'];
+
+ $display = new DisplaySearch();
+
+ // args
+ $m = getArgument($args,'m');
+ $f = getArgument($args,'f');
+ $q = getArgument($args,'q');
+ $start = getArgument($args,'start');
+ $span = getArgument($args,'span');
+ $order = getArgument($args,'order');
+ $sort = getArgument($args,'sort');
+
+ $start = $start=='' ? 0 : $start;
+ $span = $span=='' ? 15 : $span;
+ $order = $order=='' ? 'calldate' : $order;
+ $sort = $sort=='' ? 'desc' : $sort;
+
+ $paths = split(';',$ASTERISK_VOICEMAIL_PATH);
+
+ $displayname = $_SESSION['ari_user']['displayname'];
+ $extension = $_SESSION['ari_user']['extension'];
+ $context = $_SESSION['ari_user']['context'];
+ $folder = getArgument($args,'folder');
+ if (!$folder) {
+ $folder = $ASTERISK_VOICEMAIL_FOLDERS[0]['folder'];
+ }
+
+ // get data
+ $data = array();
+ foreach($paths as $key => $path) {
+ $path = fixPathSlash($path);
+ $vm_path = $path . "$context/$extension/$folder";
+ $indexes = $this->getVoicemailIndex($vm_path,$q,$order,$sort);
+ $record_count += $this->getVoicemailCount($indexes);
+ $data = array_merge($data,$this->getVoicemailData($indexes,$start,$span));
+ }
+
+ // build controls
+
+ // get the recordings from the asterisk server
+ $filter = '';
+ $recursiveMax = 1;
+ $recursiveCount = 0;
+ $files = array();
+ foreach($paths as $key => $path) {
+ $path_files = GetFiles($path,$filter,$recursiveMax,$recursiveCount);
+ $files = array_merge($files,$path_files);
+ }
+
+ // move options
+ $i=0;
+ while ($ASTERISK_VOICEMAIL_FOLDERS[$i]) {
+ $cf = $ASTERISK_VOICEMAIL_FOLDERS[$i]['folder'];
+ $fn = $ASTERISK_VOICEMAIL_FOLDERS[$i]['name'];
+ if ($cf!=$folder) {
+ $move_options .= "<option VALUE='" . $cf . "'>&nbsp;&nbsp;&nbsp;&nbsp;" . $fn;
+ }
+ $i++;
+ }
+
+ // forward options
+ if (is_readable($ASTERISK_VOICEMAIL_CONF)) {
+ $lines = file($ASTERISK_VOICEMAIL_CONF);
+ $ext_array = array();
+ foreach ($lines as $key => $line) {
+
+ // get context for forward to mailbox
+ if (preg_match("/\[.*\]/i",$line)) {
+ $forwardContext = trim(preg_replace('/\[|\]/', '', $line));
+ }
+
+ // get username and add to options
+ if (preg_match("/\=\>/i",$line)) {
+ list($username,$value) = split('=>',$line);
+ $username = trim($username);
+ if ($username!=$_SESSION['ari_user']['extension']) {
+ //$ext_array[] = $username . "|" . $forwardContext;
+ list(,$real_name,) = split(",",$value,3);
+ $ext_array[] = $real_name . "|" . $username . "|" . $forwardContext;
+ }
+ }
+ } //foreach
+ //sort the array
+ sort($ext_array);
+
+ //get the size of the array
+ $array_size = count($ext_array) - 1;
+
+ //loop through the array and build the drop down list
+ foreach ($ext_array as $item)
+ {
+ //split the values apart
+ list($real_name,$username,$context) = explode("|",$item);
+
+ //add it to the drop down
+ $forward_options .= "<option VALUE='" . $context . "/" . $username . "'>" . substr($real_name,0,15) . " <" . $username . ">";
+ }
+ }
+ else {
+ $_SESSION['ari_error'] = "File not readable: " . $ASTERISK_VOICEMAIL_CONF;
+ return;
+ }
+
+ // table controls
+ $controls = "
+ <button class='infobar' type='submit' onclick=\"document.voicemail_form.a.value='delete'\">
+ " . _("delete") . "
+ </button>
+ <button class='infobar' type='submit' onclick=\"document.voicemail_form.a.value='move_to'\">
+ " . _("move_to") . "
+ </button>
+ <select name='folder_rx' style='width:124px;'>
+ <option VALUE=''>" . _("Folder") . "
+ " . $move_options . "
+ </select>
+ <button class='infobar' type='submit' onclick=\"document.voicemail_form.a.value='forward_to'\">
+ " . _("forward_to") . "
+ </button>
+ <select name='mailbox_rx'>
+ <option VALUE=''>
+ " . $forward_options . "
+ </select>";
+
+ // table header
+ $recording_delete_header = "<th></th>";
+
+ $fields[0]['field'] = "calldate";
+ $fields[0]['text'] = _("Date");
+ $fields[1]['field'] = "calldate";
+ $fields[1]['text'] = _("Time");
+ $fields[2]['field'] = "clid";
+ $fields[2]['text'] = _("Caller ID");
+ $fields[3]['field'] = "priority";
+ $fields[3]['text'] = _("Priority");
+ $fields[4]['field'] = "origmailbox";
+ $fields[4]['text'] = _("Orig Mailbox");
+ $fields[5]['field'] = "duration";
+ $fields[5]['text'] = _("Duration");
+ $i = 0;
+ while ($fields[$i]) {
+
+ $field = $fields[$i]['field'];
+ $text = $fields[$i]['text'];
+ if ($order==$field) {
+ if ($sort=='asc') {
+ $currentSort = 'desc';
+ $arrowImg = "<img src='theme/images/arrow-asc.gif' alt='sort'>";
+ }
+ else {
+ $currentSort = 'asc';
+ $arrowImg = "<img src='theme/images/arrow-desc.gif' alt='sort'>";
+ }
+
+ if ($i==1) {
+ $arrowImg = '';
+ }
+ }
+ else {
+ $arrowImg = '';
+ $currentSort = 'desc';
+ }
+
+ $unicode_q = urlencode($q);
+ $recording_header .= "<th><a href=" . $_SESSION['ARI_ROOT'] . "?m=" . $m . "&f=" . $f . "&q=" . $unicode_q . "&order=" . $field . "&sort=" . $currentSort . ">" . $text . $arrowImg . "</a></th>";
+
+ $i++;
+ }
+ $recording_header .= "<th>" . _("Message") . "</th>";
+
+ // table body
+ if (isset($data)) {
+ foreach($data as $file=>$value) {
+
+ // recording popup link
+ $voicemail_audio_format = $voicemail_audio_format=='' ? '.wav' : $voicemail_audio_format;
+ $recording = preg_replace('/.txt/', $voicemail_audio_format, $file);
+ if (is_file($recording)) {
+ $recordingLink = "<a href='#' onClick=\"javascript:popUp('misc/recording_popup.php?recording=" . $recording . "&date=" . $date . "&time=" . $time . "'); return false;\">
+ " . _("play") . "
+ </a>";
+ }
+ else {
+ $_SESSION['ari_error'] = _("Voicemail recording(s) was not found.") . "<br>" .
+ sprintf(_("On settings page, change voicemail audio format. It is currently set to %s"),$voicemail_audio_format);
+ }
+
+ $tableText .= "
+ <tr>
+ <td class='checkbox'><input type=checkbox name='selected" . ++$i . "' value=" . $file . "></td>
+ <td width=68>" . GetDateFormat($value['origtime']) . "</td>
+ <td>" . GetTimeFormat($value['origtime']) . "</td>
+ <td width=100>" . $value[callerid] . "</td>
+ <td>" . $value[priority] . "</td>
+ <td width=90>" . $value[origmailbox] . "</td>
+ <td>" . $value[duration] . " sec</td>
+ <td>" . $recordingLink . "</td>
+ </tr>";
+ }
+ }
+
+ // options
+ $url_opts = array();
+ $url_opts['folder'] = $folder;
+ $url_opts['sort'] = $sort;
+ $url_opts['order'] = $order;
+
+ $error = 0;
+
+ // check for voicemail enabled
+ if ($_SESSION['ari_user']['voicemail_enabled']!=1) {
+ $_SESSION['ari_error'] = _("Voicemail Login not found.") . "<br>" .
+ _("No access to voicemail");
+ $error = 1;
+ }
+
+ // check admin
+ if ($extension=='admin') {
+ $_SESSION['ari_error'] = _("No Voicemail Recordings for Admin");
+ $error = 1;
+ }
+
+ // build page content
+ $ret .= checkErrorMessage();
+ if ($error) {
+ return $ret;
+ }
+
+ // ajax page refresh script
+ if ($AJAX_PAGE_REFRESH_ENABLE) {
+// $ret .= ajaxRefreshScript($args);
+ }
+
+ // header
+ $ret .= $display->displayHeaderText(sprintf(_("Voicemail for %s (%s)"),$displayname,$extension));
+ $ret .= $display->displaySearchBlock('left',$m,$q,$url_opts,true);
+
+ // start form
+ $ret .= "
+ <form name='voicemail_form' action='" . $_SESSION['ARI_ROOT'] . "' method='GET'>
+ <input type=hidden name=m value=" . $m . ">
+ <input type=hidden name=f value=msgAction>
+ <input type=hidden name=a value=''>
+ <input type=hidden name=q value=" . $q . ">
+ <input type=hidden name=folder value=" . $folder . ">
+ <input type=hidden name=start value=" . $start . ">
+ <input type=hidden name=span value=" . $span . ">
+ <input type=hidden name=order value=" . $order . ">
+ <input type=hidden name=sort value=" . $sort . ">";
+
+ $ret .= $display->displayInfoBarBlock($controls,$q,$start,$span,$record_count);
+
+ // add javascript for popup and message actions
+ $ret .= "
+ <SCRIPT LANGUAGE='JavaScript'>
+ <!-- Begin
+ function popUp(URL) {
+ popup = window.open(URL, 'play', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=1,width=324,height=110');
+ }
+
+ function checkAll(form,set) {
+ var elem = 0;
+ var i = 0;
+ while (elem = form.elements[i]) {
+ if (set) {
+ elem.checked = true;
+ } else {
+ elem.checked = false;
+ }
+ i++;
+ }
+ return true;
+ }
+ // End -->
+ </script>";
+
+ // voicemail delete recording controls
+ $ret .= "
+ <table>
+ <tr>
+ <td>
+ <small>" . _("select") . ": </small>
+ <small><a href='' OnClick=\"checkAll(document.voicemail_form,true); return false;\">" . _("all") . "</a></small>
+ <small><a href='' OnClick=\"checkAll(document.voicemail_form,false); return false;\">" . _("none") . "</a></small>
+ </td>
+ </tr>
+ </table>";
+
+ // table
+ $ret .= "
+ <table class='voicemail'>
+ <tr>
+ " . $recording_delete_header . "
+ " . $recording_header . "
+ </tr>
+ " . $tableText . "
+ </table>";
+
+ // end form
+ $ret .= "</form>";
+
+ $ret .= $display->displaySearchBlock('center',$m,$q,$url_opts,false);
+ $ret .= $display->displayNavigationBlock($m,$q,$url_opts,$start,$span,$record_count);
+
+ return $ret;
+ }
+
+ /*
+ * Gets voicemail data
+ *
+ * @param $data
+ * Reference to the variable to store the data in
+ * @param $q
+ * search string
+ */
+ function getVoicemailIndex($path,$q,$order,$sort) {
+
+ $indexes = array();
+
+ $filter = '.txt';
+ $recursiveMax = 0;
+ $recursiveCount = 0;
+ $files = getFiles($path,$filter,$recursiveMax,$recursiveCount);
+
+ if (isset($files)) {
+
+ // ugly, but sorts array by time stamp
+ foreach ($files as $file) {
+
+ if (is_file($file)) {
+
+ $lines = file($file);
+ foreach ($lines as $key => $line) {
+ unset($value);
+ list($key,$value) = split('=',$line);
+ if ($value) {
+
+ if ($key=="origtime") {
+ $calldate = $value;
+ $date = GetDateFormat($value);
+ $time = GetTimeFormat($value);
+ }
+ if ($key=="callerid") {
+ $callerid = $value;
+ }
+ if ($key=="priority") {
+ $priority = $value;
+ }
+ if ($key=="origmailbox") {
+ $origmailbox = $value;
+ }
+ if ($key=="duration") {
+ $duration = (int)$value;
+ }
+ }
+ }
+
+ // search filter
+ $found = 1;
+ if ($q) {
+
+ $found = 0;
+
+ if (preg_match("/" . $q . "/", $origmailbox) ||
+ preg_match("/" . $q . "/", $callerid) ||
+ preg_match("/" . $q . "/", $date) ||
+ preg_match("/" . $q . "/", $time)) {
+ $found = 1;
+ }
+ }
+ }
+
+ // add to index
+ if ($found) {
+ $indexes[$file] = $$order;
+ }
+ }
+
+ if (count($indexes)) {
+ if ($sort=='desc') {
+ arsort($indexes);
+ }
+ else {
+ asort($indexes);
+ }
+ }
+ }
+
+ return $indexes;
+ }
+
+ /*
+ * Deletes selected voicemails
+ *
+ * @param $files
+ * Array of files to delete
+ */
+ function deleteVoicemailData($files) {
+
+ foreach($files as $key => $path) {
+
+ // get file parts for search
+ $path_parts = pathinfo($path);
+ $path = fixPathSlash($path_parts['dirname']);
+
+ list($name,$ext) = split("\.",$path_parts['basename']);
+
+ // delete all related files using a wildcard
+ if (is_dir($path)) {
+ $hdl = opendir($path);
+ while ($fn = readdir($hdl)) {
+ if (preg_match("/" . $name ."/",$fn)) {
+ $file = $path . $fn;
+ unlink($file);
+ }
+ }
+ closedir($hdl);
+ }
+ }
+ }
+
+ /*
+ * Moves selected voicemails to a specified folder
+ *
+ * @param $files
+ * Array of files to delete
+ * @param $extension_rx
+ * Mailbox to move message to
+ * @param $folder_rx
+ * Folder to move the messages to
+ */
+ function moveVoicemailData($files,$context_rx,$extension_rx,$folder_rx) {
+
+ global $ASTERISK_VOICEMAIL_PATH;
+
+ $perm = fileperms($ASTERISK_VOICEMAIL_PATH);
+ $uid = fileowner($ASTERISK_VOICEMAIL_PATH);
+ $gid = filegroup($ASTERISK_VOICEMAIL_PATH);
+
+ // recieving path
+ $paths = split(';',$ASTERISK_VOICEMAIL_PATH);
+ $path_rx = appendPath($paths[0],$context_rx);
+ if (!is_dir($path_rx)) {
+ mkdir($path_rx, $perm);
+ chown($path_rx,intval($uid));
+ chgrp($path_rx,intval($gid));
+ }
+ $path_rx = appendPath($path_rx,$extension_rx);
+ if (!is_dir($path_rx)) {
+ mkdir($path_rx, $perm);
+ chown($path_rx,intval($uid));
+ chgrp($path_rx,intval($gid));
+ }
+ $path_rx = appendPath($path_rx,$folder_rx);
+ if (!is_dir($path_rx)) {
+ mkdir($path_rx, $perm);
+ chown($path_rx,intval($uid));
+ chgrp($path_rx,intval($gid));
+ }
+
+ // get recieving folder last message number
+ if (is_dir($path_rx)) {
+
+ $lastNum = -1;
+ $lastNumLen = 4;
+
+ $dh = opendir($path_rx);
+ while (false != ($filename = readdir($dh))) {
+ if($filename!="." && $filename!="..") {
+
+ $msg_path = $path_rx;
+ $msg_path = appendPath($msg_path,$filename);
+ if (is_file($msg_path)) {
+ $path_parts = pathinfo($msg_path);
+ $num = preg_replace("/[a-zA-Z]|\./",'', $path_parts['basename']);
+ if ($num > $lastNum) {
+ $lastNum = $num;
+ $lastNumLen = strlen($lastNum);
+ }
+ }
+ }
+ }
+ }
+ else {
+ $_SESSION['ari_error'] = sprintf(_("Could not create mailbox folder %s on the server"),$folder_rx);
+ return;
+ }
+
+ // copy files to new location, incrementing each message number
+ asort($files);
+ foreach($files as $key => $path) {
+
+ // get file parts for search
+ $path_parts = pathinfo($path);
+ $path = $path_parts['dirname'];
+ $path = fixPathSlash($path);
+ list($name,$ext) = split("\.",$path_parts['basename']);
+ if (is_dir($path)) {
+
+ $lastNum++;
+ $hdl = opendir($path);
+ while ($fn = readdir($hdl)) {
+ if (preg_match("/" . $name . "/",$fn)) {
+ $src = $path . $fn;
+ $path_parts = pathinfo($src);
+ $folder_rx = preg_replace("/\d+/",sprintf("%0" . $lastNumLen . "d",$lastNum),$path_parts['basename']);
+ $dst = appendPath($path_rx,$folder_rx);
+ if (is_writable($src) && is_writable($path_rx)) {
+
+ $perm = fileperms($src);
+ $uid = fileowner($src);
+ $gid = filegroup($src);
+
+ copy($src,$dst);
+
+ if (is_writable($dst)) {
+ chmod($dst, $perm);
+ chown($dst,intval($uid));
+ chgrp($dst,intval($gid));
+ }
+
+ unlink($src);
+ }
+ else {
+ $_SESSION['ari_error'] = sprintf(_("Permission denied on folder %s or %s"),$src,$path_rx);
+ return;
+ }
+ }
+ }
+ closedir($hdl);
+ }
+ }
+ }
+
+ /*
+ * Gets voicemail record count
+ *
+ * @param $indexes
+ * array of files to be counted
+ * @return $count
+ * number of cdr records counted
+ */
+ function getVoicemailCount($indexes) {
+
+ $count = count($indexes);
+
+ return $count;
+ }
+
+ /*
+ * Gets voicemail data
+ *
+ * @param $indexes
+ * array of voicemail files
+ * @param $start
+ * message number to start page with
+ * @param $span
+ * number of messages to display on page
+ * @param $data
+ * Reference to the variable to store the data in
+ */
+ function getVoicemailData($indexes,$start,$span) {
+
+ $data = array();
+
+ if (!isset($indexes)) {
+ return;
+ }
+
+ // populate array
+ $i = 0;
+ foreach ($indexes as $file => $index) {
+ if ($i>$start-1+$span) {
+ return $data;
+ }
+ elseif ($i>$start-1 && $i<$start+$span) {
+ $lines = file($file);
+ foreach ($lines as $key => $line) {
+ unset($value);
+ list($key,$value) = split('=',$line);
+ if ($value) {
+ $data[$file][$key] = $value;
+ }
+ }
+ }
+ $i++;
+ }
+
+ return $data;
+ }
+
+}
+
+
+?> \ No newline at end of file
diff --git a/fs_selfservice/fri/theme/global.css b/fs_selfservice/fri/theme/global.css
new file mode 100644
index 000000000..cd97aa285
--- /dev/null
+++ b/fs_selfservice/fri/theme/global.css
@@ -0,0 +1,87 @@
+/*
+ * Global Styles
+ */
+
+body {
+ color: #333;
+ background-color: white;
+ font-family: Verdana, Helvetica, Arial, sans-serif;
+}
+
+div {
+ font-family: Verdana, Helvetica, Arial, sans-serif;
+}
+
+h2 {
+ font-size: 1.2em;
+ font-family: "Trebuchet MS", Arial, Helvetica, Tahoma, Verdana, sans-serif;
+ margin-top: 0;
+ margin-bottom: 0;
+ color: #555;
+}
+
+h3 {
+ font-size: 1em;
+ margin-top: 1.5em;
+ font-family: "Trebuchet MS", Arial, Helvetica, Tahoma, Verdana, sans-serif;
+ margin-top: 0;
+ margin-bottom: 0;
+ color: #555;
+}
+
+
+h4 {
+ font-family: "Trebuchet MS", Arial, Helvetica, Tahoma, Verdana, sans-serif;
+ margin-top: 0;
+ margin-bottom: 0;
+ color: #555;
+ margin-top: 1.5em
+}
+
+
+
+sup {
+ font-size: 9px
+}
+
+small small {
+ font-family: Verdana, Helvetica, Arial, sans-serif;
+ font-weight: bold;
+}
+
+
+
+/***** info popups *****/
+a.info {
+ position:relative;
+ color:black;
+ border-bottom:1px dashed #ccc;
+}
+/* Added to solve the z-order problem of IE
+*/
+a.info:hover {
+ background-color: #FFA178;
+ z-index:2;
+}
+/* End */
+a.info span{
+ display: none;
+ background-color: #FFA178;
+}
+a.info:hover span{
+ display:block;
+ position:absolute;
+ z-index:1;
+ top:2em;
+ left:-10em;
+ width:25em;
+ border:1px solid #F2AF1D;
+ background-color:#FDF1D5;
+ color:#000;
+ text-align:justify;
+ font-size:10px;
+ font-weight:normal;
+ padding:3px;
+ line-height:15px;
+}
+
diff --git a/fs_selfservice/fri/theme/header.css b/fs_selfservice/fri/theme/header.css
new file mode 100644
index 000000000..1c28e7a5a
--- /dev/null
+++ b/fs_selfservice/fri/theme/header.css
@@ -0,0 +1,83 @@
+/*
+ * Header
+ */
+
+/* Header */
+
+#ariHeader {
+ position: relative;
+ background: #105D90;
+ height: 72px;
+ margin: 0;
+ padding: 0;
+ clear: both;
+}
+
+#ariHeader span.left {
+ position: relative;
+ height: 72px;
+ border: 0px;
+ padding: 0px;
+ margin: 0px;
+ float: left;
+}
+
+#ariHeader img {
+ border: 0px;
+}
+
+#ariHeader span.right {
+ height: 72px;
+ border: 0px;
+ padding: 0px;
+ margin: 0px;
+ float: right;
+}
+
+#ariHeader img {
+ border: 0px;
+}
+
+/* Topnav */
+
+#topnav {
+ width: 100%;
+ height: 36px;
+ border: 0;
+ padding: 0;
+ margin-top: -1px; /* stupid browser hack */
+ color: #999;
+ background-color: #333;
+}
+
+#topnav span.left {
+ float: left;
+ text-align: left;
+ font-weight: bold;
+ color: #fff;
+ width: 49%;
+}
+
+#topnav span.right {
+ float: right;
+ text-align: right;
+ font-weight: bold;
+ color: #fff;
+ width: 49%;
+}
+
+.topnav small b {
+ font-family: Verdana, Helvetica, Arial, sans-serif;
+ font-weight: bold;
+ background-color: #105D90;
+}
+
+/* Headerspacer */
+
+#headerspacer {
+ border: 0;
+ padding: 0;
+ margin-top: -16px; /* stupid browser hack */
+ background-color: #fff;
+ height: 16px
+} \ No newline at end of file
diff --git a/fs_selfservice/fri/theme/iefixes.css b/fs_selfservice/fri/theme/iefixes.css
new file mode 100644
index 000000000..a7939a454
--- /dev/null
+++ b/fs_selfservice/fri/theme/iefixes.css
@@ -0,0 +1,16 @@
+/*
+ * IE Fixes
+ */
+
+/*Win IE fix \*/
+* html .minwidth { border-left: 760px solid #fff; position: relative; float: left; z-index: 1; }
+
+/*End Win IE fix*/
+
+/*Win IE fix \*/
+* html .container { margin-left: -760px; position: relative; float: left; z-index :2; }
+/*End Win IE fix*/
+
+
+
+
diff --git a/fs_selfservice/fri/theme/images/arrow-asc.gif b/fs_selfservice/fri/theme/images/arrow-asc.gif
new file mode 100644
index 000000000..46a5848be
--- /dev/null
+++ b/fs_selfservice/fri/theme/images/arrow-asc.gif
Binary files differ
diff --git a/fs_selfservice/fri/theme/images/arrow-desc.gif b/fs_selfservice/fri/theme/images/arrow-desc.gif
new file mode 100644
index 000000000..6f4e5e6e7
--- /dev/null
+++ b/fs_selfservice/fri/theme/images/arrow-desc.gif
Binary files differ
diff --git a/fs_selfservice/fri/theme/layout.css b/fs_selfservice/fri/theme/layout.css
new file mode 100644
index 000000000..a398714ee
--- /dev/null
+++ b/fs_selfservice/fri/theme/layout.css
@@ -0,0 +1,420 @@
+/*
+ * Layout
+ */
+
+/* Page */
+
+#page {
+ background-color: white;
+ text-align: left;
+ min-width: 760px;
+}
+
+/* main */
+
+#main {
+ min-width: 760px;
+ float: left;
+}
+
+#main span.left {
+ float: left;
+}
+
+#main span.right {
+ float: left;
+}
+
+/* Center */
+
+#center {
+ float: left;
+ margin-bottom: 20px;
+}
+
+/* Login */
+
+#login {
+ margin: 0;
+ padding: 0;
+}
+#login p {
+ font-size: 0.7em;
+}
+table#login {
+ width: 600px;
+ border: 0px;
+}
+table#login td.right {
+ text-align: right;
+ width: 20%;
+}
+table#login td.left {
+ text-align: left;
+}
+table#login td.small {
+ font-size: 0.7em;
+}
+table#login_text {
+ margin-left: 60px;
+ font-size: 0.8em;
+ text-align: left;
+}
+
+/* i18n lang */
+
+.lang {
+ display: inline;
+ font-size: 0.8em;
+ margin: 0;
+ padding: 0;
+}
+.lang_code {
+ margin: 0;
+ padding: 0;
+ width: 10em;
+}
+
+/* Line */
+
+#line {
+ min-width: 604px;
+ border: 1px solid #333;
+ padding: 0;
+ margin: 0;
+ color: #999;
+ background-color: #333;
+ height: 1px;
+}
+#line span.left {
+ float: left;
+ text-align: left;
+ font-weight: bold;
+ color: #fff;
+ width: 49%;
+}
+#line span.right {
+ float: right;
+ text-align: right;
+ font-weight: bold;
+ color: #fff;
+ width: 49%;
+}
+
+/* Navbar */
+
+#navbar {
+ width: 604px;
+ height: 24px;
+ border: 1px;
+ padding: 0;
+ margin-bottom: 0;
+ color: #fff;
+ background-color: #333;
+}
+#navbar span.left {
+ margin: 2px;
+ float: left;
+ text-align: left;
+ font-weight: bold;
+ vertical-align: middle;
+ width: 49%;
+}
+#navbar span.right {
+ margin: 2px;
+ float: right;
+ text-align: right;
+ font-weight: bold;
+ vertical-align: middle;
+ width: 49%;
+}
+
+/* Info Bar */
+
+#info_bar {
+ min-width: 604px;
+ border: 1px solid #333;
+ padding: 3px;
+ margin-top: -1px; /* stupid browser hack */
+ color: #999;
+ background-color: #333;
+ height: 20px;
+}
+#info_bar span.left {
+ float: left;
+ text-align: left;
+ font-weight: bold;
+ color: #fff;
+ width: 49%;
+}
+#info_bar span.right {
+ float: right;
+ text-align: right;
+ font-weight: bold;
+ color: #fff;
+ width: 49%;
+}
+.info_bar a:link {
+ color: white;
+ text-decoration: none;
+}
+.info_bar a:active, a:link {
+ color: #105D90;
+}
+.info_bar a:hover {
+ color: #fc0;
+}
+.info_bar small b {
+ font-family: Verdana, Helvetica, Arial, sans-serif;
+ font-weight: bold;
+}
+input.infoBar {
+ font-size: 11px;
+ padding: 0px;
+ height: 22px;
+}
+
+/* bars */
+
+.bar {
+ margin: 0;
+}
+
+.bar_left {
+ width: 604px;
+ margin: 0 0 16px 0;
+ padding: 0;
+}
+
+.bar_center {
+ width: 604px;
+ text-align: center;
+ margin: 0 0 16px 0;
+ padding: 0;
+}
+.bar_center a:active, .bar_center a:hover {
+ color: red;
+}
+
+/* Subheader */
+
+#subheader {
+ padding: 0px;
+ margin: 0px;
+ margin-bottom: 16px;
+}
+
+/* servBodL */
+
+.servBodL {
+ border-left: 1px dotted #CEDCEA;
+}
+
+/* Callmonitor */
+
+table.callmonitor {
+ border: 1px #6699CC solid;
+ border-collapse: collapse;
+ border-spacing: 0px;
+ margin: 0 0 16px 0;
+ width: 604px;
+}
+table.callmonitor th {
+ background-color: #BEC8D1;
+ border: 1px solid #6699CC;
+ border-bottom: 2px solid #6699CC;
+ text-align: center;
+ font-family: Verdana;
+ font-weight: bold;
+ font-size: 0.7em;
+ color: #404040;
+}
+table.callmonitor th a {
+ color: #404040;
+}
+table.callmonitor img {
+ border: 0;
+}
+table.callmonitor td {
+ background-color: white;
+ border: 1px solid #6699CC;
+ color: #404040;
+ font-family: Verdana, sans-serif, Arial;
+ font-weight: normal;
+ font-size: 0.7em;
+ padding: 3px;
+ text-align: center;
+}
+table.callmonitor td.checkbox {
+ padding: 1px;
+}
+
+/* Voicemail */
+
+.voicemail {
+ margin: 0px;
+}
+table.voicemail {
+ border: 1px #6699CC solid;
+ border-collapse: collapse;
+ border-spacing: 0px;
+ margin: 0 0 16px 0;
+ width: 604px;
+}
+table.voicemail th {
+ background-color: #BEC8D1;
+ border: 1px solid #6699CC;
+ border-bottom: 2px solid #6699CC;
+ text-align: center;
+ font-family: Verdana;
+ font-weight: bold;
+ font-size: 0.7em;
+ color: #404040;
+}
+table.voicemail th a {
+ color: #404040;
+}
+table.voicemail img {
+ border: 0;
+}
+table.voicemail td {
+ background-color: white;
+ border: 1px solid #6699CC;
+ color: #404040;
+ font-family: Verdana, sans-serif, Arial;
+ font-weight: normal;
+ font-size: 0.7em;
+ padding: 3px;
+ text-align: center;
+}
+table.voicemail td.checkbox {
+ padding: 1px;
+}
+
+/* Help */
+
+.help {
+ margin: 0px;
+}
+table.help {
+ border: 1px #6699CC solid;
+ border-collapse: collapse;
+ border-spacing: 0px;
+ margin: 0 0 16px 0;
+}
+table.help th {
+ background-color: #BEC8D1;
+ border: 1px solid #6699CC;
+ border-bottom: 2px solid #6699CC;
+ font-family: Verdana;
+ font-weight: bold;
+ font-size: 0.7em;
+ color: #404040;
+}
+table.help th.feature_codes {
+ text-align: center;
+ width: 9em;
+}
+table.help th a {
+ color: #404040;
+}
+table.help img {
+ border: 0;
+}
+table.help td {
+ background-color: white;
+ border: 1px solid #6699CC;
+ color: #404040;
+ font-family: Verdana, sans-serif, Arial;
+ font-weight: normal;
+ font-size: 0.7em;
+ padding: 3px;
+}
+table.help td.feature_codes {
+ text-align: center;
+}
+table.help td.checkbox {
+ padding: 1px;
+}
+
+/* Settings */
+
+.settings {
+ font-family: Verdana, sans-serif, Arial;
+ font-weight: normal;
+ font-size: 0.9em;
+ padding: 0;
+ margin: 0;
+}
+table.settings {
+ font-family: Verdana;
+ color: #404040;
+ border-collapse: collapse;
+ border-spacing: 0px;
+ padding-bottom: 3px;
+}
+table.settings td {
+ color: #404040;
+ background-color: white;
+ padding: 3px;
+}
+table.settings td.note {
+ color: #105D90;
+}
+
+/* Footer */
+
+#ariFooter {
+ color: #999;
+ margin-left: 148px;
+ font-size: 10px;
+ overflow: auto;
+/* width: 100%; */
+ clear: both;
+}
+
+#ariFooter a {
+ text-decoration: none;
+ color: #999;
+}
+
+#ariFooter a:hover {
+ text-decoration: underline;
+ color: #105D90;
+}
+
+#ariFooter a:link {
+ text-decoration: none;
+ color: #999;
+}
+
+/* Misc */
+
+.ariClearBoth {
+ clear: both;
+ margin: 0;
+ padding: 0;
+}
+
+.ariBlockHide {
+ display: none;
+ height: 0;
+ width: 0;
+ overflow: hidden;
+ position: absolute; /* IE5 Mac */
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fs_selfservice/fri/theme/logo.gif b/fs_selfservice/fri/theme/logo.gif
new file mode 100644
index 000000000..b2d23d7a6
--- /dev/null
+++ b/fs_selfservice/fri/theme/logo.gif
Binary files differ
diff --git a/fs_selfservice/fri/theme/main.css b/fs_selfservice/fri/theme/main.css
new file mode 100644
index 000000000..6b9ba9405
--- /dev/null
+++ b/fs_selfservice/fri/theme/main.css
@@ -0,0 +1,13 @@
+/*
+ * Main
+ */
+
+@import url("global.css");
+@import url("text.css");
+@import url("layout.css");
+@import url("header.css");
+@import url("navigation.css");
+
+@import url("iefixes.css");
+
+
diff --git a/fs_selfservice/fri/theme/navigation.css b/fs_selfservice/fri/theme/navigation.css
new file mode 100644
index 000000000..907851b21
--- /dev/null
+++ b/fs_selfservice/fri/theme/navigation.css
@@ -0,0 +1,166 @@
+/*
+ * Navigation
+ */
+
+/* Menu */
+
+#menu {
+ width: 148px;
+ float: left;
+}
+
+/* Nav */
+
+.nav {
+ font-weight: bold;
+ color: #105D90;
+ margin-right: 20px;
+}
+
+.nav p {
+ margin: 0px;
+ padding-top: 2px;
+ padding-bottom: 3px;
+ background: #FFF;
+}
+
+.nav a:visited {
+ color: #105D90;
+}
+
+.sub {
+ margin-left: 1em;
+}
+
+.navtext {
+ margin-left: 20px;
+}
+
+.nav_b1 {
+ height: 1px;
+ font-size: 1px;
+ overflow: hidden;
+ display: block;
+ background: #EEE;
+ margin:0 5px;
+}
+
+.nav_b2 {
+ height: 1px;
+ font-size: 1px;
+ overflow: hidden;
+ display: block;
+ background: #FFF;
+ border-right: 2px solid #EEE;
+ border-left: 2px solid #EEE;
+ margin:0 3px;
+}
+
+.nav_b3 {
+ height: 1px;
+ font-size: 1px;
+ overflow: hidden;
+ display:block;
+ background: #FFF;
+ border-right: 1px solid #EEE;
+ border-left: 1px solid #EEE;
+ margin: 0 2px;
+}
+
+.nav_b4 {
+ height: 2px;
+ font-size: 1px;
+ overflow: hidden;
+ display:block;
+ background: #FFF;
+ border-right: 1px solid #EEE;
+ border-left:1px solid #EEE;
+ margin:0 1px;
+}
+
+#nav_menu {
+ background: #FFF;
+ border-right: 1px solid #EEE;
+ border-left: 1px solid #EEE;
+ padding-left: 0.75em;
+}
+
+/* Subnav */
+
+.subnav {
+ font-weight: bold;
+ color: #105D90;
+ margin-right: 20px;
+}
+
+.subnav p {
+ margin: 0px;
+ padding-top: 2px;
+ padding-bottom: 3px;
+ background: #BEC8D1;
+}
+
+.subnav a:visited {
+ color: #105D90;
+}
+
+.subnav a.current, a:visited.current {
+ color: #404040;
+}
+
+.subnav_b1 {
+ height: 1px;
+ font-size: 1px;
+ overflow: hidden;
+ display: block;
+ background: #aaa;
+ margin:0 5px;
+}
+
+.subnav_b2 {
+ height: 1px;
+ font-size: 1px;
+ overflow: hidden;
+ display: block;
+ background: #BEC8D1;
+ border-right: 2px solid #aaa;
+ border-left: 2px solid #aaa;
+ margin:0 3px;
+}
+
+.subnav_b3 {
+ height: 1px;
+ font-size: 1px;
+ overflow: hidden;
+ display:block;
+ background: #BEC8D1;
+ border-right: 1px solid #aaa;
+ border-left: 1px solid #aaa;
+ margin: 0 2px;
+}
+
+.subnav_b4 {
+ height: 2px;
+ font-size: 1px;
+ overflow: hidden;
+ display:block;
+ background: #BEC8D1;
+ border-right: 1px solid #aaa;
+ border-left:1px solid #aaa;
+ margin:0 1px;
+}
+
+.subnav_title {
+ font-weight: normal;
+ color: #105D90;
+ font-size: 12px;
+ padding-left: 1em;
+}
+
+#subnav_menu {
+ background: #BEC8D1;
+ border-right: 1px solid #aaa;
+ border-left: 1px solid #aaa;
+ padding-left: 1.25em;
+}
+
diff --git a/fs_selfservice/fri/theme/page.tpl.php b/fs_selfservice/fri/theme/page.tpl.php
new file mode 100644
index 000000000..9d54659c3
--- /dev/null
+++ b/fs_selfservice/fri/theme/page.tpl.php
@@ -0,0 +1,78 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <TITLE>User Portal</TITLE>
+ <link rel="stylesheet" href="theme/main.css" type="text/css">
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8">
+ </head>
+ <body>
+ <div id="page">
+ <div class="minwidth">
+ <div class="container">
+ <div id="topnav">
+ <div class="spacer"></div>
+ <span class="left">
+ </span>
+ <div class="spacer"></div>
+ </div>
+ <div id="headerspacer"><img src="theme/spacer.gif" alt=""></div>
+ <div id="main">
+ <div class="minwidth">
+ <div class="container">
+ <div class="spacer"></div>
+ <span class="left">
+ <div id="menu">
+ <div><img height=4 src="theme/spacer.gif" alt=""></div>
+ <div class="nav">
+ <?php if ($nav_menu != '') { ?>
+ <b class='nav_b1'></b><b class='nav_b2'></b><b class='nav_b3'></b><b class='nav_b4'></b>
+ <div id='nav_menu'>
+ <?php print($nav_menu) ?>
+ </div>
+ <b class='nav_b4'></b><b class='nav_b3'></b><b class='nav_b2'></b><b class='nav_b1'></b>
+ <?php } ?>
+ </div>
+ <div><img height=14 src="theme/spacer.gif" alt=""></div>
+ <?php if ($subnav_menu != '') { ?>
+ <div class="subnav">
+ <div class="subnav_title"><?php echo _("Folders")?>:</div>
+ <b class='subnav_b1'></b><b class='subnav_b2'></b><b class='subnav_b3'></b><b class='subnav_b4'></b>
+ <div id='subnav_menu'>
+ <?php print($subnav_menu) ?>
+ </div>
+ <b class='subnav_b4'></b><b class='subnav_b3'></b><b class='subnav_b2'></b><b class='subnav_b1'></b>
+ </div>
+ <?php } ?>
+ </div>
+ </span>
+ <span class="right">
+ <div id="center">
+ <?php if ($login != "") { ?>
+ <?php print($login) ?>
+ <?php } ?>
+ <div id="content">
+ <!-- begin main content -->
+ <?php print($content) ?>
+ <!-- end main content -->
+ </div>
+ </div>
+ </span>
+ <div class="spacer"></div>
+ </div>
+ </div>
+ </div>
+ <!--begin footer-->
+ <div id="ariFooter">
+ <small>
+ <!--&nbsp;&nbsp;<?php print($ari_version) ?> <?php echo _("Version")?><br> -->
+ Freeside Recording Interface (c) 2008 Freeside Internet Services, Inc.<br>
+ <a href="http<?php print(isset($_SERVER['HTTPS'])&&$_SERVER['HTTPS']!=''?'s':''); ?>://www.littlejohnconsulting.com">Based on ARI from Littlejohn Consulting</a>
+ </small>
+ </div>
+ <!-- end footer -->
+ </div>
+ </div>
+ </div>
+ </body>
+</html>
+
diff --git a/fs_selfservice/fri/theme/spacer.gif b/fs_selfservice/fri/theme/spacer.gif
new file mode 100644
index 000000000..8f096840c
--- /dev/null
+++ b/fs_selfservice/fri/theme/spacer.gif
Binary files differ
diff --git a/fs_selfservice/fri/theme/text.css b/fs_selfservice/fri/theme/text.css
new file mode 100644
index 000000000..9625ca0bb
--- /dev/null
+++ b/fs_selfservice/fri/theme/text.css
@@ -0,0 +1,10 @@
+/*
+ * Text
+ */
+
+/* Error */
+
+.error {
+ color: #CC3333;
+}
+
diff --git a/fs_selfservice/fri/version.php b/fs_selfservice/fri/version.php
new file mode 100644
index 000000000..7f313a138
--- /dev/null
+++ b/fs_selfservice/fri/version.php
@@ -0,0 +1,10 @@
+<?php
+
+/**
+ * @file
+ * version
+ */
+
+$ARI_VERSION = 'FreePBX 2.3';
+
+?>
diff --git a/fs_selfservice/fs_passwd_test b/fs_selfservice/fs_passwd_test
new file mode 100755
index 000000000..4f8b8a888
--- /dev/null
+++ b/fs_selfservice/fs_passwd_test
@@ -0,0 +1,19 @@
+#!/usr/bin/perl -w
+
+use strict;
+use FS::SelfService qw(passwd);
+
+my $rv = passwd(
+ 'username' => 'ivan',
+ 'old_password' => 'heyhoo',
+ 'new_password' => 'haloo',
+);
+my $error = $rv->{error};
+
+if ( $error eq 'Incorrect password.' ) {
+ exit;
+} else {
+ die $error if $error;
+ die "no error";
+}
+
diff --git a/fs_selfservice/java/biz/freeside/SelfService.java b/fs_selfservice/java/biz/freeside/SelfService.java
new file mode 100755
index 000000000..752815a02
--- /dev/null
+++ b/fs_selfservice/java/biz/freeside/SelfService.java
@@ -0,0 +1,52 @@
+package biz.freeside;
+
+// see http://ws.apache.org/xmlrpc/client.html for these classes
+import org.apache.xmlrpc.XmlRpcException;
+import org.apache.xmlrpc.client.XmlRpcClient;
+import org.apache.xmlrpc.client.XmlRpcClientConfig;
+import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
+
+import java.util.HashMap;
+import java.util.List;
+import java.net.URL;
+
+public class SelfService extends XmlRpcClient {
+
+ public SelfService( String url ) throws Exception {
+ super();
+ XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
+ config.setServerURL(new URL( url ));
+ this.setConfig(config);
+ }
+
+ private String canonicalMethod ( String method ) {
+ String canonical = new String(method);
+ if (!canonical.startsWith( "FS.SelfService.XMLRPC." )) {
+ canonical = "FS.SelfService.XMLRPC." + canonical;
+ }
+ return canonical;
+ }
+
+ private HashMap testResponse ( Object toTest ) throws XmlRpcException {
+ if (! ( toTest instanceof HashMap )) {
+ throw new XmlRpcException("expected HashMap but got" + toTest.getClass());
+ }
+ return (HashMap) toTest;
+ }
+
+ public HashMap execute( String method, List params ) throws XmlRpcException {
+ return testResponse(super.execute( canonicalMethod(method), params ));
+ }
+
+ public HashMap execute( String method, Object[] params ) throws XmlRpcException {
+ return testResponse(super.execute( canonicalMethod(method), params ));
+ }
+
+ public HashMap execute( XmlRpcClientConfig config, String method, List params ) throws XmlRpcException {
+ return testResponse(super.execute( config, canonicalMethod(method), params ));
+ }
+
+ public HashMap execute( XmlRpcClientConfig config, String method, Object[] params ) throws XmlRpcException {
+ return testResponse(super.execute( config, canonicalMethod(method), params ));
+ }
+}
diff --git a/fs_selfservice/java/freeside_login_example.java b/fs_selfservice/java/freeside_login_example.java
new file mode 100755
index 000000000..cb6d2bcac
--- /dev/null
+++ b/fs_selfservice/java/freeside_login_example.java
@@ -0,0 +1,45 @@
+
+import biz.freeside.SelfService;
+import org.apache.commons.logging.impl.SimpleLog; //included in apache xmlrpc
+import java.util.HashMap;
+import java.util.Vector;
+
+public class freeside_login_example {
+ private static SimpleLog logger = new SimpleLog("SelfService");
+
+ public static void main( String args[] ) throws Exception {
+ SelfService client =
+ new SelfService( "http://192.168.1.221:8081/xmlrpc.cgi" );
+
+ Vector params = new Vector();
+ params.addElement( "username" );
+ params.addElement( "testuser" );
+ params.addElement( "domain" );
+ params.addElement( "example.com" );
+ params.addElement( "password" );
+ params.addElement( "testpass" );
+ HashMap result = client.execute( "login", params );
+
+ String error = (String) result.get("error");
+
+ if (error.length() < 1) {
+
+ // successful login
+
+ String sessionId = (String) result.get("session_id");
+
+ logger.trace("[login] logged into freeside with session_id="+sessionId);
+
+ // store session id in your session store to be used for other calls
+
+ }else{
+
+ // successful login
+
+ logger.warn("[login] error logging into freeside: "+error);
+
+ // display error message to user
+
+ }
+ }
+}
diff --git a/fs_selfservice/java/freeside_signup_example.java b/fs_selfservice/java/freeside_signup_example.java
new file mode 100755
index 000000000..6c695c445
--- /dev/null
+++ b/fs_selfservice/java/freeside_signup_example.java
@@ -0,0 +1,69 @@
+
+import biz.freeside.SelfService;
+import org.apache.commons.logging.impl.SimpleLog; // included in apache xmlrpc
+import java.util.HashMap;
+import java.util.Vector;
+
+public class freeside_signup_example {
+ private static SimpleLog logger = new SimpleLog("SelfService");
+
+ public static void main( String args[] ) throws Exception {
+ SelfService client =
+ new SelfService( "http://192.168.1.221:8081/xmlrpc.cgi" );
+
+ Vector params = new Vector();
+ params.addElement( "first" );
+ params.addElement( "Test" );
+ params.addElement( "last" );
+ params.addElement( "User" );
+ params.addElement( "address1");
+ params.addElement( "123 Test Street" );
+ params.addElement( "address2");
+ params.addElement( "Suite A" );
+ params.addElement( "city");
+ params.addElement( "Testville" );
+ params.addElement( "state");
+ params.addElement( "OH" );
+ params.addElement( "zip");
+ params.addElement( "44632" );
+ params.addElement( "country");
+ params.addElement( "US" );
+ params.addElement( "daytime" );
+ params.addElement( "216-412-1234" );
+ params.addElement( "fax" );
+ params.addElement( "216-412-1235" );
+ params.addElement( "payby" );
+ params.addElement( "BILL" );
+ params.addElement( "invoicing_list" );
+ params.addElement( "test@test.example.com" );
+ params.addElement( "pkgpart" );
+ params.addElement( "101" );
+ params.addElement( "popnum" );
+ params.addElement( "4018" );
+ params.addElement( "username" );
+ params.addElement( "testy" );
+ params.addElement( "_password" );
+ params.addElement( "tester" );
+ HashMap result = client.execute( "new_customer", params );
+
+ String error = (String) result.get("error");
+
+ if (error.length() < 1) {
+
+ // successful signup
+
+ String custnum = (String) result.get("custnum");
+
+ logger.trace("[new_customer] signup with custnum "+custnum);
+
+ }else{
+
+ // unsuccessful signup
+
+ logger.warn("[new_customer] signup error: "+error);
+
+ // display error message to user
+
+ }
+ }
+}
diff --git a/fs_selfservice/php/freeside.class.php b/fs_selfservice/php/freeside.class.php
new file mode 100644
index 000000000..bb2ac98ee
--- /dev/null
+++ b/fs_selfservice/php/freeside.class.php
@@ -0,0 +1,34 @@
+<?php
+class FreesideSelfService {
+
+ //Change this to match the location of your selfservice xmlrpc.cgi or daemon
+ #var $URL = 'https://localhost/selfservice/xmlrpc.cgi';
+ var $URL = 'http://localhost/selfservice/xmlrpc.cgi';
+
+ function FreesideSelfService() {
+ $this;
+ }
+
+ public function __call($name, $arguments) {
+
+ error_log("[FreesideSelfService] $name called, sending to ". $this->URL);
+
+ $request = xmlrpc_encode_request("FS.SelfService.XMLRPC.$name", $arguments);
+ $context = stream_context_create( array( 'http' => array(
+ 'method' => "POST",
+ 'header' => "Content-Type: text/xml",
+ 'content' => $request
+ )));
+ $file = file_get_contents($this->URL, false, $context);
+ $response = xmlrpc_decode($file);
+ if (xmlrpc_is_fault($response)) {
+ trigger_error("[FreesideSelfService] XML-RPC communication error: $response[faultString] ($response[faultCode])");
+ } else {
+ //error_log("[FreesideSelfService] $response");
+ return $response;
+ }
+ }
+
+}
+
+?>
diff --git a/fs_selfservice/php/freeside.login_example.php b/fs_selfservice/php/freeside.login_example.php
new file mode 100644
index 000000000..69174a40a
--- /dev/null
+++ b/fs_selfservice/php/freeside.login_example.php
@@ -0,0 +1,37 @@
+<?
+
+require('freeside.class.php');
+$freeside = new FreesideSelfService();
+
+$domain = 'example.com';
+
+$response = $freeside->login( array(
+ 'username' => strtolower($_POST['username']),
+ 'domain' => $domain,
+ 'password' => strtolower($_POST['password']),
+) );
+
+error_log("[login] received response from freeside: $response");
+$error = $response['error'];
+
+if ( ! $error ) {
+
+ // sucessful login
+
+ $session_id = $response['session_id'];
+
+ error_log("[login] logged into freeside with session_id=$session_id");
+
+ // store session id in your session store, to be used for other calls
+
+} else {
+
+ // unsucessful login
+
+ error_log("[login] error logging into freeside: $error");
+
+ // display error message to user
+
+}
+
+?>
diff --git a/fs_selfservice/php/freeside_signup_example.php b/fs_selfservice/php/freeside_signup_example.php
new file mode 100644
index 000000000..8b1dc193c
--- /dev/null
+++ b/fs_selfservice/php/freeside_signup_example.php
@@ -0,0 +1,49 @@
+<?
+
+require('freeside.class.php');
+$freeside = new FreesideSelfService();
+
+$response = $freeside->new_customer( array(
+ 'agentnum' => 1,
+
+ 'first' => $_POST['first'],
+ 'last' => $_POST['last'],
+ 'address1' => $_POST['address1'],
+ 'address2' => $_POST['address2'],
+ 'city' => $_POST['city'],
+ 'state' => $_POST['state'],
+ 'zip' => $_POST['zip'],
+ 'country' => 'US',
+ 'daytime' => $_POST['daytime'],
+ 'fax' => $_POST['fax'],
+
+ 'payby' => 'BILL',
+ 'invoicing_list' => $_POST['email'],
+
+ 'pkgpart' => 2,
+ 'username' => strtolower($_POST['username']),
+ '_password' => strtolower($_POST['password'])
+) );
+
+error_log("[new_customer] received response from freeside: $response");
+$error = $response['error'];
+
+if ( ! $error ) {
+
+ // sucessful signup
+
+ $custnum = $response['custnum'];
+
+ error_log("[new_customer] signup up with custnum $custnum");
+
+} else {
+
+ // unsucessful signup
+
+ error_log("[new_customer] signup error:: $error");
+
+ // display error message to user
+
+}
+
+?>
diff --git a/fs_selfservice/php/login.php b/fs_selfservice/php/login.php
new file mode 100644
index 000000000..d9609147e
--- /dev/null
+++ b/fs_selfservice/php/login.php
@@ -0,0 +1,90 @@
+<?php
+
+require('freeside.class.php');
+$freeside = new FreesideSelfService();
+
+$login_info = $freeside->login_info();
+
+extract($login_info);
+
+$error = $_GET['error'];
+if ( $error ) {
+ $username = $_GET['username'];
+ $domain = $_GET['domain'];
+}
+
+?>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML><HEAD><TITLE>Login</TITLE></HEAD>
+<BODY BGCOLOR="#e8e8e8"><FONT SIZE=5>Login</FONT><BR><BR>
+<FONT SIZE="+1" COLOR="#ff0000"><?php echo htmlspecialchars($error); ?></FONT>
+
+<FORM ACTION="process_login.php" METHOD=POST>
+<INPUT TYPE="hidden" NAME="session" VALUE="login">
+
+<TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=2 CELLPADDING=0>
+
+<TR>
+ <TH ALIGN="right">Username </TH>
+ <TD>
+ <INPUT TYPE="text" NAME="username" VALUE="<?php echo htmlspecialchars($username); ?>"><?php if ( $single_domain ) { echo '@'.$single_domain; } ?>
+ </TD>
+</TR>
+
+<?php if ( $single_domain ) { ?>
+
+ <INPUT TYPE="hidden" NAME="domain" VALUE="<?php echo $single_domain ?>">
+
+<?php } else { ?>
+
+ <TR>
+ <TH ALIGN="right">Domain </TH>
+ <TD>
+ <INPUT TYPE="text" NAME="domain" VALUE="<?php echo htmlspecialchars($domain); ?>">
+ </TD>
+ </TR>
+
+<?php } ?>
+
+<TR>
+ <TH ALIGN="right">Password </TH>
+ <TD>
+ <INPUT TYPE="password" NAME="password">
+ </TD>
+</TR>
+<TR>
+ <TD COLSPAN=2 ALIGN="center"><INPUT TYPE="submit" VALUE="Login"></TD>
+</TR>
+</TABLE>
+</FORM>
+
+<?php if ( $phone_login ) { ?>
+
+ <B>OR</B><BR><BR>
+
+ <FORM ACTION="process_login.php" METHOD=POST>
+ <INPUT TYPE="hidden" NAME="session" VALUE="login">
+ <TABLE BGCOLOR="#c0c0c0" BORDER=0 CELLSPACING=2 CELLPADDING=0>
+ <TR>
+ <TH ALIGN="right">Phone number </TH>
+ <TD>
+ <INPUT TYPE="text" NAME="username" VALUE="<?php echo htmlspecialchars($username) ?>">
+ </TD>
+ </TR>
+ <INPUT TYPE="hidden" NAME="domain" VALUE="svc_phone">
+ <TR>
+ <TH ALIGN="right">PIN </TH>
+ <TD>
+ <INPUT TYPE="password" NAME="password">
+ </TD>
+ </TR>
+ <TR>
+ <TD COLSPAN=2 ALIGN="center"><INPUT TYPE="submit" VALUE="Login"></TD>
+ </TR>
+ </TABLE>
+ </FORM>
+
+<?php } ?>
+
+</BODY></HTML>
+
diff --git a/fs_selfservice/php/main.php b/fs_selfservice/php/main.php
new file mode 100644
index 000000000..b34a47730
--- /dev/null
+++ b/fs_selfservice/php/main.php
@@ -0,0 +1,39 @@
+<?php
+
+require('freeside.class.php');
+$freeside = new FreesideSelfService();
+
+$session_id = $_GET['session_id'];
+
+$response = $freeside->customer_info( array(
+ 'session_id' => $session_id,
+) );
+
+$error = $response['error'];
+
+if ( $error ) {
+ header('Location:login.php?error='. urlencode($error));
+ die();
+}
+
+extract($response);
+
+?>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+ <HEAD>
+ <TITLE>My Account</TITLE>
+ </HEAD>
+ <BODY>
+ <H1>My Account</H1>
+
+ Hello, <?php echo htmlspecialchars($name); ?><BR><BR>
+
+ <?php echo $small_custview; ?>
+
+ <BR>
+
+ <A HREF="order_renew.php?session_id=<?php echo $session_id; ?>">Renew early</A>
+
+ </BODY>
+</HTML>
diff --git a/fs_selfservice/php/order_renew.php b/fs_selfservice/php/order_renew.php
new file mode 100644
index 000000000..e74ba40af
--- /dev/null
+++ b/fs_selfservice/php/order_renew.php
@@ -0,0 +1,166 @@
+<?php
+
+require('freeside.class.php');
+$freeside = new FreesideSelfService();
+
+$session_id = $_GET['session_id'];
+
+$renew_info = $freeside->renew_info( array(
+ 'session_id' => $session_id,
+) );
+
+$error = $renew_info['error'];
+
+if ( $error ) {
+ header('Location:login.php?error='. urlencode($error));
+ die();
+}
+
+#in the simple case, just deal with the first package
+$bill_date = $renew_info['dates'][0]['bill_date'];
+$bill_date_pretty = $renew_info['dates'][0]['bill_date_pretty'];
+$renew_date = $renew_info['dates'][0]['renew_date'];
+$renew_date_pretty = $renew_info['dates'][0]['renew_date_pretty'];
+$amount = $renew_info['dates'][0]['amount'];
+
+$payment_info = $freeside->payment_info( array(
+ 'session_id' => $session_id,
+) );
+
+extract($payment_info);
+
+?>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+ <HEAD>
+ <TITLE>Renew Early</TITLE>
+ </HEAD>
+ <BODY>
+ <H1>Renew Early</H1>
+
+ <FONT SIZE="+1" COLOR="#ff0000"><?php echo htmlspecialchars($_GET['error']); ?></FONT>
+
+ <FORM NAME="OneTrueForm" METHOD="POST" ACTION="process_payment_order_renew.php" onSubmit="document.OneTrueForm.process.disabled=true">
+
+ <INPUT TYPE="hidden" NAME="date" VALUE="<?php echo $date; ?>">
+ <INPUT TYPE="hidden" NAME="session_id" VALUE="<?php echo $session_id; ?>">
+ <INPUT TYPE="hidden" NAME="amount" VALUE="<?php echo $amount; ?>">
+
+ A payment of $<?php echo $amount; ?> will renew your account through <?php echo $renew_date_pretty; ?>.<BR><BR>
+
+ <TABLE BGCOLOR="#cccccc">
+ <TR>
+ <TD ALIGN="right">Amount</TD>
+ <TD>
+ <TABLE><TR><TD BGCOLOR="#ffffff">
+ $<?php echo $amount; ?>
+ </TD></TR></TABLE>
+ </TD>
+ </TR>
+ <TR>
+ <TD ALIGN="right">Card&nbsp;type</TD>
+ <TD>
+ <SELECT NAME="card_type"><OPTION></OPTION>
+ <?php foreach ( array_keys($card_types) as $t ) { ?>
+ <OPTION <?php if ($card_type == $card_types[$t] ) { ?> SELECTED <?php } ?>
+ VALUE="<?php echo $card_types[$t]; ?>"
+ ><?php echo $t; ?>
+ <?php } ?>
+ </SELECT>
+ </TD>
+ </TR>
+
+ <TR>
+ <TD ALIGN="right">Card&nbsp;number</TD>
+ <TD>
+ <TABLE>
+ <TR>
+ <TD>
+ <INPUT TYPE="text" NAME="payinfo" SIZE=20 MAXLENGTH=19 VALUE="<?php echo $payinfo; ?>"> </TD>
+ <TD>Exp.</TD>
+ <TD>
+ <SELECT NAME="month">
+ <?php foreach ( array('01','02','03','04','05','06','07','08','09','10','11','12') as $m) { ?>
+ <OPTION<?php if ($m == $month ) { ?> SELECTED<?php } ?>
+ ><?php echo $m; ?>
+ <?php } ?>
+ </SELECT>
+ </TD>
+ <TD> / </TD>
+ <TD>
+ <SELECT NAME="year">
+ <?php $lt = localtime(); $y = $lt[5] + 1900;
+ for ($y = $lt[5]+1900; $y < $lt[5] + 1910; $y++ ) { ?>
+ <OPTION<?php if ($y == $year ) { ?> SELECTED<?php } ?>
+ ><?php echo $y; ?>
+ <?php } ?>
+ </SELECT>
+ </TD>
+ </TR>
+ </TABLE>
+ </TD>
+ </TR>
+ <?php if ( $withcvv ) { ?>
+ <TR>
+ <TD ALIGN="right">CVV2&nbsp;(<A HREF="javascript:myopen('cvv2.html','cvv2','toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=yes,copyhistory=no,width=480,height=288')">help</A>)</TD>
+ <TD><INPUT TYPE="text" NAME="paycvv" VALUE="" SIZE=4 MAXLENGTH=4></TD>
+ </TR>
+ <?php } ?>
+ <TR>
+ <TD ALIGN="right">Exact&nbsp;name&nbsp;on&nbsp;card</TD>
+ <TD><INPUT TYPE="text" SIZE=32 MAXLENGTH=80 NAME="payname" VALUE="<?php echo $payname; ?>"></TD>
+ </TR><TR>
+ <TD ALIGN="right">Card&nbsp;billing&nbsp;address</TD>
+ <TD>
+ <INPUT TYPE="text" SIZE=40 MAXLENGTH=80 NAME="address1" VALUE="<?php echo $address1; ?>">
+ </TD>
+ </TR><TR>
+ <TD ALIGN="right">Address&nbsp;line&nbsp;2</TD>
+ <TD>
+ <INPUT TYPE="text" SIZE=40 MAXLENGTH=80 NAME="address2" VALUE="<?php echo $address2; ?>">
+ </TD>
+ </TR><TR>
+ <TD ALIGN="right">City</TD>
+ <TD>
+ <TABLE>
+ <TR>
+ <TD>
+ <INPUT TYPE="text" NAME="city" SIZE="12" MAXLENGTH=80 VALUE="<?php echo $city; ?>">
+ </TD>
+ <TD>State</TD>
+ <TD>
+ <SELECT NAME="state">
+ <?php foreach ( $states as $s ) { ?>
+ <OPTION<?php if ($s == $state) { ?> SELECTED<?php } ?>
+ ><?php echo $s; ?>
+ <?php } ?>
+ </SELECT>
+ </TD>
+ <TD>Zip</TD>
+ <TD>
+ <INPUT TYPE="text" NAME="zip" SIZE=11 MAXLENGTH=10 VALUE="<?php echo $zip; ?>">
+ </TD>
+ </TR>
+ </TABLE>
+ </TD>
+ </TR>
+
+ <TR>
+ <TD COLSPAN=2>
+ <INPUT TYPE="checkbox" CHECKED NAME="save" VALUE="1">
+ Remember this information
+ </TD>
+ </TR><TR>
+ <TD COLSPAN=2>
+ <INPUT TYPE="checkbox"<?php if ( $payby == 'CARD' ) { ?> CHECKED<?php } ?> NAME="auto" VALUE="1" onClick="if (this.checked) { document.OneTrueForm.save.checked=true; }">
+ Charge future payments to this card automatically
+ </TD>
+ </TR>
+ </TABLE>
+ <BR>
+ <INPUT TYPE="hidden" NAME="paybatch" VALUE="<?php echo $paybatch; ?>">
+ <INPUT TYPE="submit" NAME="process" VALUE="Process payment"> <!-- onClick="this.disabled=true"> -->
+ </FORM>
+
+ </BODY>
+</HTML>
diff --git a/fs_selfservice/php/process_login.php b/fs_selfservice/php/process_login.php
new file mode 100644
index 000000000..1f4fd9a6b
--- /dev/null
+++ b/fs_selfservice/php/process_login.php
@@ -0,0 +1,38 @@
+<?php
+
+require('freeside.class.php');
+$freeside = new FreesideSelfService();
+
+$response = $freeside->login( array(
+ 'username' => strtolower($_POST['username']),
+ 'domain' => strtolower($_POST['domain']),
+ 'password' => strtolower($_POST['password']),
+) );
+
+#error_log("[login] received response from freeside: $response");
+
+$error = $response['error'];
+
+if ( $error ) {
+
+ header('Location:login.php?username='. urlencode($username).
+ '&domain='. urlencode($domain).
+ '&error='. urlencode($error)
+ );
+ die();
+
+}
+
+// sucessful login
+
+$session_id = $response['session_id'];
+
+#error_log("[login] logged into freeside with session_id=$session_id");
+
+// now what? for now, always redirect to the main page.
+// eventually, other options?
+
+header("Location:main.php?session_id=$session_id")
+#die();
+
+?>
diff --git a/fs_selfservice/php/process_payment_order_renew.php b/fs_selfservice/php/process_payment_order_renew.php
new file mode 100644
index 000000000..20594624b
--- /dev/null
+++ b/fs_selfservice/php/process_payment_order_renew.php
@@ -0,0 +1,74 @@
+<?php
+
+require('freeside.class.php');
+$freeside = new FreesideSelfService();
+
+$response = $freeside->process_payment_order_renew( array(
+ 'session_id' => $_POST['session_id'],
+ 'payby' => 'CARD',
+ 'amount' => $_POST['amount'],
+ 'payinfo' => $_POST['payinfo'],
+ 'paycvv' => $_POST['paycvv'],
+ 'month' => $_POST['month'],
+ 'year' => $_POST['year'],
+ 'payname' => $_POST['payname'],
+ 'address1' => $_POST['address1'],
+ 'address2' => $_POST['address2'],
+ 'city' => $_POST['city'],
+ 'state' => $_POST['state'],
+ 'zip' => $_POST['zip'],
+ 'save' => $_POST['save'],
+ 'auto' => $_POST['auto'],
+ 'paybatch' => $_POST['paybatch'],
+) );
+
+error_log("[process_payment_order_renew] received response from freeside: $response");
+
+$error = $response['error'];
+
+if ( $error ) {
+
+ error_log("[process_payment_order_renew] response error: $error");
+
+ header('Location:order_renew.php'.
+ '?session_id='. urlencode($_POST['session_id']).
+ '?error='. urlencode($error).
+ '&payby=CARD'.
+ '&amount='. urlencode($_POST['amount']).
+ '&payinfo='. urlencode($_POST['payinfo']).
+ '&paycvv='. urlencode($_POST['paycvv']).
+ '&month='. urlencode($_POST['month']).
+ '&year='. urlencode($_POST['year']).
+ '&payname='. urlencode($_POST['payname']).
+ '&address1='. urlencode($_POST['address1']).
+ '&address2='. urlencode($_POST['address2']).
+ '&city='. urlencode($_POST['city']).
+ '&state='. urlencode($_POST['state']).
+ '&zip='. urlencode($_POST['zip']).
+ '&save='. urlencode($_POST['save']).
+ '&auto='. urlencode($_POST['auto']).
+ '&paybatch='. urlencode($_POST['paybatch'])
+ );
+ die();
+
+}
+
+// sucessful renewal.
+
+$session_id = $response['session_id'];
+
+// now what?
+
+?>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+ <HEAD>
+ <TITLE>Renew Early</TITLE>
+ </HEAD>
+ <BODY>
+ <H1>Renew Early</H1>
+
+ Renewal processed sucessfully.
+
+ </BODY>
+</HTML>