jsgoecke-echi_files 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2009 Jason Goecke
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,55 @@
1
+ h1. ECHI Files Ruby Library
2
+
3
+ h2. Description
4
+
5
+ A library that allows one to take an ASCII or Binary file from an <a href="http://www.google.com/url?sa=t&source=web&ct=res&cd=1&url=http%3A%2F%2Fsupport.avaya.com%2Fjapple%2Fcss%2Fjapple%3FPAGE%3DProduct%26temp.productID%3D107584&ei=h1tlSaXpDomQtQO9_8mVAw&usg=AFQjCNGdjBmfY-7VhcTninYr1c9byz0U3w&sig2=qV5YXM9h76TFe_xodJ7CHg">Avaya CMS</a> <a href="http://support.avaya.com/elmodocs2/cms/R14/ECHI.pdf">External Call History Interface (ECHI)</a> and convert it into a Ruby hash for further processing.
6
+
7
+ h2. Features
8
+
9
+ * Convert Binary file to Ruby hash
10
+ * Convert ASCII file to Ruby hash
11
+ * Support both standard and extended file formats
12
+ * Tested with both Ruby 1.8.6 and JRuby 1.1.5
13
+
14
+ h2. Example
15
+ <pre>
16
+ <code>
17
+ require 'echi_files'
18
+
19
+ #Provide a filename to process as an argument on the commandline
20
+ filename = File.expand_path(ARGV[0])
21
+
22
+ #Open the file
23
+ filehandle = open(filename, "rb")
24
+
25
+ #Instantiate an EchiFiles class to process your ASCII or BINARY files
26
+ echi_handler = EchiFiles.new
27
+
28
+ #Use this to process a binary file
29
+ file_type = 'BINARY'
30
+ format = 'EXTENDED'
31
+ #In some cases the extra_byte is needed
32
+ extra_byte = true
33
+ data = echi_handler.process_file(filehandle, file_type, format, extra_byte)
34
+
35
+ #Use this to process a binary file
36
+ file_type = 'ASCII'
37
+ format = 'EXTENDED'
38
+ extra_byte = true
39
+ #Use this to process an ASCII file
40
+ data = echi_handler.process_file(filehandle, file_type, format, extra_byte)
41
+
42
+ #If you need to strip in characters from the asaiuui field
43
+ #@data Is the Array of Hashes converted above
44
+ #@array_of_decimal_values Is an array of decimal ascii values to be stripped
45
+ data = echi_handler.strip_asaiuui(data, array_of_decimal_values)
46
+ </code>
47
+ </pre>
48
+
49
+ h2. Dependencies
50
+
51
+ * FasterCSV 1.4.0+
52
+
53
+ h2. Installation
54
+
55
+ sudo gem install jsgoecke-echi_files --source=http://gems.github.com/
@@ -0,0 +1,22 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "echi_files"
3
+ s.version = "0.1.0"
4
+ s.date = "2009-01-19"
5
+ s.summary = "Ruby Library for Processing Avaya ECHI Files"
6
+ s.description = "Ruby Library for processing External Call History (ECHI) files from the Avaya CMS"
7
+ s.authors = ["Jason Goecke"]
8
+ s.email = ["jason -at- goecke.net"]
9
+ s.has_rdoc = false
10
+ s.homepage = "http://jsgoecke.github.com/echi_files"
11
+ s.rubygems_version = "1.3.1"
12
+
13
+ s.files = ["lib/echi_files.rb",
14
+ "lib/extended-definition.yml",
15
+ "lib/standard-definition.yml",
16
+ "LICENSE",
17
+ "README.textile",
18
+ "echi_files.gemspec"]
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency("fastercsv", ">=", "1.4.0")
22
+ end
data/lib/echi_files.rb ADDED
@@ -0,0 +1,185 @@
1
+ require 'yaml'
2
+ require 'fastercsv'
3
+
4
+ class EchiFiles
5
+
6
+ def initialize
7
+ @extended = YAML::load_file(File.expand_path(File.dirname(__FILE__) + "/extended-definition.yml"))
8
+ @standard = YAML::load_file(File.expand_path(File.dirname(__FILE__) + "/standard-definition.yml"))
9
+ end
10
+
11
+ #Method for parsing the various datatypes from the ECH file
12
+ def dump_binary(filehandle, type, length)
13
+ case type
14
+ when 'int'
15
+ #Process integers, assigning appropriate profile based on length
16
+ #such as long int, short int and tiny int.
17
+ case length
18
+ when 4
19
+ value = filehandle.read(length).unpack("l").first.to_i
20
+ when 2
21
+ value = filehandle.read(length).unpack("s").first.to_i
22
+ when 1
23
+ value = filehandle.read(length).unpack("U").first.to_i
24
+ end
25
+ #Process appropriate intergers into datetime format in the database
26
+ when 'datetime'
27
+ case length
28
+ when 4
29
+ value = filehandle.read(length).unpack("l").first.to_i
30
+ puts value.inspect
31
+ value = Time.at(value)
32
+ end
33
+ #Process strings
34
+ when 'str'
35
+ value = filehandle.read(length).unpack("M").first.to_s.rstrip
36
+ #Process individual bits that are booleans
37
+ when 'bool'
38
+ value = filehandle.read(length).unpack("b8").last.to_s
39
+ #Process that one wierd boolean that is actually an int, instead of a bit
40
+ when 'boolint'
41
+ value = filehandle.read(length).unpack("U").first.to_i
42
+ #Change the values of the field to Y/N for the varchar(1) representation of BOOLEAN
43
+ if value == 1
44
+ value = 'Y'
45
+ else
46
+ value = 'N'
47
+ end
48
+ end
49
+ return value
50
+ end
51
+
52
+ #Mehtod that performs the conversions
53
+ def convert_binary_file(filehandle, schema, extra_byte)
54
+
55
+ #Read header information first
56
+ fileversion = dump_binary(filehandle, 'int', 4)
57
+ filenumber = dump_binary(filehandle, 'int', 4)
58
+
59
+ bool_cnt = 0
60
+ bytearray = nil
61
+ data = Array.new
62
+ while filehandle.eof == FALSE do
63
+ record = Hash.new
64
+ schema["echi_records"].each do | field |
65
+ #We handle the 'boolean' fields differently, as they are all encoded as bits in a single 8-bit byte
66
+ if field["type"] == 'bool'
67
+ if bool_cnt == 0
68
+ bytearray = dump_binary(filehandle, field["type"], field["length"])
69
+ end
70
+ #Ensure we parse the bytearray and set the appropriate flags
71
+ #We need to make sure the entire array is not nil, in order to do Y/N
72
+ #if Nil we then set all no
73
+ if bytearray != '00000000'
74
+ if bytearray.slice(bool_cnt,1) == '1'
75
+ value = 'Y'
76
+ else
77
+ value = 'N'
78
+ end
79
+ else
80
+ value = 'N'
81
+ end
82
+ record.merge!({ field["name"] => value })
83
+ bool_cnt += 1
84
+ if bool_cnt == 8
85
+ bool_cnt = 0
86
+ end
87
+ else
88
+ #Process 'standard' fields
89
+ value = dump_binary(filehandle, field["type"], field["length"])
90
+ record.merge!({ field["name"] => value })
91
+ end
92
+
93
+ end
94
+
95
+ #Scan past the end of line record if enabled in the configuration file
96
+ #Comment this out if you do not need to read the 'extra byte'
97
+ if extra_byte
98
+ filehandle.read(1)
99
+ end
100
+ data << record
101
+ end
102
+
103
+ return data
104
+ end
105
+
106
+ #Method to create a Ruby hash out of the Avaya ECHI files
107
+ #@filehandle The filehandle
108
+ #@type Whether this is ASCII or Binary data
109
+ #@schema Whether this is the ECHI EXTENDED or STANDARD file format
110
+ def convert_ascii_file(filehandle, schema)
111
+
112
+ data = Array.new
113
+ filehandle.each do |line|
114
+ record = Hash.new
115
+ FasterCSV.parse(line) do |row|
116
+ cnt = 0
117
+ row.each do |field|
118
+ if field != nil
119
+ if schema["echi_records"][cnt]["type"] == "bool" || schema["echi_records"][cnt]["type"] == "boolint"
120
+ case field
121
+ when "0"
122
+ record.merge!({ schema["echi_records"][cnt]["name"] => "N" })
123
+ when "1"
124
+ record.merge!({ schema["echi_records"][cnt]["name"] => "Y" })
125
+ when nil
126
+ record.merge!({ schema["echi_records"][cnt]["name"] => "N" })
127
+ else
128
+ record.merge!({ schema["echi_records"][cnt]["name"] => "Y" })
129
+ end
130
+ else
131
+ record.merge!({ schema["echi_records"][cnt]["name"] => field })
132
+ end
133
+ cnt += 1
134
+ end
135
+ end
136
+ end
137
+ data << record
138
+ end
139
+
140
+ return data
141
+ end
142
+
143
+ #Pass a filehandle of the file to process that includes
144
+ #@filehandle The filehandle
145
+ #@type Whether this is ASCII or Binary data
146
+ #@format Whether this is the ECHI EXTENDED or STANDARD file format
147
+ #@extra_byte Set to true if you want to read an extra byte at the end of each record
148
+ #This method will return an array of hashes of the resulting data processed
149
+ def process_file(filehandle, type, format, extra_byte)
150
+
151
+ #Set the appropriate schema format for standard or extended from the Avaya CMS
152
+ case format
153
+ when 'EXTENDED'
154
+ schema = @extended
155
+ when 'STANDARD'
156
+ schema = @standard
157
+ end
158
+
159
+ #Process based on the filetype passed
160
+ case type
161
+ when 'ASCII'
162
+ return convert_ascii_file(filehandle, schema)
163
+ when 'BINARY'
164
+ return convert_binary_file(filehandle, schema, extra_byte)
165
+ end
166
+
167
+ end
168
+
169
+ #Method used to strip special characters
170
+ #@data An Array of Hashes to be processed
171
+ #@characters An Array of charcters to be stripped
172
+ def strip_asaiuui(data, characters)
173
+
174
+ stripped_data = Array.new
175
+ data.each do |row|
176
+ characters.each do |char|
177
+ row["asaiuui"].gsub!(char.chr,"")
178
+ end
179
+ stripped_data << row
180
+ end
181
+
182
+ return stripped_data
183
+ end
184
+
185
+ end
@@ -0,0 +1,234 @@
1
+ #ECH File construct, order is important, as the application sequentially reads the file
2
+ #Version 12 through 15 - Extended Schema
3
+ echi_records:
4
+ - name: callid
5
+ type: int
6
+ length: 4
7
+ - name: acwtime
8
+ type: int
9
+ length: 4
10
+ - name: onholdtime
11
+ type: int
12
+ length: 4
13
+ - name: consulttime
14
+ type: int
15
+ length: 4
16
+ - name: disptime
17
+ type: int
18
+ length: 4
19
+ - name: duration
20
+ type: int
21
+ length: 4
22
+ - name: segstart
23
+ type: datetime
24
+ length: 4
25
+ - name: segstop
26
+ type: datetime
27
+ length: 4
28
+ - name: talktime
29
+ type: int
30
+ length: 4
31
+ - name: netintime
32
+ type: int
33
+ length: 4
34
+ - name: origholdtime
35
+ type: int
36
+ length: 4
37
+ - name: queuetime
38
+ type: int
39
+ length: 4
40
+ - name: ringtime
41
+ type: int
42
+ length: 4
43
+ - name: dispivector
44
+ type: int
45
+ length: 2
46
+ - name: dispsplit
47
+ type: int
48
+ length: 2
49
+ - name: firstivector
50
+ type: int
51
+ length: 2
52
+ - name: split1
53
+ type: int
54
+ length: 2
55
+ - name: split2
56
+ type: int
57
+ length: 2
58
+ - name: split3
59
+ type: int
60
+ length: 2
61
+ - name: trunkgroup
62
+ type: int
63
+ length: 2
64
+ - name: tklocid
65
+ type: int
66
+ length: 2
67
+ - name: origlocid
68
+ type: int
69
+ length: 2
70
+ - name: answerlocid
71
+ type: int
72
+ length: 2
73
+ - name: obslocid
74
+ type: int
75
+ length: 2
76
+ - name: uuilen
77
+ type: int
78
+ length: 2
79
+ - name: assist
80
+ type: bool
81
+ length: 1
82
+ - name: audiodifficulty
83
+ type: bool
84
+ length: 1
85
+ - name: conference
86
+ type: bool
87
+ length: 1
88
+ - name: daqueued
89
+ type: bool
90
+ length: 1
91
+ - name: holdabn
92
+ type: bool
93
+ length: 1
94
+ - name: malicious
95
+ type: bool
96
+ length: 1
97
+ - name: observingcall
98
+ type: bool
99
+ length: 1
100
+ - name: transferred
101
+ type: bool
102
+ length: 1
103
+ - name: agentreleased
104
+ type: boolint
105
+ length: 1
106
+ - name: acdnum
107
+ type: int
108
+ length: 1
109
+ - name: calldisp
110
+ type: int
111
+ length: 1
112
+ - name: disppriority
113
+ type: int
114
+ length: 1
115
+ - name: holds
116
+ type: int
117
+ length: 1
118
+ - name: segment
119
+ type: int
120
+ length: 1
121
+ - name: ansreason
122
+ type: int
123
+ length: 1
124
+ - name: origreason
125
+ type: int
126
+ length: 1
127
+ - name: dispsklevel
128
+ type: int
129
+ length: 1
130
+ - name: events0
131
+ type: int
132
+ length: 1
133
+ - name: events1
134
+ type: int
135
+ length: 1
136
+ - name: events2
137
+ type: int
138
+ length: 1
139
+ - name: events3
140
+ type: int
141
+ length: 1
142
+ - name: events4
143
+ type: int
144
+ length: 1
145
+ - name: events5
146
+ type: int
147
+ length: 1
148
+ - name: events6
149
+ type: int
150
+ length: 1
151
+ - name: events7
152
+ type: int
153
+ length: 1
154
+ - name: events8
155
+ type: int
156
+ length: 1
157
+ - name: ucid
158
+ type: str
159
+ length: 21
160
+ - name: dispvdn
161
+ type: str
162
+ length: 8
163
+ - name: eqloc
164
+ type: str
165
+ length: 10
166
+ - name: firstvdn
167
+ type: str
168
+ length: 8
169
+ - name: origlogid
170
+ type: str
171
+ length: 10
172
+ - name: anslogid
173
+ type: str
174
+ length: 10
175
+ - name: lastobserver
176
+ type: str
177
+ length: 10
178
+ - name: dialednumber
179
+ type: str
180
+ length: 25
181
+ - name: callingparty
182
+ type: str
183
+ length: 13
184
+ - name: collectdigits
185
+ type: str
186
+ length: 17
187
+ - name: cwcdigits
188
+ type: str
189
+ length: 17
190
+ - name: callingII
191
+ type: str
192
+ length: 3
193
+ - name: cwcs0
194
+ type: str
195
+ length: 17
196
+ - name: cwcs1
197
+ type: str
198
+ length: 17
199
+ - name: cwcs2
200
+ type: str
201
+ length: 17
202
+ - name: cwcs3
203
+ type: str
204
+ length: 17
205
+ - name: cwcs4
206
+ type: str
207
+ length: 17
208
+ - name: vdn2
209
+ type: str
210
+ length: 8
211
+ - name: vdn3
212
+ type: str
213
+ length: 8
214
+ - name: vdn4
215
+ type: str
216
+ length: 8
217
+ - name: vdn5
218
+ type: str
219
+ length: 8
220
+ - name: vdn6
221
+ type: str
222
+ length: 8
223
+ - name: vdn7
224
+ type: str
225
+ length: 8
226
+ - name: vdn8
227
+ type: str
228
+ length: 8
229
+ - name: vdn9
230
+ type: str
231
+ length: 8
232
+ - name: asaiuui
233
+ type: str
234
+ length: 96
@@ -0,0 +1,198 @@
1
+ #ECH File construct, order is important, as the application sequentially reads the file
2
+ #Version 14 - Standard Schema
3
+ echi_records:
4
+ - name: callid
5
+ type: int
6
+ length: 4
7
+ - name: acwtime
8
+ type: int
9
+ length: 4
10
+ - name: onholdtime
11
+ type: int
12
+ length: 4
13
+ - name: consulttime
14
+ type: int
15
+ length: 4
16
+ - name: disptime
17
+ type: int
18
+ length: 4
19
+ - name: duration
20
+ type: int
21
+ length: 4
22
+ - name: segstart
23
+ type: datetime
24
+ length: 4
25
+ - name: segstop
26
+ type: datetime
27
+ length: 4
28
+ - name: talktime
29
+ type: int
30
+ length: 4
31
+ - name: netintime
32
+ type: int
33
+ length: 4
34
+ - name: origholdtime
35
+ type: int
36
+ length: 4
37
+ - name: dispivector
38
+ type: int
39
+ length: 2
40
+ - name: dispsplit
41
+ type: int
42
+ length: 2
43
+ - name: firstivector
44
+ type: int
45
+ length: 2
46
+ - name: split1
47
+ type: int
48
+ length: 2
49
+ - name: split2
50
+ type: int
51
+ length: 2
52
+ - name: split3
53
+ type: int
54
+ length: 2
55
+ - name: trunkgroup
56
+ type: int
57
+ length: 2
58
+ - name: tklocid
59
+ type: int
60
+ length: 2
61
+ - name: origlocid
62
+ type: int
63
+ length: 2
64
+ - name: answerlocid
65
+ type: int
66
+ length: 2
67
+ - name: obslocid
68
+ type: int
69
+ length: 2
70
+ - name: assist
71
+ type: bool
72
+ length: 1
73
+ - name: audiodifficulty
74
+ type: bool
75
+ length: 1
76
+ - name: conference
77
+ type: bool
78
+ length: 1
79
+ - name: daqueued
80
+ type: bool
81
+ length: 1
82
+ - name: holdabn
83
+ type: bool
84
+ length: 1
85
+ - name: malicious
86
+ type: bool
87
+ length: 1
88
+ - name: observingcall
89
+ type: bool
90
+ length: 1
91
+ - name: transferred
92
+ type: bool
93
+ length: 1
94
+ - name: agentreleased
95
+ type: boolint
96
+ length: 1
97
+ - name: acdnum
98
+ type: int
99
+ length: 1
100
+ - name: calldisp
101
+ type: int
102
+ length: 1
103
+ - name: disppriority
104
+ type: int
105
+ length: 1
106
+ - name: holds
107
+ type: int
108
+ length: 1
109
+ - name: segment
110
+ type: int
111
+ length: 1
112
+ - name: ansreason
113
+ type: int
114
+ length: 1
115
+ - name: origreason
116
+ type: int
117
+ length: 1
118
+ - name: dispsklevel
119
+ type: int
120
+ length: 1
121
+ - name: events0
122
+ type: int
123
+ length: 1
124
+ - name: events1
125
+ type: int
126
+ length: 1
127
+ - name: events2
128
+ type: int
129
+ length: 1
130
+ - name: events3
131
+ type: int
132
+ length: 1
133
+ - name: events4
134
+ type: int
135
+ length: 1
136
+ - name: events5
137
+ type: int
138
+ length: 1
139
+ - name: events6
140
+ type: int
141
+ length: 1
142
+ - name: events7
143
+ type: int
144
+ length: 1
145
+ - name: events8
146
+ type: int
147
+ length: 1
148
+ - name: ucid
149
+ type: str
150
+ length: 21
151
+ - name: dispvdn
152
+ type: str
153
+ length: 8
154
+ - name: eqloc
155
+ type: str
156
+ length: 10
157
+ - name: firstvdn
158
+ type: str
159
+ length: 8
160
+ - name: origlogid
161
+ type: str
162
+ length: 10
163
+ - name: anslogid
164
+ type: str
165
+ length: 10
166
+ - name: lastobserver
167
+ type: str
168
+ length: 10
169
+ - name: dialednumber
170
+ type: str
171
+ length: 25
172
+ - name: callingparty
173
+ type: str
174
+ length: 13
175
+ - name: collectdigits
176
+ type: str
177
+ length: 17
178
+ - name: cwcdigits
179
+ type: str
180
+ length: 17
181
+ - name: callingII
182
+ type: str
183
+ length: 3
184
+ - name: cwcs0
185
+ type: str
186
+ length: 17
187
+ - name: cwcs1
188
+ type: str
189
+ length: 17
190
+ - name: cwcs2
191
+ type: str
192
+ length: 17
193
+ - name: cwcs3
194
+ type: str
195
+ length: 17
196
+ - name: cwcs4
197
+ type: str
198
+ length: 17
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jsgoecke-echi_files
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jason Goecke
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-19 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: fastercsv
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0"
23
+ - - "="
24
+ - !ruby/object:Gem::Version
25
+ version: 1.4.0
26
+ version:
27
+ description: Ruby Library for processing External Call History (ECHI) files from the Avaya CMS
28
+ email:
29
+ - jason -at- goecke.net
30
+ executables: []
31
+
32
+ extensions: []
33
+
34
+ extra_rdoc_files: []
35
+
36
+ files:
37
+ - lib/echi_files.rb
38
+ - lib/extended-definition.yml
39
+ - lib/standard-definition.yml
40
+ - LICENSE
41
+ - README.textile
42
+ - echi_files.gemspec
43
+ has_rdoc: false
44
+ homepage: http://jsgoecke.github.com/echi_files
45
+ post_install_message:
46
+ rdoc_options: []
47
+
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ requirements: []
63
+
64
+ rubyforge_project:
65
+ rubygems_version: 1.2.0
66
+ signing_key:
67
+ specification_version: 2
68
+ summary: Ruby Library for Processing Avaya ECHI Files
69
+ test_files: []
70
+