1
2
3 """
4 @copyright:
5 Copyright (c) 2014 by mTLD Top Level Domain Limited. All rights reserved.\n
6 Portions copyright (c) 2008 by Argo Interactive Limited.\n
7 Portions copyright (c) 2008 by Nokia Inc.\n
8 Portions copyright (c) 2008 by Telecom Italia Mobile S.p.A.\n
9 Portions copyright (c) 2008 by Volantis Systems Limited.\n
10 Portions copyright (c) 2002-2008 by Andreas Staeding.\n
11 Portions copyright (c) 2008 by Zandan.\n
12 @author: dotMobi
13 """
14
15 import re
16 try:
17 import json as simplejson
18 except ImportError:
19 import simplejson
20
21 from mobi.mtld.da.device.ua_props import UaProps
22 from mobi.mtld.da.device.client_props import ClientProps
23 from mobi.mtld.da.data_type import DataType
24 from mobi.mtld.da.property import Property
25 from mobi.mtld.da.properties import Properties
26 from mobi.mtld.da.exception.data_file_exception import DataFileException
27 from mobi.mtld.da.exception.client_properties_exception import ClientPropertiesException
28
30
31 MIN_JSON_VERSION = 0.7
32
33
34 MAP_INITIAL_CAPACITY = 100
35
36
37 KEY_DEVICE_ID = 'iid'
38
39
40 KEY_META = '$'
41
42
43 KEY_META_VERSION = 'Ver'
44
45
46 KEY_META_REVISION = 'Rev'
47
48
49 KEY_META_TIMESTAMP = 'Utc'
50
51
52 KEY_PROPERTY_NAMES = 'p'
53
54
55 KEY_VALUES = 'v'
56
57
58 KEY_REGEX = 'r'
59
60
61
62 KEY_COMPILED_REGEX = 'creg'
63
64
65
66 KEY_HEADERS = 'h'
67
68
69
70 KEY_UA_STOCK_HEADERS = 'sl'
71
72
73 KEY_MAIN = 't'
74
75
76 KEY_DATA = 'd'
77
78
79 KEY_CHILDREN = 'c'
80
81
82 KEY_MASKED = 'm'
83
84 properties = None
85 tree = None
86 data_revision = None
87
88
89
90
91 stock_ua_headers = []
92
93 __config = None
94 __ua_props = None
95 __client_props = None
96 __device_id_prop_name_id = None
97
98
163
165 """
166 Get the list of all available property names from the tree (not contains
167 client side props)
168 """
169 return self.tree[self.KEY_PROPERTY_NAMES]
170
176
182
183 - def put_properties(self, user_agent, stock_user_agents,
184 client_side_properties = None):
185 """
186 Get properties from tree walk/ua/client-side and put them in the
187 tree.properties
188
189 @param user_agent: user-agent string (from the original User-Agent header) to be
190 used for detecting ua-props
191 @param stock_user_agents: list of candidate user-agent strings to be used for
192 tree walk
193 @param client_side_properties: optional client side properties
194 """
195
196 self.properties = Properties()
197
198 self.put_tree_walk_properties(user_agent, stock_user_agents)
199
200 if client_side_properties is not None and client_side_properties != "":
201 if self.__client_props is None:
202
203 raise ClientPropertiesException('JSON data does not support client ' +
204 'properties.')
205 self.__client_props.put_properties(client_side_properties)
206
208 """
209 Get properties from tree walk/ua and put them in the tree.properties
210
211 if stock_user_agents is not None:
212 - iterate over stock_user_agents
213 for each item: tree-walk and stop iteration if result has deviceId
214 - use userAgent for detecting the ua-props
215
216 if stock_user_agents is None:
217 - use userAgent for tree walk
218 - use userAgent for detecting the ua-props
219
220 @param user_agent: user-agent string (from the original User-Agent header)
221 @param stock_user_agents: list of candidate user-agent strings to be used for
222 tree walk
223 """
224
225 include_ua_props = self.__config.include_ua_props
226
227
228 props_to_vals = {}
229 regexes = self.tree[self.KEY_REGEX][str(UaProps.API_ID)]
230 tree_main = self.tree[self.KEY_MAIN]
231 matched = ""
232
233
234 user_agent = user_agent.strip().replace("\/", "/")
235
236 if stock_user_agents is None:
237
238 self.__seek_properties(tree_main, user_agent, props_to_vals, matched,
239 regexes)
240
241 else:
242
243 for stock_user_agent in stock_user_agents:
244 stock_user_agent = stock_user_agent.replace("\/", "/")
245 self.__seek_properties(tree_main, stock_user_agent, props_to_vals, matched,
246 regexes)
247 if self.__device_id_prop_name_id in props_to_vals:
248 break
249
250
251
252
253 for property_id, value_id in props_to_vals.items():
254 name = self.property_name_by_id(int(property_id))
255 self.properties[name[1:]] = Property(self.property_value_by_id(value_id),
256 name[0])
257
258
259 if self.__config.include_match_info:
260
261 self.properties['_matched'] = Property(matched, DataType.STRING)
262 self.properties['_unmatched'] = Property(user_agent[len(matched):],
263 DataType.STRING)
264
265
266 if include_ua_props and self.__ua_props is not None:
267 self.__ua_props.put_properties(user_agent, props_to_vals)
268
269
272
275
276
277
278 - def __seek_properties(self, node, string, props_to_vals, matched, regex_rules,
279 sought = None):
280
281 if self.KEY_DATA in node and node[self.KEY_DATA] is not None:
282 data = node[self.KEY_DATA]
283 if sought is None:
284 for key, value in data.items():
285 props_to_vals[key] = value
286
287 else:
288 for name_id in sought:
289 value_id = data[name_id]
290 if value_id is not None:
291 props_to_vals[name_id] = value_id
292 if self.KEY_MASKED not in node or name_id not in node[self.KEY_MASKED]:
293 del sought[name_id]
294 if sought is None or len(sought) == 0:
295 return
296
297 if self.KEY_CHILDREN in node:
298 if self.KEY_REGEX in node:
299 to_run = node[self.KEY_REGEX]
300 max_regex_rules = len(regex_rules)
301 for to_run_j in to_run:
302 if to_run_j < max_regex_rules:
303 patt = regex_rules[to_run_j]
304 string = re.sub(patt, '', string)
305
306 if string is not None:
307 length = len(string) + 1
308 children = node[self.KEY_CHILDREN]
309 for k in range(0, length):
310 seek = string[0:k]
311 if seek in children:
312 matched += seek
313 return self.__seek_properties(children[seek], string[k:], props_to_vals,
314 matched, regex_rules, sought)
315