summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Wells <mark@freeside.biz>2013-03-22 13:33:44 -0700
committerMark Wells <mark@freeside.biz>2013-03-22 13:33:44 -0700
commita205ffec778bd42eb084bcffec6884063263f634 (patch)
treeff8a9a33c1ea29748091d832a8b516bfa18b7de3
parent26bc6f249a1cdb165bf9b0d0fa3fc055ed457723 (diff)
SIM/KI inventory for Huawei HLR export, #21514
-rw-r--r--FS/FS/part_export.pm11
-rw-r--r--FS/FS/part_export/huawei_hlr.pm110
-rwxr-xr-xhttemplate/browse/part_export.cgi15
-rw-r--r--httemplate/elements/progress-init.html2
-rw-r--r--httemplate/misc/part_export/huawei_hlr-import_sim.html52
-rw-r--r--httemplate/misc/part_export/process/huawei_hlr-import_sim.html10
6 files changed, 199 insertions, 1 deletions
diff --git a/FS/FS/part_export.pm b/FS/FS/part_export.pm
index 3eee37f..15ce9c0 100644
--- a/FS/FS/part_export.pm
+++ b/FS/FS/part_export.pm
@@ -601,6 +601,17 @@ DEFAULTSREF is a hashref with the same keys where true values indicate the
setting is a default (and thus can be displayed in the UI with less emphasis,
or hidden by default).
+=item actions
+
+Adds one or more "action" links to the export's display in
+browse/part_export.cgi. Should return pairs of values. The first is
+the link label; the second is the Mason path to a document to load.
+The document will show in a popup.
+
+=cut
+
+sub actions { }
+
=cut
=item weight
diff --git a/FS/FS/part_export/huawei_hlr.pm b/FS/FS/part_export/huawei_hlr.pm
index d231567..0079818 100644
--- a/FS/FS/part_export/huawei_hlr.pm
+++ b/FS/FS/part_export/huawei_hlr.pm
@@ -5,8 +5,12 @@ use Tie::IxHash;
use FS::Record qw(qsearch qsearchs dbh);
use FS::part_export;
use FS::svc_phone;
+use FS::inventory_class;
+use FS::inventory_item;
use IO::Socket::INET;
use Data::Dumper;
+use MIME::Base64 qw(decode_base64);
+use Storable qw(thaw);
use strict;
@@ -18,6 +22,20 @@ tie my %options, 'Tie::IxHash',
'pwd' => { label=>'Operator password' },
'tplid' => { label=>'Template number' },
'hlrsn' => { label=>'HLR serial number' },
+ 'k4sno' => { label=>'K4 serial number' },
+ 'cardtype' => { label => 'Card type',
+ type => 'select',
+ options=> ['SIM', 'USIM']
+ },
+ 'alg' => { label => 'Authentication algorithm',
+ type => 'select',
+ options=> ['COMP128_1',
+ 'COMP128_2',
+ 'COMP128_3',
+ 'MILENAGE' ],
+ },
+ 'opcvalue' => { label=>'OPC value (for MILENAGE only)' },
+ 'opsno' => { label=>'OP serial number (for MILENAGE only)' },
'timeout' => { label=>'Timeout (seconds)', default => 120 },
'debug' => { label=>'Enable debugging', type=>'checkbox' },
;
@@ -33,6 +51,10 @@ set on the service, and the template must exist.
END
);
+sub actions {
+ 'Import SIMs' => 'misc/part_export/huawei_hlr-import_sim.html'
+}
+
sub _export_insert {
my( $self, $svc_phone ) = (shift, shift);
# svc_phone::check should ensure phonenum and sim_imsi are numeric
@@ -227,4 +249,92 @@ sub command {
\%return;
}
+sub process_import_sim {
+ my $job = shift;
+ my $param = thaw(decode_base64(shift));
+ $param->{'job'} = $job;
+ my $exportnum = delete $param->{'exportnum'};
+ my $export = __PACKAGE__->by_key($exportnum);
+ my $file = delete $param->{'uploaded_files'};
+ $file =~ s/^file://;
+ my $dir = $FS::UID::cache_dir .'/cache.'. $FS::UID::datasrc;
+ open( $param->{'filehandle'}, '<', "$dir/$file" )
+ or die "unable to open '$file'.\n";
+ my $error = $export->import_sim($param);
+}
+
+sub import_sim {
+ # import a SIM list
+ local $FS::UID::AutoCommit = 1; # yes, 1
+ my $self = shift;
+ my $param = shift;
+ my $job = $param->{'job'};
+ my $fh = $param->{'filehandle'};
+ my @lines = $fh->getlines;
+
+ my @command = 'ADD KI';
+ push @command, ('HLRSN', $self->option('hlrsn')) if $self->option('hlrsn');
+
+ my @args = ('OPERTYPE', 'ADD');
+ push @args, ('K4SNO', $self->option('k4sno')) if $self->option('k4sno');
+ push @args, ('CARDTYPE', $self->option('cardtype'),
+ 'ALG', $self->option('alg'));
+ push @args, ('OPCVALUE', $self->option('opcvalue'),
+ 'OPSNO', $self->option('opsno'))
+ if $self->option('alg') eq 'MILENAGE';
+
+ my $agentnum = $param->{'agentnum'};
+ my $classnum = $param->{'classnum'};
+ my $class = FS::inventory_class->by_key($classnum)
+ or die "bad inventory class $classnum\n";
+ my %existing = map { $_->item, 1 }
+ qsearch('inventory_item', { 'classnum' => $classnum });
+
+ my $socket = $self->login;
+ my $num=0;
+ my $total = scalar(@lines);
+ foreach my $line (@lines) {
+ $num++;
+ $job->update_statustext(int(100*$num/$total).',Provisioning IMSIs...')
+ if $job;
+
+ chomp $line;
+ my ($imsi, $iccid, $pin1, $puk1, $pin2, $puk2, $acc, $ki) =
+ split(' ', $line);
+ # the only fields we really care about are the IMSI and KI.
+ if ($imsi !~ /^\d{15}$/ or $ki !~ /^[0-9A-Z]{32}$/) {
+ warn "misspelled line in SIM file: $line\n";
+ next;
+ }
+ if ($existing{$imsi}) {
+ warn "IMSI $imsi already in inventory, skipped\n";
+ next;
+ }
+
+ # push IMSI/KI to the HLR
+ my $return = $self->command($socket,
+ @command,
+ 'IMSI', $imsi,
+ 'KIVALUE', $ki,
+ @args
+ );
+ if ( $return->{success} ) {
+ # add to inventory
+ my $item = FS::inventory_item->new({
+ 'classnum' => $classnum,
+ 'agentnum' => $agentnum,
+ 'item' => $imsi,
+ });
+ my $error = $item->insert;
+ if ( $error ) {
+ die "IMSI $imsi added to HLR, but not to inventory:\n$error\n";
+ }
+ } else {
+ die "IMSI $imsi could not be added to HLR:\n".$return->{error}."\n";
+ }
+ } #foreach $line
+ $self->logout($socket);
+ return;
+}
+
1;
diff --git a/httemplate/browse/part_export.cgi b/httemplate/browse/part_export.cgi
index 91238a0..876633a 100755
--- a/httemplate/browse/part_export.cgi
+++ b/httemplate/browse/part_export.cgi
@@ -38,6 +38,21 @@ function part_export_areyousure(href) {
<TD CLASS="grid" BGCOLOR="<% $bgcolor %>">
<% $part_export->label_html %>
(<A HREF="<% $p %>edit/part_export.cgi?<% $part_export->exportnum %>">edit</A>&nbsp;|&nbsp;<A HREF="javascript:part_export_areyousure('<% $p %>misc/delete-part_export.cgi?<% $part_export->exportnum %>')">delete</A>)
+% if ( my @actions = $part_export->actions ) {
+ <P STYLE="position: absolute">
+ Management:
+% while (@actions) {
+% my $label = shift @actions;
+% my $path = shift @actions;
+ <& /elements/popup_link.html,
+ 'label' => $label,
+ 'action' => $fsurl.$path.'?'.$part_export->exportnum,
+ 'actionlabel' => $label,
+ &><% @actions ? '&nbsp;|&nbsp;' : '' %>
+% }
+ </P>
+% } #if @actions
+
</TD>
<TD CLASS="inv" BGCOLOR="<% $bgcolor %>">
diff --git a/httemplate/elements/progress-init.html b/httemplate/elements/progress-init.html
index 7a282a3..cef54b8 100644
--- a/httemplate/elements/progress-init.html
+++ b/httemplate/elements/progress-init.html
@@ -108,7 +108,7 @@ function <%$key%>process () {
function <%$key%>myCallback( jobnum ) {
- overlib( OLiframeContent('<%$p%>elements/progress-popup.html?jobnum=' + jobnum + ';<%$url_or_message_link%>;formname=<%$formname%>' , 444, 168, '<% $popup_name %>'), CAPTION, 'Please wait...', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', CLOSECLICK, MIDX, 0, MIDY, 0 );
+ overlib( OLiframeContent('<%$fsurl%>elements/progress-popup.html?jobnum=' + jobnum + ';<%$url_or_message_link%>;formname=<%$formname%>' , 444, 168, '<% $popup_name %>'), CAPTION, 'Please wait...', STICKY, AUTOSTATUSCAP, CLOSETEXT, '', CLOSECLICK, MIDX, 0, MIDY, 0 );
}
diff --git a/httemplate/misc/part_export/huawei_hlr-import_sim.html b/httemplate/misc/part_export/huawei_hlr-import_sim.html
new file mode 100644
index 0000000..9b87b3d
--- /dev/null
+++ b/httemplate/misc/part_export/huawei_hlr-import_sim.html
@@ -0,0 +1,52 @@
+<& /elements/header-popup.html, 'Import SIMs' &>
+Import a file containing SIM card properties.<BR>
+Each row should contain the following fields, separated by spaces:<BR>
+IMSI, ICCID, PIN1, PUK1, PIN2, PUK2, ACC, Ki<BR>
+<BR>
+<& /elements/form-file_upload.html,
+ 'name' => 'ImportForm',
+ 'action' => 'process/huawei_hlr-import_sim.html',
+ 'num_files' => 1,
+ 'fields' => [ 'exportnum', 'classnum', 'agentnum', ],
+ 'message' => 'Inventory import successful',
+ 'onsubmit' => "document.ImportForm.submitButton.disabled=true;",
+&>
+<TABLE CLASS="inv" WIDTH="100%">
+ <INPUT TYPE="hidden" NAME="exportnum" VALUE="<%$exportnum%>">
+ <& /elements/file-upload.html,
+ 'field' => 'file',
+ 'label' => 'Filename',
+ &>
+ <& /elements/tr-select-agent.html,
+ 'disable_empty' => 1,
+ &>
+ <& /elements/tr-select-table.html,
+ 'table' => 'inventory_class',
+ 'name_col' => 'classname',
+ 'label' => 'Inventory class',
+ 'disable_empty' => 1,
+ &>
+
+ <TR>
+ <TD COLSPAN=2 ALIGN="center" STYLE="padding-top:6px">
+ <INPUT TYPE = "submit"
+ NAME = "submitButton"
+ ID = "submitButton"
+ VALUE = "Import file"
+ >
+ </TD>
+ </TR>
+
+</TABLE>
+
+</FORM>
+
+<%init>
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+my ($exportnum) = $cgi->keywords;
+$exportnum =~ /^\d+$/ or die "bad exportnum '$exportnum'";
+my $part_export = FS::part_export->by_key($exportnum)
+ or die "export $exportnum not found";
+</%init>
diff --git a/httemplate/misc/part_export/process/huawei_hlr-import_sim.html b/httemplate/misc/part_export/process/huawei_hlr-import_sim.html
new file mode 100644
index 0000000..d46700d
--- /dev/null
+++ b/httemplate/misc/part_export/process/huawei_hlr-import_sim.html
@@ -0,0 +1,10 @@
+<% $server->process %>
+<%init>
+
+die "access denied"
+ unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
+
+my $server = new FS::UI::Web::JSRPC
+ 'FS::part_export::huawei_hlr::process_import_sim', $cgi;
+
+</%init>