1 package FS::cdr::acmepacket;
5 FS:cdr::acmepacket - CDR import definition based on Acme Packet Net-Net 4000
9 The Acme Packet NetNet 4000 S-CX6.4.0 generates an odd cdr log format:
11 - Each row in the CSV may be in one of many various formats, some of
13 - Columns are inconsistently enclosed with " characters
14 - Quoted column values may, themselves, contain unescaped quote marks.
15 This breaks Text::CSV (well technically the FORMAT is broken, not
17 - A single call can generate multiple CDR records. The only records we're
18 interested in are billable calls:
19 - These are called "Stop Record CSV Placement" in Acme Packet documentation
20 - These will always contain a "2" as the first column value
21 - These rows may be 175 or 269 fields in length. It's unclear if the
22 undocumented 269 column rows are an intentional Acme Packet format, or
23 a bug in their switch. The extra columns are inserted at idx 115,
24 and can safely be disregarded.
28 The Acme Packet manual doesn't describe it's date format in detail. The sample
29 we were given contains only records from December. Dates are formatted like
30 so: 15:54:56.868 PST DEC 18 2017
32 I gave my best guess how they will format the month text in the parser
33 FS::cdr::_cdr_date_parse(). If this format doesn't import records on a
34 particular month, check there.
42 use FS::cdr qw(_cdr_date_parse);
47 my $cbcsv = Text::CSV->new({binary => 1})
48 or die "Error loading Text::CSV - ".Text::CSV->error_diag();
50 # Used to map source format into the contrived format created for import_fields
51 # $cdr_premap[ IMPORT_FIELDS_IDX ] = SOURCE_FORMAT_IDX
69 name => 'Acme Packet',
75 # freeside # [idx] acmepacket
76 'clid', # 9 Calling-Station-Id
77 'src', # 9 Calling-Station-Id
78 'dst', # 10 Called-Station-Id
79 'channel', # 22 Acme-Session-Ingress-Realm
80 'dstchannel', # 23 Acme-Session-Egress-Realm
81 'src_ip_addr', # 26 Acme-Flow-In-Src-Adr_FS1_f
82 'dst_ip_addr', # 28 Acme-Flow-In-Dst-Addr_FS1_f
83 'startdate', # 13 h323-setup-time
84 'answerdate', # 14 h323-connect-time
85 'enddate', # 15 h323-disconnect-time
86 'duration', # 12 Acct-Session-Time
87 'billsec', # 12 Acct-Session-Time
88 'userfield', # 3 Acct-Session-Id
94 # Only process records whose first column contains a 2
95 return undef unless $line =~ /^2\,/;
97 # Replace unescaped quote characters within quote-enclosed text cols
98 $line =~ s/(?<!\,)\"(?!\,)/\'/g;
100 unless( $cbcsv->parse($line) ) {
101 warn "Text::CSV Error parsing Acme Packet CDR: ".$cbcsv->error_diag();
105 my @row = $cbcsv->fields();
107 # Splice out the extra columns
108 @row = (@row[0..114], @row[209..@row-1]);
109 } elsif (@row != 175) {
110 warn "Unknown row format parsing Acme Packet CDR";
114 my @out = map{ $row[$_] } @cdr_premap;
117 warn "~~~~~~~~~~pre-processed~~~~~~~~~~~~~~~~ \n";
118 warn "$_ $out[$_] \n" for (0..@out-1);
121 # answerdate, enddate, startdate
123 $out[$_] = _cdr_date_parse($out[$_]);
124 if ($out[$_] =~ /\D/) {
125 warn "Unparsable date in Acme Packet CDR: ($out[$_])";
130 # clid, dst, src CDR field formatted as one of the following:
131 # 'WIRELESS CALLER'<sip:12513001300@4.2.2.2:5060;user=phone>;tag=SDepng302
132 # <sip:12513001300@4.2.2.2:5060;user=phone>;tag=SDepng302
135 $out[0] = $out[0] =~ /^\'(.+)\'/ ? $1 : "";
138 # All of the sample data given shows sip connections. In case the same
139 # switch is hooked into another circuit type in the future, we'll just
140 # tease out a length 7+ number not contained in the caller-id-text field
142 $out[$_] =~ s/^\'.+\'//g; # strip caller id label portion
143 $out[$_] = $out[$_] =~ /(\d{7,})/ ? $1 : undef;
147 warn "~~~~~~~~~~post-processed~~~~~~~~~~~~~~~~ \n";
148 warn "$_ $out[$_] \n" for (0..@out-1);
151 # I haven't seen commas in sample data text fields. Extra caution,
152 # mangle commas into periods as we pass back to importer
153 join ',', map{ $_ =~ s/\,/\./g; $_ } @out;