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.1"
37
38 import re
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
77
84
91
94
95 recovery_map = (
96
97 (u"UP.Browser/7.2", u"opwv_v72_generic"),
98 (u"UP.Browser/7", u"opwv_v7_generic"),
99 (u"UP.Browser/6.2", u"opwv_v62_generic"),
100 (u"UP.Browser/6", u"opwv_v6_generic"),
101 (u"UP.Browser/5", u"upgui_generic"),
102 (u"UP.Browser/4", u"uptext_generic"),
103 (u"UP.Browser/3", u"uptext_generic"),
104
105
106 (u"Series60", u"nokia_generic_series60"),
107
108
109 (u"NetFront/3.0", u"netfront_ver3"),
110 (u"ACS-NF/3.0", u"netfront_ver3"),
111 (u"NetFront/3.1", u"netfront_ver3_1"),
112 (u"ACS-NF/3.1", u"netfront_ver3_1"),
113 (u"NetFront/3.2", u"netfront_ver3_2"),
114 (u"ACS-NF/3.2", u"netfront_ver3_2"),
115 (u"NetFront/3.3", u"netfront_ver3_3"),
116 (u"ACS-NF/3.3", u"netfront_ver3_3"),
117 (u"NetFront/3.4", u"netfront_ver3_4"),
118 (u"NetFront/3.5", u"netfront_ver3_5"),
119
120
121 (u"Windows CE", u"ms_mobile_browser_ver1"),
122
123
124 (u"Mozilla/4.0", u"generic_web_browser"),
125 (u"Mozilla/5.0", u"generic_web_browser"),
126 (u"Mozilla/5.0", u"generic_web_browser"),
127
128
129 (u"Mozilla/", u"generic_xhtml"),
130 (u"ObigoInternetBrowser/Q03C", u"generic_xhtml"),
131 (u"AU-MIC/2", u"generic_xhtml"),
132 (u"AU-MIC-", u"generic_xhtml"),
133 (u"AU-OBIGO/", u"generic_xhtml"),
134 (u"Obigo/Q03", u"generic_xhtml"),
135 (u"Obigo/Q04", u"generic_xhtml"),
136 (u"ObigoInternetBrowser/2", u"generic_xhtml"),
137 (u"Teleca Q03B1", u"generic_xhtml"),
138
139
140 (u"Opera Mini/1", u"opera_mini_ver1"),
141 (u"Opera Mini/2", u"opera_mini_ver2"),
142 (u"Opera Mini/3", u"opera_mini_ver3"),
143 (u"Opera Mini/4", u"opera_mini_ver4"),
144
145
146 (u"DoCoMo", u"docomo_generic_jap_ver1"),
147 (u"KDDI", u"docomo_generic_jap_ver1"))
148
150
151 match = u"generic"
152 for partial_agent, wdevice in self.recovery_map:
153 if partial_agent in user_agent:
154 match = wdevice
155 break
156 return match
157
161 return (user_agent.startswith(u"Alcatel") or
162 user_agent.startswith(u"ALCATEL"))
163
167 return u"Android" in user_agent
168
170 tolerance = uiol(user_agent, u" ",
171 start_index=uiol(user_agent, u"Android"))
172 match = ris_match(self.user_agents, user_agent, tolerance)
173
174 return match
175
177 return u"generic_android"
178
183
186 APPLE_LD_TOLERANCE = 5
187
189 return (u"iPhone" in user_agent or u"iPod" in user_agent or u"iPad" in
190 user_agent)
191
197
199 if u"iPad" in user_agent:
200 return "apple_ipad_ver1"
201 if u"iPod" in user_agent:
202 return u"apple_ipod_ver1"
203 return u"apple_iphone_ver1"
204
208 return user_agent.startswith(u"BENQ") or user_agent.startswith(u"BenQ")
209
212 blackberries = {}
213 blackberries["2."] = u"blackberry_generic_ver2"
214 blackberries["3.2"] = u"blackberry_generic_ver3_sub2"
215 blackberries["3.3"] = u"blackberry_generic_ver3_sub30"
216 blackberries["3.5"] = u"blackberry_generic_ver3_sub50"
217 blackberries["3.6"] = u"blackberry_generic_ver3_sub60"
218 blackberries["3.7"] = u"blackberry_generic_ver3_sub70"
219 blackberries["4."] = u"blackberry_generic_ver4"
220
222 return u"BlackBerry" in user_agent
223
225 match = u"generic"
226
227 if user_agent.startswith(u"BlackBerry"):
228 version = self.get_version(user_agent)
229 match = self.blackberries.get(version, u"generic")
230
231 return match
232
234 version = u""
235 position = user_agent.index('/')
236 if position + 4 < len(user_agent):
237 version = user_agent[position+1:position+4]
238 return version
239
242 bots = (u"bot", u"crawler", u"spider", u"novarra", u"transcoder",
243 u"yahoo! searchmonkey", u"yahoo! slurp", u"feedfetcher-google",
244 u"toolbar", u"mowser")
245
246 BOT_TOLERANCE = 4
247
249 user_agent = user_agent.lower()
250 for bot in self.bots:
251 if bot in user_agent:
252 return True
253 return False
254
258
260 return u"generic_web_crawler"
261
288
294
298 return user_agent.startswith(u"DoCoMo")
299
302
304 if user_agent.startswith(u"DoCoMo/2"):
305 return u"docomo_generic_jap_ver2"
306 return u"docomo_generic_jap_ver1"
307
313
317 return (user_agent.startswith(u"Grundig") or
318 user_agent.startswith(u"GRUNDIG"))
319
323 return user_agent.startswith(u"HTC")
324
328 return u"KDDI" in user_agent
329
341
343 if u"Opera" in user_agent:
344 return u"opera"
345 return u"opwv_v62_generic"
346
352
356 return (user_agent.startswith(u"kyocera") or
357 user_agent.startswith(u"QC-") or
358 user_agent.startswith(u"KWC-"))
359
363 return (user_agent.startswith(u"lg") or u"LG-" in user_agent or
364 u"LGE" in user_agent)
365
367 if u"Vodafone" in user_agent:
368 tolerance = uiol(user_agent, u"LG")
369 elif user_agent.startswith(u"LGE/") or user_agent.startswith("LG/"):
370 tolerance = utils.second_slash(user_agent)
371 else:
372 tolerance = utils.first_slash(user_agent)
373
374 return ris_match(self.user_agents, user_agent, tolerance)
375
379 return user_agent.startswith(u"Mitsu")
380
383 MOTOROLA_TOLERANCE = 5
384
386 return (user_agent.startswith(u"Mot-") or
387 u"MOT-" in user_agent or
388 u"Motorola" in user_agent)
389
400
402 if u"MIB/2.2" in user_agent or u"MIB/BER2.2" in user_agent:
403 match = u"mot_mib22_generic"
404 else:
405 match = u"generic"
406 return match
407
411 return (not utils.is_mobile_browser(user_agent) and
412 user_agent.startswith(u"Mozilla") and
413 u"MSIE" in user_agent)
414
417
418 NEC_LD_TOLERANCE = 2
419
421 return user_agent.startswith(u"NEC") or user_agent.startswith(u"KGT")
422
432
436 return u"Nokia" in user_agent
437
439 tolerance = uiol(user_agent, u"/",
440 start_index=user_agent.index(u"Nokia"))
441
442 match = ris_match(self.user_agents, user_agent, tolerance)
443
444 return match
445
447 if u"Series60" in user_agent:
448 match = u"nokia_generic_series60"
449 elif u"Series80" in user_agent:
450 match = u"nokia_generic_series80"
451 else:
452 match = u"generic"
453 return match
454
482
486 return u"Opera Mini" in user_agent
487
489 match = u""
490 if u"Opera Mini/1" in user_agent:
491 match = u"opera_mini_ver1"
492 elif u"Opera Mini/2" in user_agent:
493 match = u"opera_mini_ver2"
494 elif u"Opera Mini/3" in user_agent:
495 match = u"opera_mini_ver3"
496 elif u"Opera Mini/4" in user_agent:
497 match = u"opera_mini_ver4"
498 return match
499
503 return user_agent.startswith(u"Panasonic")
504
507
508 PANTECH_LD_TOLERANCE = 4
509
511 return (user_agent.startswith(u"Pantech") or
512 user_agent.startswith(u"PT-") or
513 user_agent.startswith(u"PANTECH") or
514 user_agent.startswith(u"PG-"))
515
525
529 return (user_agent.startswith(u"Philips") or
530 user_agent.startswith(u"PHILIPS"))
531
535 return user_agent.startswith(u"portalmmm")
536
539
543 return user_agent.startswith(u"Qtek")
544
548 return (not utils.is_mobile_browser(user_agent) and
549 user_agent.startswith(u"Mozilla") and
550 u"Safari" in user_agent)
551
553 if u"Macintosh" in user_agent or u"Windows" in user_agent:
554 match = u"generic_web_browser"
555 else:
556 match = u"generic"
557 return match
558
562 return (user_agent.startswith(u"Sagem") or
563 user_agent.startswith(u"SAGEM"))
564
568 return (u"Samsung/SGH" in user_agent or
569 user_agent.startswith(u"SEC-") or
570 user_agent.startswith(u"Samsung") or
571 user_agent.startswith(u"SAMSUNG") or
572 user_agent.startswith(u"SPH") or
573 user_agent.startswith(u"SGH") or
574 user_agent.startswith(u"SCH"))
575
577 if (user_agent.startswith(u"SEC-") or
578 user_agent.startswith(u"SAMSUNG-") or
579 user_agent.startswith(u"SCH")):
580 tolerance = utils.first_slash(user_agent)
581 elif (user_agent.startswith(u"Samsung") or
582 user_agent.startswith(u"SPH") or
583 user_agent.startswith(u"SGH")):
584 tolerance = utils.first_space(user_agent)
585 elif user_agent.startswith(u"SAMSUNG/"):
586 tolerance = utils.second_slash(user_agent)
587 elif u"Samsung/SGH-L870" in user_agent:
588 tolerance = uiol(user_agent, u"/", 5)
589 else:
590 tolerance = len(user_agent)
591 match = ris_match(self.user_agents, user_agent, tolerance)
592
593 return match
594
598 return (user_agent.startswith(u"Sanyo") or
599 user_agent.startswith(u"SANYO"))
600
604 return (user_agent.startswith(u"Sharp") or
605 user_agent.startswith(u"SHARP"))
606
610 return user_agent.startswith(u"SIE-")
611
615 return u"SonyEricsson" in user_agent
616
626
630 return u"SPV" in user_agent
631
633 tolerance = uiol(user_agent, u";", start_index=uiol(user_agent, u"SPV"))
634 match = ris_match(self.user_agents, user_agent, tolerance)
635 return match
636
640 return user_agent.startswith(u"Toshiba")
641
644
646 return user_agent.startswith(u"Vodafone")
647
653
656 WINDOWS_CE_TOLERANCE = 3
657
659 return u"Mozilla/" in user_agent and (u"Windows CE" in user_agent or
660 u"WindowsCE" in user_agent)
661
666
668 return u"ms_mobile_browser_ver1"
669
670
671 handlers = [NokiaMatcher(),
672 AndroidMatcher(normalizers.android),
673 SonyEricssonMatcher(),
674 MotorolaMatcher(),
675 BlackberryMatcher(),
676 SiemensMatcher(),
677 SagemMatcher(),
678 SamsungMatcher(),
679 PanasonicMatcher(),
680 NecMatcher(),
681 QtekMatcher(),
682 MitsubishiMatcher(),
683 PhilipsMatcher(),
684 LGMatcher(),
685 AppleMatcher(),
686 KyoceraMatcher(),
687 AlcatelMatcher(),
688 SharpMatcher(),
689 SanyoMatcher(),
690 BenQMatcher(),
691 PantechMatcher(),
692 ToshibaMatcher(),
693 GrundigMatcher(),
694 HTCMatcher(),
695 BotMatcher(),
696 SPVMatcher(),
697 WindowsCEMatcher(),
698 PortalmmmMatcher(),
699 DoCoMoMatcher(),
700 KDDIMatcher(),
701 VodafoneMatcher(),
702 OperaMiniMatcher(),
703 ChromeMatcher(normalizers.chrome),
704 AOLMatcher(),
705 OperaMatcher(normalizers.opera),
706 KonquerorMatcher(normalizers.konqueror),
707 SafariMatcher(normalizers.safari),
708 FirefoxMatcher(normalizers.firefox),
709 MSIEMatcher(normalizers.msie),
710 CatchAllMatcher()]
711