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
133 # '12513001300'<sip:4.2.2.2:5060;user=phone>;tag=SDepng302
136 $out[0] = $out[0] =~ /^\'(.+)\'/ ? $1 : "";
139 # Use the 7+ digit number as the src/dst phone number.
140 # Prefer using the number within <sip> label. If there is not one,
141 # allow using number from caller-id text field.
144 $out[$_] =~ s/^\'.+\'//g; # strip caller id label portion
145 if ($out[$_] =~ /(\d{7,})/) {
146 # Using number from <sip>
148 } elsif ($f =~ /(\d{7,})/) {
149 # Using number from caller-id text
152 # No phone number, perhaps an IP only call
158 warn "~~~~~~~~~~post-processed~~~~~~~~~~~~~~~~ \n";
159 warn "$_ $out[$_] \n" for (0..@out-1);
162 # I haven't seen commas in sample data text fields. Extra caution,
163 # mangle commas into periods as we pass back to importer
164 join ',', map{ $_ =~ s/\,/\./g; $_ } @out;