1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 __doc__ = """
21 This module contains the supporting classes for the Two Step Analysis user agent
22 algorithm that is used as the primary way to match user agents with the Java API
23 for the WURFL.
24
25 A description of the way the following source is intended to work can be found
26 within the source for the original Java API implementation here:
27 http://sourceforge.net/projects/wurfl/files/WURFL Java API/
28
29 The original Java code is GPLd and Copyright (c) 2008-2009 WURFL-Pro srl
30 """
31
32 __author__ = "Armand Lynch <lyncha@users.sourceforge.net>"
33 __copyright__ = "Copyright 2010, Armand Lynch"
34 __license__ = "LGPL"
35 __url__ = "http://celljam.net/"
36 __version__ = "1.0.0"
37
38 from functools import partial
39
40 from pywurfl.algorithms.wurfl import utils
41 from pywurfl.algorithms.wurfl import normalizers
42 from pywurfl.algorithms.wurfl.strategies import ld_match, ris_match
43
44
45 uiol = utils.indexof_or_length
46 uoi = utils.ordinal_index
50 user_agent_map = {}
51
53 if normalizer is None:
54 self.normalizer = lambda x: x
55 else:
56 self.normalizer = normalizer
57 self.known_user_agents = set()
58
59 - def add(self, user_agent, wurfl_id):
60 self.known_user_agents.add(user_agent)
61 self.user_agent_map[user_agent] = wurfl_id
62
63 @property
65 return sorted(self.known_user_agents)
66
68 raise NotImplementedError
69
71 user_agent = self.normalizer(user_agent)
72 devid = self.conclusive_match(user_agent)
73 if not devid or devid == u"generic":
74 devid = self.recovery_match(user_agent)
75 if not devid or devid == u"generic":
76 devid = self.catch_all_recovery_match(user_agent)
77 return devid
78
88
95
98
100
101 match = u"generic"
102
103
104 if u"UP.Browser/7.2" in user_agent:
105 match = u"opwv_v72_generic"
106 elif u"UP.Browser/7" in user_agent:
107 match = u"opwv_v7_generic"
108 elif u"UP.Browser/6.2" in user_agent:
109 match = u"opwv_v62_generic"
110 elif u"UP.Browser/6" in user_agent:
111 match = u"opwv_v6_generic"
112 elif u"UP.Browser/5" in user_agent:
113 match = u"upgui_generic"
114 elif u"UP.Browser/4" in user_agent:
115 match = u"uptext_generic"
116 elif u"UP.Browser/3" in user_agent:
117 match = u"uptext_generic"
118
119
120 elif u"Series60" in user_agent:
121 match = u"nokia_generic_series60"
122
123
124 elif u"NetFront/3.0" in user_agent or u"ACS-NF/3.0" in user_agent:
125 match = u"netfront_ver3"
126 elif u"NetFront/3.1" in user_agent or u"ACS-NF/3.1" in user_agent:
127 match = u"netfront_ver3_1"
128 elif u"NetFront/3.2" in user_agent or u"ACS-NF/3.2" in user_agent:
129 match = u"netfront_ver3_2"
130 elif u"NetFront/3.3" in user_agent or u"ACS-NF/3.3" in user_agent:
131 match = u"netfront_ver3_3"
132 elif u"NetFront/3.4" in user_agent:
133 match = u"netfront_ver3_4"
134 elif u"NetFront/3.5" in user_agent:
135 match = u"netfront_ver3_5"
136
137
138 elif u"Windows CE" in user_agent:
139 match = u"ms_mobile_browser_ver1"
140
141
142 elif u"Mozilla/4.0" in user_agent:
143 match = u"generic_web_browser"
144 elif u"Mozilla/5.0" in user_agent:
145 match = u"generic_web_browser"
146 elif u"Mozilla/6.0" in user_agent:
147 match = u"generic_web_browser"
148
149
150 elif u"Mozilla/" in user_agent:
151 match = u"generic_xhtml"
152
153 elif (u"ObigoInternetBrowser/Q03C" in user_agent or
154 u"AU-MIC/2" in user_agent or
155 u"AU-MIC-" in user_agent or
156 u"AU-OBIGO/" in user_agent or
157 u"Obigo/Q03" in user_agent or
158 u"Obigo/Q04" in user_agent or
159 u"ObigoInternetBrowser/2" in user_agent or
160 u"Teleca Q03B1" in user_agent):
161 match = u"generic_xhtml"
162
163
164 elif u"Opera Mini/1" in user_agent:
165 match = u"opera_mini_ver1"
166 elif u"Opera Mini/2" in user_agent:
167 match = u"opera_mini_ver2"
168 elif u"Opera Mini/3" in user_agent:
169 match = u"opera_mini_ver3"
170 elif u"Opera Mini/4" in user_agent:
171 match = u"opera_mini_ver4"
172
173
174 elif user_agent.startswith(u"DoCoMo") or user_agent.startswith(u"KDDI"):
175 match = u"docomo_generic_jap_ver1"
176
177 return match
178
182 return (user_agent.startswith(u"Alcatel") or
183 user_agent.startswith(u"ALCATEL"))
184
188 return u"Android" in user_agent
189
191 tolerance = uiol(user_agent, u" ", uiol(user_agent, u"Android"))
192 match = ris_match(self.user_agents, user_agent, tolerance)
193
194 return match
195
200
203 APPLE_LD_TOLLERANCE = 5
204
206 return u"iPhone" in user_agent or u"iPod" in user_agent
207
212
214 if u"iPhone" in user_agent:
215 return u"apple_iphone_ver1"
216 return u"apple_ipod_touch_ver1"
217
221 return user_agent.startswith(u"BenQ") or user_agent.startswith(u"BENQ")
222
226 return u"BlackBerry" in user_agent
227
229 match = u"generic"
230
231 if user_agent.startswith("BlackBerry"):
232 try:
233 position = user_agent.index('/')
234 if position + 4 < len(user_agent):
235 version = user_agent[position+1:position+4]
236 if version.startswith(u"2."):
237 match = u"blackberry_generic_ver2"
238 elif version.startswith(u"3.2"):
239 match = u"blackberry_generic_ver3_sub2"
240 elif version.startswith(u"3.3"):
241 match = u"blackberry_generic_ver3_sub30"
242 elif version.startswith(u"3.5"):
243 match = u"blackberry_generic_ver3_sub50"
244 elif version.startswith(u"3.6"):
245 match = u"blackberry_generic_ver3_sub60"
246 elif version.startswith(u"3.7"):
247 match = u"blackberry_generic_ver3_sub70"
248 elif version.startswith(u"4."):
249 match = u"blackberry_generic_ver4"
250 except ValueError:
251 pass
252
253 return match
254
257 bots = (u"bot", u"crawler", u"novarra", u"transcoder")
258
260 user_agent = user_agent.lower()
261 for bot in self.bots:
262 if bot in user_agent:
263 return True
264 return False
265
292
298
302 return user_agent.startswith(u"DoCoMo")
303
306
308 return u"docomo_generic_jap_ver1"
309
315
319 return (user_agent.startswith(u"Grundig") or
320 user_agent.startswith(u"GRUNDIG"))
321
325 return user_agent.startswith(u"HTC")
326
330 return user_agent.startswith(u"KDDI")
331
341
343 return u"opwv_v62_generic"
344
350
354 return (user_agent.startswith(u"kyocera") or
355 user_agent.startswith(u"QC-") or
356 user_agent.startswith(u"KWC-"))
357
361 return user_agent.startswith(u"LG") or user_agent.startswith(u"lg")
362
372
376 return user_agent.startswith(u"Mitsu")
377
380 MOTOROLA_TOLERANCE = 5
381
383 return (user_agent.startswith(u"Mot-") or
384 u"MOT-" in user_agent or
385 u"Motorola" in user_agent)
386
397
399 if u"MIB/2.2" in user_agent or u"MIB/BER2.2" in user_agent:
400 match = u"mot_mib22_generic"
401 else:
402 match = u"generic"
403 return match
404
408 return (not utils.is_mobile_browser(user_agent) and
409 user_agent.startswith(u"Mozilla") and
410 u"MSIE" in user_agent)
411
414
415 NEC_LD_TOLERANCE = 2
416
418 return user_agent.startswith(u"NEC") or user_agent.startswith(u"KGT")
419
429
433 return u"Nokia" in user_agent
434
436 tolerance = uiol(user_agent, u"/", user_agent.index(u"Nokia"))
437
438 match = ris_match(self.user_agents, user_agent, tolerance)
439
440 return match
441
443 if u"Series60" in user_agent:
444 match = u"nokia_generic_series60"
445 elif u"Series80" in user_agent:
446 match = u"nokia_generic_series80"
447 else:
448 match = u"generic"
449
463
467 return u"Opera Mini" in user_agent
468
470 match = u""
471 if u"Opera Mini/1" in user_agent:
472 match = u"opera_mini_ver1"
473 elif u"Opera Mini/2" in user_agent:
474 match = u"opera_mini_ver2"
475 elif u"Opera Mini/3" in user_agent:
476 match = u"opera_mini_ver3"
477 elif u"Opera Mini/4" in user_agent:
478 match = u"opera_mini_ver4"
479
480 return match
481
485 return user_agent.startswith(u"Panasonic")
486
489
490 PANTECH_LD_TOLERANCE = 4
491
493 return (user_agent.startswith(u"Pantech") or
494 user_agent.startswith(u"PT-") or
495 user_agent.startswith(u"PANTECH") or
496 user_agent.startswith(u"PG-"))
497
507
511 return (user_agent.startswith(u"Philips") or
512 user_agent.startswith(u"PHILIPS"))
513
517 return user_agent.startswith(u"portalmmm")
518
521
525 return user_agent.startswith(u"Qtek")
526
530 return (not utils.is_mobile_browser(user_agent) and
531 user_agent.startswith(u"Mozilla") and
532 u"Safari" in user_agent)
533
535 if u"Macintosh" in user_agent or u"Windows" in user_agent:
536 match = u"generic_web_browser"
537 else:
538 match = u"generic"
539 return match
540
545 return (user_agent.startswith(u"Sagem") or
546 user_agent.startswith(u"SAGEM"))
547
551 return (u"Samsung/SGH" in user_agent or
552 user_agent.startswith(u"SEC-") or
553 user_agent.startswith(u"Samsung") or
554 user_agent.startswith(u"SAMSUNG") or
555 user_agent.startswith(u"SPH") or
556 user_agent.startswith(u"SGH") or
557 user_agent.startswith(u"SCH"))
558
580
584 return (user_agent.startswith(u"Sanyo") or
585 user_agent.startswith(u"SANYO"))
586
590 return (user_agent.startswith(u"Sharp") or
591 user_agent.startswith(u"SHARP"))
592
596 return user_agent.startswith(u"SIE-")
597
601 return u"SonyEricsson" in user_agent
602
612
616 return u"SPV" in user_agent
617
622
626 return user_agent.startswith(u"Toshiba")
627
646
649 WINDOWS_CE_TOLERANCE = 3
650
652 return u"Mozilla/" in user_agent and u"Windows CE" in user_agent
653
658
660 return u"ms_mobile_browser_ver1"
661
662
663 handlers = [VodafoneMatcher(),
664 NokiaMatcher(),
665 SonyEricssonMatcher(),
666 MotorolaMatcher(),
667 BlackberryMatcher(),
668 SiemensMatcher(),
669 SagemMatcher(),
670 SamsungMatcher(),
671 PanasonicMatcher(),
672 NecMatcher(),
673 QtekMatcher(),
674 MitsubishiMatcher(),
675 PhilipsMatcher(),
676 LGMatcher(),
677 AppleMatcher(),
678 KyoceraMatcher(),
679 AlcatelMatcher(),
680 SharpMatcher(),
681 SanyoMatcher(),
682 BenQMatcher(),
683 PantechMatcher(),
684 ToshibaMatcher(),
685 GrundigMatcher(),
686 HTCMatcher(),
687 SPVMatcher(),
688 WindowsCEMatcher(),
689 PortalmmmMatcher(),
690 DoCoMoMatcher(),
691 KDDIMatcher(),
692 AndroidMatcher(),
693 OperaMiniMatcher(),
694 BotMatcher(),
695 ChromeMatcher(normalizers.chrome),
696 AOLMatcher(),
697 OperaMatcher(normalizers.opera),
698 KonquerorMatcher(normalizers.konqueror),
699 SafariMatcher(normalizers.safari),
700 FirefoxMatcher(normalizers.firefox),
701 MSIEMatcher(normalizers.msie),
702 CatchAllMatcher()]
703