summaryrefslogtreecommitdiff
path: root/httemplate/view
diff options
context:
space:
mode:
Diffstat (limited to 'httemplate/view')
-rwxr-xr-xhttemplate/view/cust_main.cgi4
-rwxr-xr-xhttemplate/view/cust_main/notes.html10
-rw-r--r--httemplate/view/cust_main/payment_history.html9
-rw-r--r--httemplate/view/cust_main/payment_history/credit.html8
-rw-r--r--httemplate/view/cust_main/payment_history/payment.html8
-rw-r--r--httemplate/view/cust_main/payment_history/voided_payment.html4
-rw-r--r--httemplate/view/cust_main/tickets.html25
-rw-r--r--httemplate/view/cust_svc.cgi23
-rw-r--r--httemplate/view/elements/svc_export_settings.html34
-rw-r--r--httemplate/view/elements/tr.html9
-rwxr-xr-xhttemplate/view/svc_acct.cgi387
-rw-r--r--httemplate/view/svc_acct/basics.html158
-rw-r--r--httemplate/view/svc_acct/change_svc.html21
-rw-r--r--httemplate/view/svc_acct/change_svc_form.html23
-rw-r--r--httemplate/view/svc_acct/hosting.html38
-rw-r--r--httemplate/view/svc_acct/radius_usage.html77
-rw-r--r--httemplate/view/svc_acct/usage.html27
-rwxr-xr-xhttemplate/view/svc_domain.cgi198
-rw-r--r--httemplate/view/svc_domain/acct_defaults.html71
-rw-r--r--httemplate/view/svc_domain/basics.html134
-rw-r--r--httemplate/view/svc_domain/dns.html94
-rwxr-xr-xhttemplate/view/svc_forward.cgi32
-rw-r--r--httemplate/view/svc_mailinglist.cgi71
-rw-r--r--httemplate/view/svc_phone.cgi40
24 files changed, 980 insertions, 525 deletions
diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi
index 6e024132b..6eea2b09e 100755
--- a/httemplate/view/cust_main.cgi
+++ b/httemplate/view/cust_main.cgi
@@ -1,5 +1,5 @@
<% include('/elements/header.html', {
- 'title' => "Customer View: ". $cust_main->name,
+ 'title' => "Customer: ". $cust_main->name,
'nobr' => 1,
})
%>
@@ -128,7 +128,7 @@ Comments
'actionlabel' => 'Enter customer note',
'cust_main' => $cust_main,
'width' => 616,
- 'height' => 408,
+ 'height' => 538, #575
)
%>
diff --git a/httemplate/view/cust_main/notes.html b/httemplate/view/cust_main/notes.html
index 833c92e67..71511dc93 100755
--- a/httemplate/view/cust_main/notes.html
+++ b/httemplate/view/cust_main/notes.html
@@ -11,6 +11,9 @@
% }
<TH CLASS="grid" BGCOLOR="#cccccc">Person</TH>
<TH CLASS="grid" BGCOLOR="#cccccc">Note</TH>
+% if ($curuser->access_right('Edit customer note') ) {
+ <TH CLASS="grid" BGCOLOR="#cccccc">&nbsp;</TH>
+% }
</TR>
% my $bgcolor1 = '#eeeeee';
@@ -34,7 +37,7 @@
% ";notenum=$notenum",
% 'actionlabel' => 'Edit customer note',
% 'width' => 616,
-% 'height' => 408,
+% 'height' => 538, #575
% 'frame' => 'top',
% );
% my $clickjs = qq!onclick="$onclick"!;
@@ -50,8 +53,11 @@
&nbsp;<% $note->otaker%>
</TD>
<TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
- &nbsp;<%$note->comments%><% $edit %>
+ &nbsp;<%$note->comments%>
</TD>
+% if($edit) {
+ <TD CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $edit %></TD>
+% }
</TR>
% } #end display notes
diff --git a/httemplate/view/cust_main/payment_history.html b/httemplate/view/cust_main/payment_history.html
index 56a2c4dde..0dc4c41d5 100644
--- a/httemplate/view/cust_main/payment_history.html
+++ b/httemplate/view/cust_main/payment_history.html
@@ -205,11 +205,11 @@
<TR ID="balance_forward_row">
<TD CLASS="grid" BGCOLOR="#dddddd">
- <% time2str("%D",$date) %>
+ <% time2str($date_format, $date) %>
</TD>
<TD CLASS="grid" BGCOLOR="#dddddd">
- <I>Starting balance on <% time2str("%D",$date) %></I>
+ <I>Starting balance on <% time2str($date_format, $date) %></I>
(<A HREF="javascript:void(0);" onClick="show_history();">show prior history</A>)
</TD>
@@ -297,7 +297,7 @@
<A NAME="<% $target %>">
% }
- <% time2str("%D",$item->{'date'}) %>
+ <% time2str($date_format, $item->{'date'}) %>
% if ( $target && $target{$target} == 1 ) {
</A>
@@ -355,6 +355,7 @@ my( $cust_main ) = @_;
my $custnum = $cust_main->custnum;
my $conf = new FS::Conf;
+my $date_format = $conf->config('date_format') || '%m/%d/%Y';
my $curuser = $FS::CurrentUser::CurrentUser;
@@ -376,7 +377,7 @@ my @history = ();
my %opt = (
( map { $_ => scalar($conf->config($_)) }
- qw( card_refund-days )
+ qw( card_refund-days date_format )
),
( map { $_ => $conf->exists($_) }
qw( deleteinvoices deletepayments deleterefunds pkg-balances )
diff --git a/httemplate/view/cust_main/payment_history/credit.html b/httemplate/view/cust_main/payment_history/credit.html
index 058c6f536..fa5838e4e 100644
--- a/httemplate/view/cust_main/payment_history/credit.html
+++ b/httemplate/view/cust_main/payment_history/credit.html
@@ -4,6 +4,8 @@ by <% $cust_credit->otaker %><% "$reason$desc$apply$delete$unapply" %>
my( $cust_credit, %opt ) = @_;
+my $date_format = $opt{'date_format'} || '%m/%d/%Y';
+
my $curuser = $FS::CurrentUser::CurrentUser;
my @cust_credit_bill = $cust_credit->cust_credit_bill;
@@ -56,7 +58,7 @@ if ( scalar(@cust_credit_bill) == 0
&& scalar(@cust_credit_refund) == 1
&& $cust_credit->credited == 0 ) {
#applied to one refund
- $desc .= ' refunded on '. time2str("%D", $cust_credit_refund[0]->_date);
+ $desc .= ' refunded on '. time2str($date_format, $cust_credit_refund[0]->_date);
} else {
#complicated
$desc .= '<BR>';
@@ -67,11 +69,11 @@ if ( scalar(@cust_credit_bill) == 0
'$'. $app->amount.
' '. $app->applied_to_invoice.
'<BR>';
- #' on '. time2str("%D", $app->_date).
+ #' on '. time2str($date_format, $app->_date).
} elsif ( $app->isa('FS::cust_credit_refund') ) {
$desc .= '&nbsp;&nbsp;'.
'$'. $app->amount.
- ' refunded on '. time2str("%D", $app->_date).
+ ' refunded on '. time2str($date_format, $app->_date).
'<BR>';
} else {
die "$app is not a FS::cust_credit_bill or a FS::cust_credit_refund";
diff --git a/httemplate/view/cust_main/payment_history/payment.html b/httemplate/view/cust_main/payment_history/payment.html
index a4a349bb8..53fc0dad3 100644
--- a/httemplate/view/cust_main/payment_history/payment.html
+++ b/httemplate/view/cust_main/payment_history/payment.html
@@ -4,6 +4,8 @@
my( $cust_pay, %opt ) = @_;
+my $date_format = $opt{'date_format'} || '%m/%d/%Y';
+
my $curuser = $FS::CurrentUser::CurrentUser;
my $payby = $cust_pay->payby;
@@ -79,7 +81,7 @@ if ( scalar(@cust_bill_pay) == 0
&& scalar(@cust_pay_refund) == 1
&& $cust_pay->unapplied == 0 ) {
#applied to one refund
- $desc .= ' refunded on '. time2str("%D", $cust_pay_refund[0]->_date);
+ $desc .= ' refunded on '. time2str($date_format, $cust_pay_refund[0]->_date);
} else {
#complicated
$desc .= '<BR>';
@@ -90,11 +92,11 @@ if ( scalar(@cust_bill_pay) == 0
'$'. $app->amount.
' '. $app->applied_to_invoice.
'<BR>';
- #' on '. time2str("%D", $cust_bill_pay->_date).
+ #' on '. time2str($date_format, $cust_bill_pay->_date).
} elsif ( $app->isa('FS::cust_pay_refund') ) {
$desc .= '&nbsp;&nbsp;'.
'$'. $app->amount.
- ' refunded on '. time2str("%D", $app->_date).
+ ' refunded on '. time2str($date_format, $app->_date).
'<BR>';
} else {
die "$app is not a FS::cust_bill_pay or FS::cust_pay_refund";
diff --git a/httemplate/view/cust_main/payment_history/voided_payment.html b/httemplate/view/cust_main/payment_history/voided_payment.html
index 610372721..be68ff091 100644
--- a/httemplate/view/cust_main/payment_history/voided_payment.html
+++ b/httemplate/view/cust_main/payment_history/voided_payment.html
@@ -1,10 +1,12 @@
<DEL>Payment <% $info %></DEL>
-<I>voided <% time2str("%D", $cust_pay_void->void_date) %>
+<I>voided <% time2str($date_format, $cust_pay_void->void_date) %>
by <% $cust_pay_void->otaker %></I><% $unvoid %>
<%init>
my( $cust_pay_void, %opt ) = @_;
+my $date_format = $opt{'date_format'} || '%m/%d/%Y';
+
my $curuser = $FS::CurrentUser::CurrentUser;
my $payby = $cust_pay_void->payby;
diff --git a/httemplate/view/cust_main/tickets.html b/httemplate/view/cust_main/tickets.html
index 167849c76..e1f9a131e 100644
--- a/httemplate/view/cust_main/tickets.html
+++ b/httemplate/view/cust_main/tickets.html
@@ -1,7 +1,24 @@
+<FORM METHOD="GET" ACTION="<% $new_base %>" NAME="CreateTicketForm">
+<INPUT TYPE="submit" VALUE="Create new ticket">
+in queue
+<SELECT NAME="Queue">
+% my %queues = FS::TicketSystem->queues();
+% foreach my $queueid ( keys %queues ) {
+% #should consider whether the user has ACL to create ticket in each queue
+ <OPTION VALUE="<% $queueid %>"
+ <% $queueid == $new_param{'Queue'} ? 'SELECTED' : '' %>
+ ><% $queues{$queueid} |h %>
+% }
+</SELECT>
+% foreach my $param ( grep { $_ ne 'Queue' } keys %new_param ) {
+ <INPUT TYPE="hidden" NAME="<% $param %>" VALUE="<% $new_param{$param} |h %>">
+% }
+</FORM>
+<BR>
+
(<A HREF="<% $open_link %>">View <% $openlabel %> tickets for this customer</A>)
(<A HREF="<% $res_link %>">View resolved tickets for this customer</A>)
-<BR>
-(<A HREF="<% $new_link %>">Create new ticket for this customer</A>)
+<BR><BR>
<% include("/elements/table-grid.html") %>
% my $bgcolor1 = '#eeeeee';
@@ -73,6 +90,10 @@ my $res_link = FS::TicketSystem->href_customer_tickets(
{ 'statuses' => [ 'resolved' ] }
);
+my( $new_base, %new_param ) = FS::TicketSystem->href_params_new_ticket(
+ $cust_main,
+ join(', ', $cust_main->invoicing_list_emailonly ) );
+
my $new_link = FS::TicketSystem->href_new_ticket(
$cust_main,
join(', ', $cust_main->invoicing_list_emailonly )
diff --git a/httemplate/view/cust_svc.cgi b/httemplate/view/cust_svc.cgi
new file mode 100644
index 000000000..8ccfce3ff
--- /dev/null
+++ b/httemplate/view/cust_svc.cgi
@@ -0,0 +1,23 @@
+<% $cgi->redirect(popurl(1)."$svcdb.cgi?". $svcnum ) %>
+<%init>
+
+#needed here? we're just redirecting. i guess it could reveal the svcdb of a
+#svcnum... oooooo scary. not.
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('View customer services');
+
+#some false laziness w/svc_*.cgi
+
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/;
+my $svcnum = $1;
+my $cust_svc = qsearchs( 'cust_svc', { 'svcnum' => $svcnum } );
+die "Unknown svcnum" unless $cust_svc;
+
+my $part_svc = qsearchs('part_svc',{'svcpart'=> $cust_svc->svcpart } );
+die "Unknown svcpart" unless $part_svc;
+
+my $svcdb = $part_svc->svcdb;
+
+</%init>
+
diff --git a/httemplate/view/elements/svc_export_settings.html b/httemplate/view/elements/svc_export_settings.html
new file mode 100644
index 000000000..c5f2555bd
--- /dev/null
+++ b/httemplate/view/elements/svc_export_settings.html
@@ -0,0 +1,34 @@
+% if ( $FS::CurrentUser::CurrentUser->option('export_getsettings') ) {
+
+% my ( $settings, $defaults ) = $svc_x->export_getsettings;
+% if ( keys %$settings ) {
+
+%# a way to label this "Communigate pro settings".. just a config maybe... eh,
+%# its just for devel
+ External settings
+ <% ntable('#cccccc',2) %>
+
+% foreach my $key ( sort {$defaults->{$a} <=> $defaults->{$b} or $a cmp $b}
+% keys %$settings
+% )
+% {
+ <TR>
+ <TD ALIGN="right"><% $key |h %></TD>
+ <TD BGCOLOR="<% $defaults->{$key} ? '#eeeeee' : '#ffffff' %>">
+ <% $defaults->{$key} ? '<I>' : '<B>' %>
+ <% $settings->{$key} |h %>
+ <% $defaults->{$key} ? '</I>' : '</B>' %>
+ </TD>
+ </TR>
+% }
+
+ </TABLE>
+ <BR>
+
+% }
+% }
+<%init>
+
+my $svc_x = shift;
+
+</%init>
diff --git a/httemplate/view/elements/tr.html b/httemplate/view/elements/tr.html
new file mode 100644
index 000000000..e2ec7d42f
--- /dev/null
+++ b/httemplate/view/elements/tr.html
@@ -0,0 +1,9 @@
+<TR>
+ <TD ALIGN="right"><% $opt{'label'} %></TD>
+ <TD BGCOLOR="#ffffff"><% $opt{'value'} %></TD>
+</TR>
+<%init>
+
+my %opt = @_;
+
+</%init>
diff --git a/httemplate/view/svc_acct.cgi b/httemplate/view/svc_acct.cgi
index 44a2aa611..9135e67e9 100755
--- a/httemplate/view/svc_acct.cgi
+++ b/httemplate/view/svc_acct.cgi
@@ -14,328 +14,63 @@
}
</SCRIPT>
- <% include("/elements/header.html",'Account View', menubar(
+ <% include("/elements/header.html",'View account', menubar(
"Cancel this (unaudited) account" =>
"javascript:areyousure(\'${p}misc/cancel-unaudited.cgi?$svcnum\')",
)) %>
% }
-% if ( $part_svc->part_export_usage ) {
-%
-% my $last_bill;
-% my %plandata;
-% if ( $cust_pkg ) {
-% #false laziness w/httemplate/edit/part_pkg... this stuff doesn't really
-% #belong in plan data
-% %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); }
-% split("\n", $cust_pkg->part_pkg->plandata );
-%
-% $last_bill = $cust_pkg->last_bill;
-% } else {
-% $last_bill = 0;
-% %plandata = ();
-% }
-%
-% my $seconds = $svc_acct->seconds_since_sqlradacct( $last_bill, time );
-% my $hour = int($seconds/3600);
-% my $min = int( ($seconds%3600) / 60 );
-% my $sec = $seconds%60;
-%
-% my $input = $svc_acct->attribute_since_sqlradacct(
-% $last_bill, time, 'AcctInputOctets'
-% ) / 1048576;
-% my $output = $svc_acct->attribute_since_sqlradacct(
-% $last_bill, time, 'AcctOutputOctets'
-% ) / 1048576;
-%
-%
+<% include( 'svc_acct/radius_usage.html',
+ 'svc_acct' => $svc_acct,
+ 'part_svc' => $part_svc,
+ 'cust_pkg' => $cust_pkg,
+ %gopt,
+ )
+%>
-
- RADIUS session information<BR>
- <% ntable('#cccccc',2) %>
- <TR><TD BGCOLOR="#ffffff">
-% if ( $seconds ) {
-
- Online <B><% $hour %></B>h <B><% $min %></B>m <B><% $sec %></B>s
-% } else {
-
- Has not logged on
-% }
-% if ( $cust_pkg ) {
-
- since last bill (<% time2str('%a %b %o %Y', $last_bill) %>)
-% if ( length($plandata{recur_included_hours}) ) {
-
- - <% $plandata{recur_included_hours} %> total hours in plan
-% }
-
- <BR>
-% } else {
-
- (no billing cycle available for unaudited account)<BR>
-% }
-
-
- Upload: <B><% sprintf("%.3f", $input) %></B> megabytes<BR>
- Download: <B><% sprintf("%.3f", $output) %></B> megabytes<BR>
- Last Login: <B><% $svc_acct->last_login_text %></B><BR>
-% my $href = qq!<A HREF="${p}search/sqlradius.cgi?svcnum=$svcnum!;
-
- View session detail:
- <% $href %>;begin=<% $last_bill %>">this billing cycle</A>
- | <% $href %>;begin=<% time-15552000 %>">past six months</A>
- | <% $href %>">all sessions</A>
-
- </TD></TR></TABLE><BR>
-% }
-
-% my @part_svc = ();
-% if ($FS::CurrentUser::CurrentUser->access_right('Change customer service')) {
-
- <SCRIPT TYPE="text/javascript">
- function enable_change () {
- if ( document.OneTrueForm.svcpart.selectedIndex > 1 ) {
- document.OneTrueForm.submit.disabled = false;
- } else {
- document.OneTrueForm.submit.disabled = true;
- }
- }
- </SCRIPT>
-
- <FORM NAME="OneTrueForm" ACTION="<%$p%>edit/process/cust_svc.cgi">
- <INPUT TYPE="hidden" NAME="svcnum" VALUE="<% $svcnum %>">
- <INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum %>">
-
-% #print qq!<BR><A HREF="../misc/sendconfig.cgi?$svcnum">Send account information</A>!;
-%
-% if ( $pkgnum ) {
-% @part_svc = grep { $_->svcdb eq 'svc_acct'
-% && $_->svcpart != $part_svc->svcpart }
-% $cust_pkg->available_part_svc;
-% } else {
-% @part_svc = qsearch('part_svc', {
-% svcdb => 'svc_acct',
-% disabled => '',
-% svcpart => { op=>'!=', value=>$part_svc->svcpart },
-% } );
-% }
-%
-% }
+<% include( 'svc_acct/change_svc_form.html',
+ 'part_svc' => \@part_svc,
+ 'svcnum' => $svcnum,
+ 'pkgnum' => $pkgnum,
+ %gopt,
+ )
+%>
Service #<B><% $svcnum %></B>
| <A HREF="<%$p%>edit/svc_acct.cgi?<%$svcnum%>">Edit this service</A>
-% if ( @part_svc ) {
-
-| <SELECT NAME="svcpart" onChange="enable_change()">
- <OPTION VALUE="">Change service</OPTION>
- <OPTION VALUE="">--------------</OPTION>
-% foreach my $opt_part_svc ( @part_svc ) {
-
- <OPTION VALUE="<% $opt_part_svc->svcpart %>"><% $opt_part_svc->svc %></OPTION>
-% }
-
- </SELECT>
- <INPUT NAME="submit" TYPE="submit" VALUE="Change" disabled>
-
-% }
-
-
-<% &ntable("#cccccc") %><TR><TD><% &ntable("#cccccc",2) %>
-
-<TR>
- <TD ALIGN="right">Service</TD>
- <TD BGCOLOR="#ffffff"><% $part_svc->svc %></TD>
-</TR>
-<TR>
- <TD ALIGN="right">Username</TD>
- <TD BGCOLOR="#ffffff"><% $svc_acct->username %></TD>
-</TR>
-<TR>
- <TD ALIGN="right">Domain</TD>
- <TD BGCOLOR="#ffffff"><% $domain %></TD>
-</TR>
-
-<TR>
- <TD ALIGN="right">Password</TD>
- <TD BGCOLOR="#ffffff">
-% my $password = $svc_acct->get_cleartext_password;
-% if ( $password =~ /^\*\w+\* (.*)$/ ) {
-% $password = $1;
-%
+<% include( 'svc_acct/change_svc.html',
+ 'part_svc' => \@part_svc,
+ %gopt,
+ )
+%>
- <I>(login disabled)</I>
-% }
-% if ( !$password and
-% $svc_acct->_password_encryption ne 'plain' and
-% $svc_acct->_password ) {
- <I>(<% uc($svc_acct->_password_encryption) %> encrypted)</I>
-% }
-% elsif ( $conf->exists('showpasswords') ) {
-
- <PRE><% encode_entities($password) %></PRE>
-% } else {
-
- <I>(hidden)</I>
-% }
-
-
- </TD>
-</TR>
-% $password = '';
-% if ( $conf->exists('security_phrase') ) {
-% my $sec_phrase = $svc_acct->sec_phrase;
-%
-
- <TR>
- <TD ALIGN="right">Security phrase</TD>
- <TD BGCOLOR="#ffffff"><% $svc_acct->sec_phrase %></TD>
- </TR>
-% }
-% if ( $svc_acct->popnum ) {
-% my $svc_acct_pop = qsearchs('svc_acct_pop',{'popnum'=>$svc_acct->popnum});
-%
+<% include( 'svc_acct/basics.html',
+ 'svc_acct' => $svc_acct,
+ 'part_svc' => $part_svc,
+ %gopt,
+ )
+%>
- <TR>
- <TD ALIGN="right">Access number</TD>
- <TD BGCOLOR="#ffffff"><% $svc_acct_pop->text %></TD>
- </TR>
-% }
-% if ($svc_acct->uid ne '') {
-
- <TR>
- <TD ALIGN="right">UID</TD>
- <TD BGCOLOR="#ffffff"><% $svc_acct->uid %></TD>
- </TR>
-% }
-% if ($svc_acct->gid ne '') {
-
- <TR>
- <TD ALIGN="right">GID</TD>
- <TD BGCOLOR="#ffffff"><% $svc_acct->gid %></TD>
- </TR>
-% }
-% if ($svc_acct->finger ne '') {
-
- <TR>
- <TD ALIGN="right">Real Name</TD>
- <TD BGCOLOR="#ffffff"><% $svc_acct->finger %></TD>
- </TR>
-% }
-% if ($svc_acct->dir ne '') {
-
- <TR>
- <TD ALIGN="right">Home directory</TD>
- <TD BGCOLOR="#ffffff"><% $svc_acct->dir %></TD>
- </TR>
-% }
-% if ($svc_acct->shell ne '') {
-
- <TR>
- <TD ALIGN="right">Shell</TD>
- <TD BGCOLOR="#ffffff"><% $svc_acct->shell %></TD>
- </TR>
-% }
-% if ($svc_acct->quota ne '') {
-
- <TR>
- <TD ALIGN="right">Quota</TD>
- <TD BGCOLOR="#ffffff"><% $svc_acct->quota %></TD>
- </TR>
-% }
-% if ($svc_acct->slipip) {
-
- <TR>
- <TD ALIGN="right">IP address</TD>
- <TD BGCOLOR="#ffffff">
- <% ( $svc_acct->slipip eq "0.0.0.0" || $svc_acct->slipip eq '0e0' )
- ? "<I>(Dynamic)</I>"
- : $svc_acct->slipip
- %>
- </TD>
- </TR>
-% }
-% my %ulabel = ( seconds => 'Time',
-% upbytes => 'Upload bytes',
-% downbytes => 'Download bytes',
-% totalbytes => 'Total bytes',
-% );
-% foreach my $uf ( keys %ulabel ) {
-% my $tf = $uf . "_threshold";
-% if ( $svc_acct->$uf ne '' ) {
-% my $v = $uf eq 'seconds'
-% #? (($svc_acct->$uf < 0 ? '-' : ''). duration_exact($svc_acct->$uf) )
-% ? ($svc_acct->$uf < 0 ? '-' : '').
-% int(abs($svc_acct->$uf)/3600). "hr ".
-% sprintf("%02d",(abs($svc_acct->$uf)%3600)/60). "min"
-% : FS::UI::bytecount::display_bytecount($svc_acct->$uf);
- <TR>
- <TD ALIGN="right"><% $ulabel{$uf} %> remaining</TD>
- <TD BGCOLOR="#ffffff"><% $v %></TD>
- </TR>
-
-% }
-% }
-% foreach my $attribute ( grep /^radius_/, $svc_acct->fields ) {
-% $attribute =~ /^radius_(.*)$/;
-% my $pattribute = $FS::raddb::attrib{$1};
-%
-
- <TR>
- <TD ALIGN="right">Radius (reply) <% $pattribute %></TD>
- <TD BGCOLOR="#ffffff"><% $svc_acct->getfield($attribute) %></TD>
- </TR>
-% }
-% foreach my $attribute ( grep /^rc_/, $svc_acct->fields ) {
-% $attribute =~ /^rc_(.*)$/;
-% my $pattribute = $FS::raddb::attrib{$1};
-%
-
- <TR>
- <TD ALIGN="right">Radius (check) <% $pattribute %></TD>
- <TD BGCOLOR="#ffffff"><% $svc_acct->getfield($attribute) %></TD>
- </TR>
-% }
-
-
-<TR>
- <TD ALIGN="right">RADIUS groups</TD>
- <TD BGCOLOR="#ffffff"><% join('<BR>', $svc_acct->radius_groups) %></TD>
-</TR>
-%
-%# Can this be abstracted further? Maybe a library function like
-%# widget('HTML', 'view', $svc_acct) ? It would definitely make UI
-%# style management easier.
-%
-% foreach (sort { $a cmp $b } $svc_acct->virtual_fields) {
-
- <% $svc_acct->pvf($_)->widget('HTML', 'view', $svc_acct->getfield($_)) %>
-% }
-
-
-</TABLE></TD></TR></TABLE>
</FORM>
+<BR>
+
+<% include( 'svc_acct/hosting.html',
+ %gopt,
+ )
+%>
+
+%#remove this? does anybody even use it? it was a misunderstood customer
+%#request IIRC?
+% my $conf = new FS::Conf;
+% if ( $conf->exists('svc_acct-notes') ) {
+% warn 'WARNING: svc_acct-notes deprecated\n';
+<% join("<BR>", $conf->config('svc_acct-notes') ) %>
<BR><BR>
-
-% if ( @svc_www ) {
- Hosting
- <% &ntable("#cccccc") %><TR><TD><% &ntable("#cccccc",2) %>
-% foreach my $svc_www (@svc_www) {
-% my($label, $value) = $svc_www->cust_svc->label;
-% my $link = $p. 'view/svc_www.cgi?'. $svc_www->svcnum;
- <TR>
- <TD BGCOLOR="#ffffff">
- <A HREF="<% $link %>"><% "$label: $value" %></A>
- </TD>
- </TR>
-% }
- </TABLE></TD></TR></TABLE>
- <BR><BR>
% }
-<% join("<BR>", $conf->config('svc_acct-notes') ) %>
-<BR><BR>
+<% include('elements/svc_export_settings.html', $svc_acct) %>
<% joblisting({'svcnum'=>$svcnum}, 1) %>
@@ -345,8 +80,6 @@ Service #<B><% $svcnum %></B>
die "access denied"
unless $FS::CurrentUser::CurrentUser->access_right('View customer services');
-my $conf = new FS::Conf;
-
my $addl_from = ' LEFT JOIN cust_svc USING ( svcnum ) '.
' LEFT JOIN cust_pkg USING ( pkgnum ) '.
' LEFT JOIN cust_main USING ( custnum ) ';
@@ -382,25 +115,27 @@ my $part_svc = qsearchs('part_svc',{'svcpart'=> $cust_svc->svcpart } );
die "Unknown svcpart" unless $part_svc;
my $svc = $part_svc->svc;
-die 'Empty domsvc for svc_acct.svcnum '. $svc_acct->svcnum
- unless $svc_acct->domsvc;
-my $svc_domain = qsearchs('svc_domain', { 'svcnum' => $svc_acct->domsvc } );
-die 'Unknown domain (domsvc '. $svc_acct->domsvc.
- ' for svc_acct.svcnum '. $svc_acct->svcnum. ')'
- unless $svc_domain;
-my $domain = $svc_domain->domain;
+my @part_svc = ();
+if ($FS::CurrentUser::CurrentUser->access_right('Change customer service')) {
+
+ if ( $pkgnum ) {
+ @part_svc = grep { $_->svcdb eq 'svc_acct'
+ && $_->svcpart != $part_svc->svcpart }
+ $cust_pkg->available_part_svc;
+ } else {
+ @part_svc = qsearch('part_svc', {
+ svcdb => 'svc_acct',
+ disabled => '',
+ svcpart => { op=>'!=', value=>$part_svc->svcpart },
+ } );
+ }
-my @svc_www = qsearch({
- 'select' => 'svc_www.*',
- 'table' => 'svc_www',
- 'addl_from' => $addl_from,
- 'hashref' => { 'usersvc' => $svcnum },
- #XXX shit outta luck if you somehow got them linked across agents
- # maybe we should show but not link to them? kinda makes sense...
- # (maybe a specific ACL for this situation???)
- 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql(
- 'null_right' => 'View/link unlinked services'
- ),
-});
+}
+
+my $communigate = scalar($part_svc->part_export('communigate_pro'));
+ # || scalar($part_svc->part_export('communigate_pro_singledomain'));
+
+my %gopt = ( 'communigate' => $communigate,
+ );
</%init>
diff --git a/httemplate/view/svc_acct/basics.html b/httemplate/view/svc_acct/basics.html
new file mode 100644
index 000000000..92b9ad7fe
--- /dev/null
+++ b/httemplate/view/svc_acct/basics.html
@@ -0,0 +1,158 @@
+<% &ntable("#cccccc") %><TR><TD><% &ntable("#cccccc",2) %>
+
+<% include('/view/elements/tr.html', label=>'Service', value=>$part_svc->svc) %>
+<% include('/view/elements/tr.html', label=>'Username', value=>$svc_acct->username) %>
+<% include('/view/elements/tr.html', label=>'Domain', value=>$domain) %>
+
+% if ( $opt{'communigate'} ) {
+ <% include('/view/elements/tr.html', label=>'Aliases', value=>$svc_acct->cgp_aliases) %>
+%}
+
+% if ( $svc_acct->pbxsvc ) {
+ <% include('/view/elements/tr.html', label=>'PBX', value=>$svc_acct->pbx_title) %>
+%}
+
+% my $show_pw = '';
+% my $password = $svc_acct->get_cleartext_password;
+% if ( $password =~ /^\*\w+\* (.*)$/ ) {
+% $password = $1;
+% $show_pw .= '<I>(login disabled)</I> ';
+% }
+% if ( ! $password
+% && $svc_acct->_password_encryption ne 'plain'
+% && $svc_acct->_password
+% )
+% {
+% $show_pw .= '<I>('. uc($svc_acct->_password_encryption). ' encrypted)</I>';
+% } elsif ( $conf->exists('showpasswords') ) {
+% $show_pw .= '<PRE>'. encode_entities($password). '</PRE>';
+% } else {
+% $show_pw .= '<I>(hidden)</I>';
+% }
+% $password = '';
+<% include('/view/elements/tr.html', label=>'Password', value=>$show_pw) %>
+
+
+% if ( $conf->exists('security_phrase') ) {
+ <%include('/view/elements/tr.html', label=>'Security phrase', value=>$svc_acct->sec_phrase)%>
+% }
+
+% if ( $svc_acct->popnum ) {
+% my $svc_acct_pop = qsearchs('svc_acct_pop',{'popnum'=>$svc_acct->popnum});
+ <% include('/view/elements/tr.html', label=>'Access number', value=>$svc_acct_pop->text) %>
+% }
+
+% if ($svc_acct->uid ne '') {
+ <% include('/view/elements/tr.html', label=>'UID', value=>$svc_acct->uid) %>
+% }
+
+% if ($svc_acct->gid ne '') {
+ <% include('/view/elements/tr.html', label=>'GID', value=>$svc_acct->gid) %>
+% }
+
+% if ($svc_acct->finger ne '') {
+ <% include('/view/elements/tr.html', label=>'Real Name', value=>$svc_acct->finger) %>
+% }
+
+% if ($svc_acct->dir ne '') {
+ <% include('/view/elements/tr.html', label=>'Home directory', value=>$svc_acct->dir) %>
+% }
+
+% if ($svc_acct->shell ne '') {
+ <% include('/view/elements/tr.html', label=>'Shell', value=>$svc_acct->shell) %>
+% }
+
+% if ($svc_acct->quota ne '' && ! $opt{'communigate'} ) {
+
+ <% include('/view/elements/tr.html', label=>'Quota', value=>$svc_acct->quota) %>
+
+% } elsif ( $opt{'communigate'} ) {
+
+ <% include('/view/elements/tr.html', label=>'Mailbox type', value=>$svc_acct->cgp_type) %>
+
+ <% include('/view/elements/tr.html', label=>'Enabled services',
+ value=>$svc_acct->cgp_accessmodes ) %>
+
+ <% include('/view/elements/tr.html', label=>'Mail storage limit',
+ value=>$svc_acct->quota ) %>
+
+ <% include('/view/elements/tr.html', label=>'File storage limit',
+ value=>$svc_acct->file_quota ) %>
+
+ <% include('/view/elements/tr.html', label=>'Number of files limit',
+ value=>$svc_acct->file_maxnum ) %>
+
+ <% include('/view/elements/tr.html', label=>'File size limit',
+ value=>$svc_acct->file_maxsize ) %>
+
+ <% include('/view/elements/tr.html', label=>'Message delete method',
+ value=>$svc_acct->cgp_deletemode ) %>
+
+ <% include('/view/elements/tr.html', label=>'On logout remove trash',
+ value=>$svc_acct->cgp_emptytrash ) %>
+
+
+% }
+
+% if ($svc_acct->slipip) {
+ <% include('/view/elements/tr.html',
+ label=>'IP address',
+ value=> ( $svc_acct->slipip eq "0.0.0.0" || $svc_acct->slipip eq '0e0' )
+ ? "<I>(Dynamic)</I>"
+ : $svc_acct->slipip
+ )
+ %>
+% }
+
+<% include('usage.html',
+ 'svc_acct' => $svc_acct,
+ )
+%>
+
+% foreach my $attribute ( grep /^radius_/, $svc_acct->fields ) {
+% $attribute =~ /^radius_(.*)$/;
+% my $pattribute = $FS::raddb::attrib{$1};
+ <% include('/view/elements/tr.html', label=>"Radius (reply) $pattribute",
+ value=>$svc_acct->getfield($attribute)
+ )
+ %>
+% }
+
+% foreach my $attribute ( grep /^rc_/, $svc_acct->fields ) {
+% $attribute =~ /^rc_(.*)$/;
+% my $pattribute = $FS::raddb::attrib{$1};
+ <% include('/view/elements/tr.html', label=>"Radius (check) $pattribute",
+ value=>$svc_acct->getfield($attribute)
+ )
+ %>
+% }
+
+<% include('/view/elements/tr.html', label=>'RADIUS groups',
+ value=>join('<BR>', $svc_acct->radius_groups) ) %>
+
+%# Can this be abstracted further? Maybe a library function like
+%# widget('HTML', 'view', $svc_acct) ? It would definitely make UI
+%# style management easier.
+% foreach (sort { $a cmp $b } $svc_acct->virtual_fields) {
+ <% $svc_acct->pvf($_)->widget('HTML', 'view', $svc_acct->getfield($_)) %>
+% }
+
+</TABLE></TD></TR></TABLE>
+<%init>
+
+my %opt = @_;
+
+my $conf = new FS::Conf;
+
+my $svc_acct = $opt{'svc_acct'};
+my $part_svc = $opt{'part_svc'};
+
+die 'Empty domsvc for svc_acct.svcnum '. $svc_acct->svcnum
+ unless $svc_acct->domsvc;
+my $svc_domain = qsearchs('svc_domain', { 'svcnum' => $svc_acct->domsvc } );
+die 'Unknown domain (domsvc '. $svc_acct->domsvc.
+ ' for svc_acct.svcnum '. $svc_acct->svcnum. ')'
+ unless $svc_domain;
+my $domain = $svc_domain->domain;
+
+</%init>
diff --git a/httemplate/view/svc_acct/change_svc.html b/httemplate/view/svc_acct/change_svc.html
new file mode 100644
index 000000000..33d44a713
--- /dev/null
+++ b/httemplate/view/svc_acct/change_svc.html
@@ -0,0 +1,21 @@
+% if ( @part_svc || $opt{'showall'} ) {
+
+| <SELECT NAME="svcpart" onChange="enable_change()">
+ <OPTION VALUE="">Change service</OPTION>
+ <OPTION VALUE="">--------------</OPTION>
+% foreach my $opt_part_svc ( @part_svc ) {
+
+ <OPTION VALUE="<% $opt_part_svc->svcpart %>"><% $opt_part_svc->svc %></OPTION>
+% }
+
+ </SELECT>
+ <INPUT NAME="submit" TYPE="submit" VALUE="Change" disabled>
+
+% }
+
+<%init>
+
+my %opt = @_;
+my @part_svc = @{ $opt{'part_svc'} };
+
+</%init>
diff --git a/httemplate/view/svc_acct/change_svc_form.html b/httemplate/view/svc_acct/change_svc_form.html
new file mode 100644
index 000000000..4f10922ba
--- /dev/null
+++ b/httemplate/view/svc_acct/change_svc_form.html
@@ -0,0 +1,23 @@
+% if ( @part_svc || $opt{'showall'} ) {
+ <SCRIPT TYPE="text/javascript">
+ function enable_change () {
+ if ( document.OneTrueForm.svcpart.selectedIndex > 1 ) {
+ document.OneTrueForm.submit.disabled = false;
+ } else {
+ document.OneTrueForm.submit.disabled = true;
+ }
+ }
+ </SCRIPT>
+
+ <FORM NAME="OneTrueForm" ACTION="<%$p%>edit/process/cust_svc.cgi">
+ <INPUT TYPE="hidden" NAME="svcnum" VALUE="<% $svcnum %>">
+ <INPUT TYPE="hidden" NAME="pkgnum" VALUE="<% $pkgnum %>">
+% }
+<%init>
+
+my %opt = @_;
+my @part_svc = @{ $opt{'part_svc'} };
+my $svcnum = $opt{'svcnum'};
+my $pkgnum = $opt{'pkgnum'};
+
+</%init>
diff --git a/httemplate/view/svc_acct/hosting.html b/httemplate/view/svc_acct/hosting.html
new file mode 100644
index 000000000..1d83603b7
--- /dev/null
+++ b/httemplate/view/svc_acct/hosting.html
@@ -0,0 +1,38 @@
+% if ( @svc_www || $opt{'showall'} ) {
+ Hosting
+ <% &ntable("#cccccc") %><TR><TD><% &ntable("#cccccc",2) %>
+% foreach my $svc_www (@svc_www) {
+% my($label, $value) = $svc_www->cust_svc->label;
+% my $link = $p. 'view/svc_www.cgi?'. $svc_www->svcnum;
+ <TR>
+ <TD BGCOLOR="#ffffff">
+ <A HREF="<% $link %>"><% "$label: $value" %></A>
+ </TD>
+ </TR>
+% }
+ </TABLE></TD></TR></TABLE>
+ <BR><BR>
+% }
+<%init>
+
+my %opt = @_;
+
+#false laziness w/view_svc_acct.cgi and a zillion other places
+my $addl_from = ' LEFT JOIN cust_svc USING ( svcnum ) '.
+ ' LEFT JOIN cust_pkg USING ( pkgnum ) '.
+ ' LEFT JOIN cust_main USING ( custnum ) ';
+
+my @svc_www = qsearch({
+ 'select' => 'svc_www.*',
+ 'table' => 'svc_www',
+ 'addl_from' => $addl_from,
+ 'hashref' => { 'usersvc' => $opt{'svcnum'} },
+ #XXX shit outta luck if you somehow got them linked across agents
+ # maybe we should show but not link to them? kinda makes sense...
+ # (maybe a specific ACL for this situation???)
+ 'extra_sql' => ' AND '. $FS::CurrentUser::CurrentUser->agentnums_sql(
+ 'null_right' => 'View/link unlinked services'
+ ),
+});
+
+</%init>
diff --git a/httemplate/view/svc_acct/radius_usage.html b/httemplate/view/svc_acct/radius_usage.html
new file mode 100644
index 000000000..e2253a34a
--- /dev/null
+++ b/httemplate/view/svc_acct/radius_usage.html
@@ -0,0 +1,77 @@
+% if ( $part_svc->part_export_usage ) {
+%
+% my $last_bill;
+% my %plandata;
+% if ( $cust_pkg ) {
+% #false laziness w/httemplate/edit/part_pkg... this stuff doesn't really
+% #belong in plan data
+% %plandata = map { /^(\w+)=(.*)$/; ( $1 => $2 ); }
+% split("\n", $cust_pkg->part_pkg->plandata );
+%
+% $last_bill = $cust_pkg->last_bill;
+% } else {
+% $last_bill = 0;
+% %plandata = ();
+% }
+%
+% my $seconds = $svc_acct->seconds_since_sqlradacct( $last_bill, time );
+% my $hour = int($seconds/3600);
+% my $min = int( ($seconds%3600) / 60 );
+% my $sec = $seconds%60;
+%
+% my $input = $svc_acct->attribute_since_sqlradacct(
+% $last_bill, time, 'AcctInputOctets'
+% ) / 1048576;
+% my $output = $svc_acct->attribute_since_sqlradacct(
+% $last_bill, time, 'AcctOutputOctets'
+% ) / 1048576;
+%
+%
+
+
+ RADIUS session information<BR>
+ <% ntable('#cccccc',2) %>
+ <TR><TD BGCOLOR="#ffffff">
+% if ( $seconds ) {
+
+ Online <B><% $hour %></B>h <B><% $min %></B>m <B><% $sec %></B>s
+% } else {
+
+ Has not logged on
+% }
+% if ( $cust_pkg ) {
+
+ since last bill (<% time2str('%a %b %o %Y', $last_bill) %>)
+% if ( length($plandata{recur_included_hours}) ) {
+
+ - <% $plandata{recur_included_hours} %> total hours in plan
+% }
+
+ <BR>
+% } else {
+
+ (no billing cycle available for unaudited account)<BR>
+% }
+
+
+ Upload: <B><% sprintf("%.3f", $input) %></B> megabytes<BR>
+ Download: <B><% sprintf("%.3f", $output) %></B> megabytes<BR>
+ Last Login: <B><% $svc_acct->last_login_text %></B><BR>
+% my $href = qq!<A HREF="${p}search/sqlradius.cgi?svcnum=!. $svc_acct->svcnum;
+
+ View session detail:
+ <% $href %>;begin=<% $last_bill %>">this billing cycle</A>
+ | <% $href %>;begin=<% time-15552000 %>">past six months</A>
+ | <% $href %>">all sessions</A>
+
+ </TD></TR></TABLE><BR>
+% }
+<%init>
+
+my %opt = @_;
+
+my $svc_acct = $opt{'svc_acct'};
+my $part_svc = $opt{'part_svc'};
+my $cust_pkg = $opt{'cust_pkg'};
+
+</%init>
diff --git a/httemplate/view/svc_acct/usage.html b/httemplate/view/svc_acct/usage.html
new file mode 100644
index 000000000..9758d8332
--- /dev/null
+++ b/httemplate/view/svc_acct/usage.html
@@ -0,0 +1,27 @@
+% my %ulabel = ( seconds => 'Time',
+% upbytes => 'Upload bytes',
+% downbytes => 'Download bytes',
+% totalbytes => 'Total bytes',
+% );
+% foreach my $uf ( keys %ulabel ) {
+% my $tf = $uf . "_threshold";
+% if ( $svc_acct->$uf ne '' ) {
+% my $v = $uf eq 'seconds'
+% #? (($svc_acct->$uf < 0 ? '-' : ''). duration_exact($svc_acct->$uf) )
+% ? ($svc_acct->$uf < 0 ? '-' : '').
+% int(abs($svc_acct->$uf)/3600). "hr ".
+% sprintf("%02d",(abs($svc_acct->$uf)%3600)/60). "min"
+% : FS::UI::bytecount::display_bytecount($svc_acct->$uf);
+ <TR>
+ <TD ALIGN="right"><% $ulabel{$uf} %> remaining</TD>
+ <TD BGCOLOR="#ffffff"><% $v %></TD>
+ </TR>
+
+% }
+% }
+<%init>
+
+my %opt = @_;
+my $svc_acct = $opt{'svc_acct'};
+
+</%init>
diff --git a/httemplate/view/svc_domain.cgi b/httemplate/view/svc_domain.cgi
index a9fc775ee..3938a3406 100755
--- a/httemplate/view/svc_domain.cgi
+++ b/httemplate/view/svc_domain.cgi
@@ -1,136 +1,40 @@
-<% include("/elements/header.html",'Domain View', menubar(
- ( ( $pkgnum || $custnum )
- ? ( "View this customer (#$display_custnum)" => "${p}view/cust_main.cgi?$custnum",
- )
- : ( "Delete this (unaudited) domain" =>
- "javascript:areyousure('${p}misc/cancel-unaudited.cgi?$svcnum', 'Delete $domain and all records?' )" )
- )
-)) %>
+% if ( $custnum ) {
-<% include('/elements/error.html') %>
-
-Service #<% $svcnum %>
-<BR>Service: <B><% $part_svc->svc %></B>
-<BR>Domain name: <B><% $domain %></B>
-% if ($export) {
-<BR>Status: <B><% $status %></B>
-% if ( $FS::CurrentUser::CurrentUser->access_right('Manage domain registration') ) {
-% if ( defined($ops{'register'}) ) {
- <A HREF="<% ${p} %>edit/process/domreg.cgi?op=register&svcnum=<% $svcnum %>">Register at <% $registrar->{'name'} %></A>&nbsp;
-% }
-% if ( defined($ops{'transfer'}) ) {
- <A HREF="<% ${p} %>edit/process/domreg.cgi?op=transfer&svcnum=<% $svcnum %>">Transfer to <% $registrar->{'name'} %></A>&nbsp;
-% }
-% if ( defined($ops{'renew'}) ) {
- <A HREF="<% ${p} %>edit/process/domreg.cgi?op=renew&svcnum=<% $svcnum %>&period=1">Renew at <% $registrar->{'name'} %></A>&nbsp;
-% }
-% if ( defined($ops{'revoke'}) ) {
- <A HREF="<% ${p} %>edit/process/domreg.cgi?op=revoke&svcnum=<% $svcnum %>">Revoke</A>
-% }
-% }
-% }
+%# <% include("/elements/header.html","View $svcdomain") %>
+ <% include("/elements/header.html","View domain") %>
+ <% include( '/elements/small_custview.html', $custnum, '', 1,
+ "${p}view/cust_main.cgi") %>
+ <BR>
-% if ( $FS::CurrentUser::CurrentUser->access_right('Edit domain catchall') ) {
- <BR>Catch all email <A HREF="<% ${p} %>misc/catchall.cgi?<% $svcnum %>">(change)</A>:
% } else {
- <BR>Catch all email:
-% }
-<% $email ? "<B>$email</B>" : "<I>(none)<I>" %>
-<BR><BR><A HREF="<% ${p} %>misc/whois.cgi?custnum=<%$custnum%>;svcnum=<%$svcnum%>;domain=<%$domain%>">View whois information.</A>
-<BR><BR>
-<SCRIPT>
- function areyousure(href, message) {
- if ( confirm(message) == true )
- window.location.href = href;
- }
- function slave_areyousure() {
- return confirm("Remove all records and slave from " + document.SlaveForm.recdata.value + "?");
- }
-</SCRIPT>
-
-% my @records; if ( @records = $svc_domain->domain_record ) {
-
- <% include('/elements/table-grid.html') %>
-
-% my $bgcolor1 = '#eeeeee';
-% my $bgcolor2 = '#ffffff';
-% my $bgcolor = $bgcolor2;
-
- <tr>
- <th CLASS="grid" BGCOLOR="#cccccc">Zone</th>
- <th CLASS="grid" BGCOLOR="#cccccc">Type</th>
- <th CLASS="grid" BGCOLOR="#cccccc">Data</th>
- </tr>
-
-% foreach my $domain_record ( @records ) {
-% my $type = $domain_record->rectype eq '_mstr'
-% ? "(slave)"
-% : $domain_record->recaf. ' '. $domain_record->rectype;
-
-
- <tr>
- <td CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $domain_record->reczone %></td>
- <td CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $type %></td>
- <td CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $domain_record->recdata %>
-
-% unless ( $domain_record->rectype eq 'SOA'
-% || ! $FS::CurrentUser::CurrentUser->access_right('Edit domain nameservice')
-% ) {
-% ( my $recdata = $domain_record->recdata ) =~ s/"/\\'\\'/g;
- (<A HREF="javascript:areyousure('<%$p%>misc/delete-domain_record.cgi?<%$domain_record->recnum%>', 'Delete \'<% $domain_record->reczone %> <% $type %> <% $recdata %>\' ?' )">delete</A>)
-% }
- </td>
- </tr>
-
-
-% if ( $bgcolor eq $bgcolor1 ) {
-% $bgcolor = $bgcolor2;
-% } else {
-% $bgcolor = $bgcolor1;
-% }
-
-% }
-
- </table>
-% }
-
-% if ( $FS::CurrentUser::CurrentUser->access_right('Edit domain nameservice') ) {
- <BR>
- <FORM METHOD="POST" ACTION="<%$p%>edit/process/domain_record.cgi">
- <INPUT TYPE="hidden" NAME="svcnum" VALUE="<%$svcnum%>">
- <INPUT TYPE="text" NAME="reczone">
- <INPUT TYPE="hidden" NAME="recaf" VALUE="IN"> IN
- <SELECT NAME="rectype">
-% foreach (qw( A NS CNAME MX PTR TXT) ) {
- <OPTION VALUE="<%$_%>"><%$_%></OPTION>
-% }
- </SELECT>
- <INPUT TYPE="text" NAME="recdata">
- <INPUT TYPE="submit" VALUE="Add record">
- </FORM>
-
- <BR><BR>
- or
- <BR><BR>
-
- <FORM NAME="SlaveForm" METHOD="POST" ACTION="<%$p%>edit/process/domain_record.cgi">
- <INPUT TYPE="hidden" NAME="svcnum" VALUE="<%$svcnum%>">
-% if ( @records ) {
- Delete all records and
-% }
- Slave from nameserver IP
- <INPUT TYPE="hidden" NAME="svcnum" VALUE="<%$svcnum%>">
- <INPUT TYPE="hidden" NAME="reczone" VALUE="@">
- <INPUT TYPE="hidden" NAME="recaf" VALUE="IN">
- <INPUT TYPE="hidden" NAME="rectype" VALUE="_mstr">
- <INPUT TYPE="text" NAME="recdata">
- <INPUT TYPE="submit" VALUE="Slave domain" onClick="return slave_areyousure()">
- </FORM>
+ <% include("/elements/header.html",'View domain', menubar(
+ "Cancel this (unaudited) domain" =>
+ "javascript:areyousure('${p}misc/cancel-unaudited.cgi?$svcnum', 'Delete $domain and all records?')",
+ ))
+ %>
% }
-<BR><BR>
+<% include('/elements/error.html') %>
+
+<% include('svc_domain/basics.html', $svc_domain,
+ 'part_svc' => $part_svc,
+ 'custnum' => $custnum,
+ )
+%>
+<BR>
+
+<% include('svc_domain/acct_defaults.html', $svc_domain,
+ 'part_svc' => $part_svc,
+ )
+%>
+<BR>
+
+<% include('svc_domain/dns.html', $svc_domain ) %>
+<BR>
+
+<% include('elements/svc_export_settings.html', $svc_domain) %>
<% joblisting({'svcnum'=>$svcnum}, 1) %>
@@ -140,6 +44,8 @@ Service #<% $svcnum %>
die "access denied"
unless $FS::CurrentUser::CurrentUser->access_right('View customer services');
+my $conf = new FS::Conf;
+
my($query) = $cgi->keywords;
$query =~ /^(\d+)$/;
my $svcnum = $1;
@@ -171,46 +77,6 @@ if ($pkgnum) {
my $part_svc = qsearchs('part_svc',{'svcpart'=> $cust_svc->svcpart } );
die "Unknown svcpart" unless $part_svc;
-my $email = '';
-if ($svc_domain->catchall) {
- my $svc_acct = qsearchs('svc_acct',{'svcnum'=> $svc_domain->catchall } );
- die "Unknown svcpart" unless $svc_acct;
- $email = $svc_acct->email;
-}
-
my $domain = $svc_domain->domain;
-my $status = 'Unknown';
-my %ops = ();
-
-my @exports = $part_svc->part_export();
-
-my $registrar;
-my $export;
-
-# Find the first export that does domain registration
-foreach (@exports) {
- $export = $_ if $_->can('registrar');
-}
-# If we have a domain registration export, get the registrar object
-if ($export) {
- $registrar = $export->registrar;
- my $domstat = $export->get_status( $svc_domain );
- if (defined($domstat->{'message'})) {
- $status = $domstat->{'message'};
- } elsif (defined($domstat->{'unregistered'})) {
- $status = 'Not registered';
- $ops{'register'} = "Register";
- } elsif (defined($domstat->{'status'})) {
- $status = $domstat->{'status'} . ' ' . $domstat->{'contact_email'} . ' ' . $domstat->{'last_update_time'};
- } elsif (defined($domstat->{'expdate'})) {
- $status = "Expires " . $domstat->{'expdate'};
- $ops{'renew'} = "Renew";
- $ops{'revoke'} = "Revoke";
- } else {
- $status = $domstat->{'reason'};
- $ops{'transfer'} = "Transfer";
- }
-}
-
</%init>
diff --git a/httemplate/view/svc_domain/acct_defaults.html b/httemplate/view/svc_domain/acct_defaults.html
new file mode 100644
index 000000000..0c072bff5
--- /dev/null
+++ b/httemplate/view/svc_domain/acct_defaults.html
@@ -0,0 +1,71 @@
+% if ( $communigate ) {
+
+ Account defaults
+ <% &ntable("#cccccc") %><TR><TD><% &ntable("#cccccc",2) %>
+
+ <% include('/view/elements/tr.html',
+ label=>'Password modification',
+ value=>$svc_domain->acct_def_password_selfchange ? 'YES' : 'NO',
+ )
+ %>
+ <% include('/view/elements/tr.html',
+ label=>'Password recovery',
+ value=>$svc_domain->acct_def_password_recover ? 'YES' : 'NO',
+ )
+ %>
+
+ <% include('/view/elements/tr.html',
+ label=>'Enabled services',
+ value=>$svc_domain->acct_def_cgp_accessmodes,
+ )
+ %>
+
+ <% include('/view/elements/tr.html',
+ label=>'Mail storage limit',
+ value=>$svc_domain->acct_def_quota,
+ )
+ %>
+
+ <% include('/view/elements/tr.html',
+ label=>'File storage limit',
+ value=>$svc_domain->acct_def_file_quota,
+ )
+ %>
+
+ <% include('/view/elements/tr.html',
+ label=>'Files limt',
+ value=>$svc_domain->acct_def_file_maxnum,
+ )
+ %>
+
+ <% include('/view/elements/tr.html',
+ label=>'File size limit',
+ value=>$svc_domain->acct_def_file_maxsize,
+ )
+ %>
+
+ <% include('/view/elements/tr.html',
+ label=>'Message delete method',
+ value=>$svc_domain->acct_def_cgp_deletemode,
+ )
+ %>
+
+ <% include('/view/elements/tr.html',
+ label=>'On logout remove trash',
+ value=>$svc_domain->acct_def_cgp_emptytrash,
+ )
+ %>
+
+ </TABLE></TD></TR></TABLE>
+
+% }
+<%init>
+
+my($svc_domain, %opt) = @_;
+
+my $part_svc = $opt{'part_svc'};
+
+my $communigate = scalar($part_svc->part_export('communigate_pro'));
+ # || scalar($part_svc->part_export('communigate_pro_singledomain'));
+
+</%init>
diff --git a/httemplate/view/svc_domain/basics.html b/httemplate/view/svc_domain/basics.html
new file mode 100644
index 000000000..db4fac150
--- /dev/null
+++ b/httemplate/view/svc_domain/basics.html
@@ -0,0 +1,134 @@
+Service #<B><% $svcnum %></B>
+% #if ( $conf->exists('svc_domain-edit_domain') ) {
+ | <A HREF="<%$p%>edit/svc_domain.cgi?<%$svcnum%>">Edit this domain</A>
+% #}
+
+<% &ntable("#cccccc") %><TR><TD><% &ntable("#cccccc",2) %>
+
+<TR>
+ <TD ALIGN="right">Service</TD>
+ <TD BGCOLOR="#ffffff"><% $part_svc->svc %></TD>
+</TR>
+
+<TR>
+ <TD ALIGN="right">Domain</TD>
+ <TD BGCOLOR="#ffffff">
+ <B><% $domain %></B>
+ <A HREF="<% ${p} %>misc/whois.cgi?custnum=<%$custnum%>;svcnum=<%$svcnum%>;domain=<%$domain%>">(view whois information)</A>
+ </TD>
+</TR>
+
+% if ($export) {
+ <TR>
+ <TD ALIGN="right">Registration status</TD>
+ <TD BGCOLOR="#ffffff"><B><% $status %></B>
+
+% if ( $FS::CurrentUser::CurrentUser->access_right('Manage domain registration') ) {
+% if ( defined($ops{'register'}) ) {
+ <A HREF="<% ${p} %>edit/process/domreg.cgi?op=register&svcnum=<% $svcnum %>">Register at <% $registrar->{'name'} %></A>&nbsp;
+% }
+% if ( defined($ops{'transfer'}) ) {
+ <A HREF="<% ${p} %>edit/process/domreg.cgi?op=transfer&svcnum=<% $svcnum %>">Transfer to <% $registrar->{'name'} %></A>&nbsp;
+% }
+% if ( defined($ops{'renew'}) ) {
+ <A HREF="<% ${p} %>edit/process/domreg.cgi?op=renew&svcnum=<% $svcnum %>&period=1">Renew at <% $registrar->{'name'} %></A>&nbsp;
+% }
+% if ( defined($ops{'revoke'}) ) {
+ <A HREF="<% ${p} %>edit/process/domreg.cgi?op=revoke&svcnum=<% $svcnum %>">Revoke</A>
+% }
+% }
+
+ </TD>
+ </TR>
+% }
+
+% if ( $communigate ) {
+
+ <TR>
+ <TD ALIGN="right">Administrator domain</TD>
+ <TD BGCOLOR="#ffffff">
+% if ( $svc_domain->parent_svcnum ) {
+% #XXX agent-virt aware the link
+ <A HREF="svc_domain.cgi?<% $svc_domain->parent_svcnum %>"><% $svc_domain->parent_svc_x->domain %></A>
+% } else {
+ <I>(none)</I>
+% }
+ </TD>
+ </TR>
+
+ <TR>
+ <TD ALIGN="right">Aliases</TD>
+ <TD BGCOLOR="#ffffff"><% $svc_domain->cgp_aliases %></TD>
+ </TR>
+
+% }
+
+% if ( $communigate && $svc_domain->max_accounts ) {
+ <TR>
+ <TD ALIGN="right">Maximum number of Accounts</TD>
+ <TD BGCOLOR="#ffffff"><% $svc_domain->max_accounts %></TD>
+ </TR>
+% }
+
+<TR>
+ <TD ALIGN="right">Catch all email</TD>
+ <TD BGCOLOR="#ffffff"><% $email ? "<B>$email</B>" : '<I>(none)</I>' %>
+% if ( $FS::CurrentUser::CurrentUser->access_right('Edit domain catchall') ) {
+ <A HREF="<% ${p} %>misc/catchall.cgi?<% $svcnum %>">(change)</A>
+% }
+ </TD>
+</TR>
+
+<TR>
+ <TD ALIGN="right">Enabled services</TD>
+ <TD BGCOLOR="#ffffff"><% $svc_domain->cgp_accessmodes %></TD>
+</TR>
+
+</TABLE></TD></TR></TABLE>
+
+<%init>
+
+my($svc_domain, %opt) = @_;
+my $svcnum = $svc_domain->svcnum;
+my $domain = $svc_domain->domain;
+my $custnum = $opt{'custnum'};
+my $part_svc = $opt{'part_svc'};
+
+my $communigate = scalar($part_svc->part_export('communigate_pro'));
+ # || scalar($part_svc->part_export('communigate_pro_singledomain'));
+
+my $email = '';
+if ($svc_domain->catchall) {
+ my $svc_acct = qsearchs('svc_acct',{'svcnum'=> $svc_domain->catchall } );
+ die "Unknown svcpart" unless $svc_acct;
+ $email = $svc_acct->email;
+}
+
+# Find the first export that does domain registration
+my @exports = grep $_->can('registrar'), $part_svc->part_export;
+my $export = $exports[0];
+# If we have a domain registration export, get the registrar object
+my $registrar;
+my $status = 'Unknown';
+my %ops = ();
+if ($export) {
+ $registrar = $export->registrar;
+ my $domstat = $export->get_status( $svc_domain );
+ if (defined($domstat->{'message'})) {
+ $status = $domstat->{'message'};
+ } elsif (defined($domstat->{'unregistered'})) {
+ $status = 'Not registered';
+ $ops{'register'} = "Register";
+ } elsif (defined($domstat->{'status'})) {
+ $status = $domstat->{'status'} . ' ' . $domstat->{'contact_email'} . ' ' . $domstat->{'last_update_time'};
+ } elsif (defined($domstat->{'expdate'})) {
+ $status = "Expires " . $domstat->{'expdate'};
+ $ops{'renew'} = "Renew";
+ $ops{'revoke'} = "Revoke";
+ } else {
+ $status = $domstat->{'reason'};
+ $ops{'transfer'} = "Transfer";
+ }
+}
+
+</%init>
diff --git a/httemplate/view/svc_domain/dns.html b/httemplate/view/svc_domain/dns.html
new file mode 100644
index 000000000..f6f8c71c7
--- /dev/null
+++ b/httemplate/view/svc_domain/dns.html
@@ -0,0 +1,94 @@
+<SCRIPT>
+ function areyousure(href, message) {
+ if ( confirm(message) == true )
+ window.location.href = href;
+ }
+ function slave_areyousure() {
+ return confirm("Remove all records and slave from " + document.SlaveForm.recdata.value + "?");
+ }
+</SCRIPT>
+
+DNS records
+% my @records; if ( @records = $svc_domain->domain_record ) {
+
+ <% include('/elements/table-grid.html') %>
+
+% my $bgcolor1 = '#eeeeee';
+% my $bgcolor2 = '#ffffff';
+% my $bgcolor = $bgcolor2;
+
+ <tr>
+ <th CLASS="grid" BGCOLOR="#cccccc">Zone</th>
+ <th CLASS="grid" BGCOLOR="#cccccc">Type</th>
+ <th CLASS="grid" BGCOLOR="#cccccc">Data</th>
+ </tr>
+
+% foreach my $domain_record ( @records ) {
+% my $type = $domain_record->rectype eq '_mstr'
+% ? "(slave)"
+% : $domain_record->recaf. ' '. $domain_record->rectype;
+
+
+ <tr>
+ <td CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $domain_record->reczone %></td>
+ <td CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $type %></td>
+ <td CLASS="grid" BGCOLOR="<% $bgcolor %>"><% $domain_record->recdata %>
+
+% unless ( $domain_record->rectype eq 'SOA'
+% || ! $FS::CurrentUser::CurrentUser->access_right('Edit domain nameservice')
+% ) {
+% ( my $recdata = $domain_record->recdata ) =~ s/"/\\'\\'/g;
+ (<A HREF="javascript:areyousure('<%$p%>misc/delete-domain_record.cgi?<%$domain_record->recnum%>', 'Delete \'<% $domain_record->reczone %> <% $type %> <% $recdata %>\' ?' )">delete</A>)
+% }
+ </td>
+ </tr>
+
+
+% if ( $bgcolor eq $bgcolor1 ) {
+% $bgcolor = $bgcolor2;
+% } else {
+% $bgcolor = $bgcolor1;
+% }
+
+% }
+
+ </table>
+% }
+
+% if ( $FS::CurrentUser::CurrentUser->access_right('Edit domain nameservice') ) {
+ <FORM METHOD="POST" ACTION="<%$p%>edit/process/domain_record.cgi">
+ <INPUT TYPE="hidden" NAME="svcnum" VALUE="<%$svcnum%>">
+ <INPUT TYPE="text" NAME="reczone">
+ <INPUT TYPE="hidden" NAME="recaf" VALUE="IN"> IN
+ <SELECT NAME="rectype">
+% foreach (qw( A NS CNAME MX PTR TXT) ) {
+ <OPTION VALUE="<%$_%>"><%$_%></OPTION>
+% }
+ </SELECT>
+ <INPUT TYPE="text" NAME="recdata">
+ <INPUT TYPE="submit" VALUE="Add record">
+ </FORM>
+
+ <FORM NAME="SlaveForm" METHOD="POST" ACTION="<%$p%>edit/process/domain_record.cgi">
+ <INPUT TYPE="hidden" NAME="svcnum" VALUE="<%$svcnum%>">
+% if ( @records ) {
+ Delete all records and
+% }
+ Or slave from nameserver IP
+ <INPUT TYPE="hidden" NAME="svcnum" VALUE="<%$svcnum%>">
+ <INPUT TYPE="hidden" NAME="reczone" VALUE="@">
+ <INPUT TYPE="hidden" NAME="recaf" VALUE="IN">
+ <INPUT TYPE="hidden" NAME="rectype" VALUE="_mstr">
+ <INPUT TYPE="text" NAME="recdata">
+ <INPUT TYPE="submit" VALUE="Slave domain" onClick="return slave_areyousure()">
+ </FORM>
+
+% }
+
+<%init>
+
+my($svc_domain, %opt) = @_;
+my $svcnum = $svc_domain->svcnum;
+
+</%init>
+
diff --git a/httemplate/view/svc_forward.cgi b/httemplate/view/svc_forward.cgi
index 0847a5e65..43d8a4e8b 100755
--- a/httemplate/view/svc_forward.cgi
+++ b/httemplate/view/svc_forward.cgi
@@ -1,12 +1,26 @@
-<% include('/elements/header.html', 'Mail Forward View', menubar(
- ( ( $pkgnum || $custnum )
- ? ( "View this customer (#$display_custnum)" => "${p}view/cust_main.cgi?$custnum",
- )
- : ( "Cancel this (unaudited) mail forward" =>
- "${p}misc/cancel-unaudited.cgi?$svcnum" )
- )
-))
-%>
+% if ( $custnum ) {
+
+ <% include("/elements/header.html","View mail forward") %>
+ <% include( '/elements/small_custview.html', $custnum, '', 1,
+ "${p}view/cust_main.cgi") %>
+ <BR>
+
+% } else {
+
+ <% include("/elements/header.html",'View mail forward', menubar(
+ "Cancel this (unaudited) mail forward" =>
+ "javascript:areyousure('${p}misc/cancel-unaudited.cgi?$svcnum')",
+ ))
+ %>
+
+ <SCRIPT>
+ function areyousure(href) {
+ if (confirm("Permanently delete this mail forward?") == true)
+ window.location.href = href;
+ }
+ </SCRIPT>
+
+% }
<A HREF="<% $p %>edit/svc_forward.cgi?<% $svcnum %>">Edit this information</A>
diff --git a/httemplate/view/svc_mailinglist.cgi b/httemplate/view/svc_mailinglist.cgi
new file mode 100644
index 000000000..f646a417d
--- /dev/null
+++ b/httemplate/view/svc_mailinglist.cgi
@@ -0,0 +1,71 @@
+<% include('elements/svc_Common.html',
+ 'table' => 'svc_mailinglist',
+ %opt,
+ )
+%>
+<%init>
+
+my %opt = ();
+
+my $info = FS::svc_mailinglist->table_info;
+
+$opt{'name'} = $info->{'name'};
+
+my $fields = $info->{'fields'};
+my %labels = map { $_ => ( ref($fields->{$_})
+ ? $fields->{$_}{'label'}
+ : $fields->{$_}
+ );
+ }
+ keys %$fields;
+
+#$opt{'fields'} = [ keys %$fields ];
+$opt{'fields'} = [
+ 'username',
+ 'domain',
+ 'listname',
+ 'reply_to',
+ 'remove_from',
+ 'reject_auto',
+ 'remove_to_and_cc',
+];
+
+$opt{'labels'} = \%labels;
+
+$opt{'html_foot'} = sub {
+ my $svc_mailinglist = shift;
+ my $listnum = $svc_mailinglist->listnum;
+
+ my $sql = 'SELECT COUNT(*) FROM mailinglistmember WHERE listnum = ?';
+ my $sth = dbh->prepare($sql) or die dbh->errstr;
+ $sth->execute($listnum) or die $sth->errstr;
+ my $num = $sth->fetchrow_arrayref->[0];
+
+ my $add_url = $p."edit/mailinglistmember.html?listnum=$listnum";
+
+ my $add_link = include('/elements/init_overlib.html').
+ include('/elements/popup_link.html',
+ 'action' => $add_url,
+ 'label' => 'add',
+ 'actionlabel' => 'Add list member',
+ 'width' => 392,
+ 'height' => 192,
+ );
+
+ ntable('#cccccc').'<TR><TD>'.ntable('#cccccc',2). qq[
+ <TR>
+ <TD>List members</TD>
+ <TD BGCOLOR="#ffffff">
+ $num members
+ ( <A HREF="${p}search/mailinglistmember.html?listnum=$listnum">view</A>
+ | $add_link )
+ </TD>
+ </TR>
+ </TABLE></TD></TR></TABLE>
+
+ <BR><BR>
+ ]. include('svc_export_settings.html', $svc_mailinglist);
+
+};
+
+</%init>
diff --git a/httemplate/view/svc_phone.cgi b/httemplate/view/svc_phone.cgi
index c5fce62d9..75591c747 100644
--- a/httemplate/view/svc_phone.cgi
+++ b/httemplate/view/svc_phone.cgi
@@ -1,15 +1,11 @@
<% include('elements/svc_Common.html',
'table' => 'svc_phone',
- 'fields' => [qw(
- countrycode
- phonenum
- sip_password
- pin
- phone_name
- )],
+ 'fields' => \@fields,
'labels' => {
'countrycode' => 'Country code',
'phonenum' => 'Phone number',
+ 'domain' => 'Domain',
+ 'pbx_title' => 'PBX',
'sip_password' => 'SIP password',
'pin' => 'PIN',
'phone_name' => 'Name',
@@ -19,10 +15,36 @@
%>
<%init>
+my $conf = new FS::Conf;
+my $countrydefault = $conf->config('countrydefault') || 'US';
+
+my @fields = qw( countrycode phonenum );
+push @fields, 'domain' if $conf->exists('svc_phone-domain');
+push @fields, qw( pbx_title sip_password pin phone_name );
+
my $html_foot = sub {
my $svc_phone = shift;
###
+ # E911 Info
+ ###
+
+ my $e911 =
+ 'E911 Information'.
+ &ntable("#cccccc"). '<TR><TD>'. ntable("#cccccc",2).
+ '<TR><TD>Location</TD>'.
+ '<TD BGCOLOR="#FFFFFF">'.
+ $svc_phone->location_label( 'join_string' => '<BR>',
+ 'double_space' => ' &nbsp; ',
+ 'escape_function' => \&encode_entities,
+ 'countrydefault' => $countrydefault,
+ ).
+ '</TD></TR>'.
+ '</TABLE></TD></TR></TABLE>'.
+ '<BR>'
+ ;
+
+ ###
# Devices
###
@@ -56,6 +78,7 @@ my $html_foot = sub {
'<TH CLASS="grid" BGCOLOR="#cccccc">Type</TH>'.
'<TH CLASS="grid" BGCOLOR="#cccccc">MAC Addr</TH>'.
'<TH CLASS="grid" BGCOLOR="#cccccc"></TH>'.
+ '<TH CLASS="grid" BGCOLOR="#cccccc"></TH>'.
'</TR>';
my $bgcolor1 = '#eeeeee';
my $bgcolor2 = '#ffffff';
@@ -71,10 +94,12 @@ my $html_foot = sub {
my $td = qq(<TD CLASS="grid" BGCOLOR="$bgcolor">);
my $devicenum = $phone_device->devicenum;
+ my $export_links = join( '<BR>', @{ $phone_device->export_links } );
$devices .= '<TR>'.
$td. $phone_device->part_device->devicename. '</TD>'.
$td. $phone_device->mac_addr. '</TD>'.
+ $td. $export_links. '</TD>'.
"$td( ".
qq(<A HREF="${p}edit/phone_device.html?$devicenum">edit</A> | ).
qq(<A HREF="javascript:areyousure('${p}misc/delete-phone_device.html?$devicenum')">delete</A>).
@@ -118,6 +143,7 @@ my $html_foot = sub {
# concatenate & return
###
+ $e911.
$devices.
join(' | ', @links ). '<BR>'.
join(' | ', @ilinks). '<BR>';