Package pywurfl :: Package algorithms :: Package wurfl :: Module handlers
[hide private]
[frames] | no frames]

Source Code for Module pywurfl.algorithms.wurfl.handlers

  1  # pywurfl - Wireless Universal Resource File Tools in Python 
  2  # Copyright (C) 2006-2011 Armand Lynch 
  3  # 
  4  # This library is free software; you can redistribute it and/or modify it 
  5  # under the terms of the GNU Lesser General Public License as published by the 
  6  # Free Software Foundation; either version 2.1 of the License, or (at your 
  7  # option) any later version. 
  8  # 
  9  # This library is distributed in the hope that it will be useful, but WITHOUT 
 10  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
 11  # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 
 12  # details. 
 13  # 
 14  # You should have received a copy of the GNU Lesser General Public License 
 15  # along with this library; if not, write to the Free Software Foundation, Inc., 
 16  # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 17  # 
 18  # Armand Lynch <lyncha@users.sourceforge.net> 
 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) WURFL-Pro srl 
 30  """ 
 31   
 32  __author__ = "Armand Lynch <lyncha@users.sourceforge.net>" 
 33  __copyright__ = "Copyright 2011, Armand Lynch" 
 34  __license__ = "LGPL" 
 35  __url__ = "http://celljam.net/" 
 36  __version__ = "1.2.1" 
 37   
 38  import re 
 39   
 40  from pywurfl.algorithms.wurfl.utils import (first_semi_colon, first_slash, 
 41                                              first_space, is_mobile_browser, 
 42                                              second_slash, third_space) 
 43  from pywurfl.algorithms.wurfl.utils import indexof_or_length as iol 
 44  from pywurfl.algorithms.wurfl import normalizers 
 45  from pywurfl.algorithms.wurfl.strategies import ld_match, ris_match 
46 47 48 -class AbstractMatcher(object):
49 user_agent_map = {} 50
51 - def __init__(self, normalizer=normalizers.generic):
52 self.normalizer = normalizer 53 self.known_user_agents = set()
54
55 - def add(self, user_agent, wurfl_id):
56 self.known_user_agents.add(user_agent) 57 self.user_agent_map[user_agent] = wurfl_id
58 59 @property
60 - def user_agents(self):
61 return sorted(self.known_user_agents)
62
63 - def can_handle(self, user_agent):
64 raise NotImplementedError
65
66 - def __call__(self, user_agent):
67 normalized_user_agent = self.normalizer(user_agent) 68 devid = self.conclusive_match(normalized_user_agent) 69 if not devid or devid == u"generic": 70 devid = self.recovery_match(normalized_user_agent) 71 if not devid or devid == u"generic": 72 devid = self.catch_all_recovery_match(user_agent) 73 return devid
74
75 - def conclusive_match(self, user_agent):
76 match = self.find_matching_ua(user_agent) 77 #print "%s -> conclusive_match -> %s" % (user_agent, match) 78 devid = self.user_agent_map.get(match, u"generic") 79 return devid
80
81 - def find_matching_ua(self, user_agent):
82 tolerance = first_slash(user_agent) 83 match = self.ris_matcher(user_agent, tolerance) 84 #print "AbstractMatcher %s -> f_m_ua -> %s" % (user_agent, match) 85 return match
86
87 - def recovery_match(self, user_agent):
88 return u"generic"
89 90 recovery_map = ( 91 # Openwave 92 (u"UP.Browser/7.2", u"opwv_v72_generic"), 93 (u"UP.Browser/7", u"opwv_v7_generic"), 94 (u"UP.Browser/6.2", u"opwv_v62_generic"), 95 (u"UP.Browser/6", u"opwv_v6_generic"), 96 (u"UP.Browser/5", u"upgui_generic"), 97 (u"UP.Browser/4", u"uptext_generic"), 98 (u"UP.Browser/3", u"uptext_generic"), 99 100 # Series 60 101 (u"Series60", u"nokia_generic_series60"), 102 103 # Access/Net Front 104 (u"NetFront/3.0", u"generic_netfront_ver3"), 105 (u"ACS-NF/3.0", u"generic_netfront_ver3"), 106 (u"NetFront/3.1", u"generic_netfront_ver3_1"), 107 (u"ACS-NF/3.1", u"generic_netfront_ver3_1"), 108 (u"NetFront/3.2", u"generic_netfront_ver3_2"), 109 (u"ACS-NF/3.2", u"generic_netfront_ver3_2"), 110 (u"NetFront/3.3", u"generic_netfront_ver3_3"), 111 (u"ACS-NF/3.3", u"generic_netfront_ver3_3"), 112 (u"NetFront/3.4", u"generic_netfront_ver3_4"), 113 (u"NetFront/3.5", u"generic_netfront_ver3_5"), 114 (u"NetFront/4.0", u"generic_netfront_ver4"), 115 (u"NetFront/4.1", u"generic_netfront_ver4_1"), 116 117 # Windows CE 118 (u"Windows CE", u"generic_ms_mobile_browser_ver1"), 119 120 # web browsers? 121 (u"Mozilla/4.0", u"generic_web_browser"), 122 (u"Mozilla/5.0", u"generic_web_browser"), 123 (u"Mozilla/6.0", u"generic_web_browser"), 124 125 # Generic XHTML 126 (u"Mozilla/", u"generic_xhtml"), 127 (u"ObigoInternetBrowser/Q03C", u"generic_xhtml"), 128 (u"AU-MIC/2", u"generic_xhtml"), 129 (u"AU-MIC-", u"generic_xhtml"), 130 (u"AU-OBIGO/", u"generic_xhtml"), 131 (u"Obigo/Q03", u"generic_xhtml"), 132 (u"Obigo/Q04", u"generic_xhtml"), 133 (u"ObigoInternetBrowser/2", u"generic_xhtml"), 134 (u"Teleca Q03B1", u"generic_xhtml"), 135 136 # Opera Mini 137 (u"Opera Mini/1", u"browser_opera_mini_release1"), 138 (u"Opera Mini/2", u"browser_opera_mini_release2"), 139 (u"Opera Mini/3", u"browser_opera_mini_release3"), 140 (u"Opera Mini/4", u"browser_opera_mini_release4"), 141 (u"Opera Mini/5", u"browser_opera_mini_release5"), 142 143 # DoCoMo 144 (u"DoCoMo", u"docomo_generic_jap_ver1"), 145 (u"KDDI", u"docomo_generic_jap_ver1")) 146
147 - def catch_all_recovery_match(self, user_agent):
148 149 match = u"generic" 150 for partial_agent, wdevice in self.recovery_map: 151 if partial_agent in user_agent: 152 match = wdevice 153 break 154 return match
155
156 - def ris_matcher(self, user_agent, tolerance):
157 return ris_match(self.user_agents, user_agent, tolerance)
158
159 - def ld_matcher(self, user_agent, tolerance):
160 return ld_match(self.user_agents, user_agent, tolerance)
161
162 163 -class AlcatelMatcher(AbstractMatcher):
164 - def can_handle(self, user_agent):
165 return (user_agent.startswith(u"Alcatel") or 166 user_agent.startswith(u"ALCATEL"))
167
168 169 -class AndroidMatcher(AbstractMatcher):
170 171 androids = {} 172 androids[u""] = u"generic_android" 173 androids[u"1_5"] = u"generic_android_ver1_5" 174 androids[u"1_6"] = u"generic_android_ver1_6" 175 androids[u"2_0"] = u"generic_android_ver2" 176 androids[u"2_1"] = u"generic_android_ver2_1" 177 androids[u"2_2"] = u"generic_android_ver2_2" 178 179 android_os_re = re.compile(r".*Android[\s/](\d)\.(\d)") 180
181 - def can_handle(self, user_agent):
182 return user_agent.startswith(u"Mozilla") and u"Android" in user_agent
183
184 - def find_matching_ua(self, user_agent):
185 tolerance = iol(user_agent, u" ", 186 start_index=iol(user_agent, u"Android")) 187 match = self.ris_matcher(user_agent, tolerance) 188 #print "AndroidMatcher %s -> f_m_ua -> %s" % (user_agent, match) 189 return match
190
191 - def recovery_match(self, user_agent):
192 if u"Froyo" in user_agent: 193 return u"generic_android_ver2_2" 194 return self.androids.get(self.android_os_version(user_agent), 195 u"generic_android")
196
197 - def android_os_version(self, user_agent):
198 match = self.android_os_re.match(user_agent) 199 if match: 200 return u"%s_%s" % (match.group(1), match.group(2))
201
202 203 -class AOLMatcher(AbstractMatcher):
204 - def can_handle(self, user_agent):
205 return not is_mobile_browser(user_agent) and u"AOL" in user_agent
206
207 208 -class AppleMatcher(AbstractMatcher):
209 APPLE_LD_TOLERANCE = 5 210
211 - def can_handle(self, user_agent):
212 return (u"iPhone" in user_agent or u"iPod" in user_agent or u"iPad" in 213 user_agent)
214
215 - def find_matching_ua(self, user_agent):
216 if user_agent.startswith(u"Apple"): 217 tolerance = third_space(user_agent) 218 else: 219 tolerance = first_semi_colon(user_agent) 220 match = self.ris_matcher(user_agent, tolerance) 221 #print "AppleMatcher %s -> f_m_ua -> %s" % (user_agent, match) 222 return match
223
224 - def recovery_match(self, user_agent):
225 if u"iPad" in user_agent: 226 return "apple_ipad_ver1" 227 if u"iPod" in user_agent: 228 return u"apple_ipod_touch_ver1" 229 return u"apple_iphone_ver1"
230
231 232 -class BenQMatcher(AbstractMatcher):
233 - def can_handle(self, user_agent):
234 return user_agent.startswith(u"BENQ") or user_agent.startswith(u"BenQ")
235
236 237 -class BlackberryMatcher(AbstractMatcher):
238 blackberries = {} 239 blackberries[u"2."] = u"blackberry_generic_ver2" 240 blackberries[u"3.2"] = u"blackberry_generic_ver3_sub2" 241 blackberries[u"3.3"] = u"blackberry_generic_ver3_sub30" 242 blackberries[u"3.5"] = u"blackberry_generic_ver3_sub50" 243 blackberries[u"3.6"] = u"blackberry_generic_ver3_sub60" 244 blackberries[u"3.7"] = u"blackberry_generic_ver3_sub70" 245 blackberries[u"4.1"] = u"blackberry_generic_ver4_sub10" 246 blackberries[u"4.2"] = u"blackberry_generic_ver4_sub20" 247 blackberries[u"4.3"] = u"blackberry_generic_ver4_sub30" 248 blackberries[u"4.5"] = u"blackberry_generic_ver4_sub50" 249 blackberries[u"4.6"] = u"blackberry_generic_ver4_sub60" 250 blackberries[u"4.7"] = u"blackberry_generic_ver4_sub70" 251 blackberries[u"4."] = u"blackberry_generic_ver4" 252 blackberries[u"5."] = u"blackberry_generic_ver5" 253 blackberries[u"6."] = u"blackberry_generic_ver6" 254 255 blackberry_os_re = re.compile(r".*Black[Bb]erry[^/\s]+/(\d\.\d)") 256
257 - def can_handle(self, user_agent):
258 return u"BlackBerry" in user_agent or u"Blackberry" in user_agent
259
260 - def recovery_match(self, user_agent):
261 match = u"generic" 262 version = self.blackberry_os_version(user_agent) 263 if version: 264 match = self.blackberries.get(version, u"generic") 265 if match == u"generic": 266 match = self.blackberries.get(version[:-1], u"generic") 267 return match
268
269 - def blackberry_os_version(self, user_agent):
270 match = self.blackberry_os_re.match(user_agent) 271 if match: 272 return match.group(1)
273
274 275 -class BotMatcher(AbstractMatcher):
276 bots = (u"bot", u"crawler", u"spider", u"novarra", u"transcoder", 277 u"yahoo! searchmonkey", u"yahoo! slurp", u"feedfetcher-google", 278 u"toolbar", u"mowser", u"mediapartners-google", u"azureus", 279 u"inquisitor", u"baiduspider", u"baidumobaider", u"indy library", 280 u"slurp", u"crawl", u"wget", u"ucweblient", u"snoopy", 281 u"mozfdsilla", u"ask jeeves", u"jeeves/teoma", u"mechanize", 282 u"http client", u"servicemonitor", u"httpunit", u"hatena", 283 u"ichiro") 284 285 BOT_TOLERANCE = 4 286
287 - def can_handle(self, user_agent):
288 user_agent = user_agent.lower() 289 for bot in self.bots: 290 if bot in user_agent: 291 return True 292 return False
293
294 - def find_matching_ua(self, user_agent):
295 match = self.ld_matcher(user_agent, self.BOT_TOLERANCE) 296 return match
297
298 - def recovery_match(self, user_agent):
299 return u"generic_web_crawler"
300
301 302 -class CatchAllMatcher(AbstractMatcher):
303 MOZILLA_LD_TOLERANCE = 4 304
305 - def can_handle(self, user_agent):
306 return True
307
308 - def find_matching_ua(self, user_agent):
309 if user_agent.startswith(u"Mozilla"): 310 if user_agent.startswith(u"Mozilla/4"): 311 match = ld_match(self.extract_uas(u"Mozilla/4"), user_agent, 312 self.MOZILLA_LD_TOLERANCE) 313 elif user_agent.startswith(u"Mozilla/5"): 314 match = ld_match(self.extract_uas(u"Mozilla/5"), user_agent, 315 self.MOZILLA_LD_TOLERANCE) 316 else: 317 match = ld_match(self.extract_uas(u"Mozilla"), user_agent, 318 self.MOZILLA_LD_TOLERANCE) 319 else: 320 match = super(CatchAllMatcher, self).find_matching_ua(user_agent) 321 #print "CatchAllMatcher %s -> f_m_ua -> %s" % (user_agent, match) 322 return match
323
324 - def extract_uas(self, start):
325 return (x for x in self.user_agents if x.startswith(start))
326
327 328 -class ChromeMatcher(AbstractMatcher):
329 - def can_handle(self, user_agent):
330 return not is_mobile_browser(user_agent) and u"Chrome" in user_agent
331
332 333 -class DoCoMoMatcher(AbstractMatcher):
334 - def can_handle(self, user_agent):
335 return user_agent.startswith(u"DoCoMo")
336
337 - def find_matching_ua(self, user_agent):
338 return u""
339
340 - def recovery_match(self, user_agent):
341 if user_agent.startswith(u"DoCoMo/2"): 342 return u"docomo_generic_jap_ver2" 343 return u"docomo_generic_jap_ver1"
344
345 346 -class FirefoxMatcher(AbstractMatcher):
347 - def can_handle(self, user_agent):
348 return not is_mobile_browser(user_agent) and u"Firefox" in user_agent
349
350 351 -class GrundigMatcher(AbstractMatcher):
352 - def can_handle(self, user_agent):
353 return (user_agent.startswith(u"Grundig") or 354 user_agent.startswith(u"GRUNDIG"))
355
356 357 -class HTCMatcher(AbstractMatcher):
358 - def can_handle(self, user_agent):
359 return user_agent.startswith(u"HTC") or u"XV6875.1" in user_agent
360
361 362 -class KDDIMatcher(AbstractMatcher):
363 - def can_handle(self, user_agent):
364 return u"KDDI" in user_agent
365
366 - def find_matching_ua(self, user_agent):
367 if user_agent.startswith(u"KDDI/"): 368 tolerance = second_slash(user_agent) 369 elif user_agent.startswith(u"KDDI"): 370 tolerance = first_slash(user_agent) 371 else: 372 tolerance = iol(user_agent, ")") 373 match = self.ris_matcher(user_agent, tolerance) 374 #print "KDDIMatcher %s -> f_m_ua -> %s" % (user_agent, match) 375 return match
376
377 - def recovery_match(self, user_agent):
378 if u"Opera" in user_agent: 379 return u"opera" 380 return u"opwv_v62_generic"
381
382 383 -class KonquerorMatcher(AbstractMatcher):
384 - def can_handle(self, user_agent):
385 return not is_mobile_browser(user_agent) and u"Konqueror" in user_agent
386
387 388 -class KyoceraMatcher(AbstractMatcher):
389 - def can_handle(self, user_agent):
390 return (user_agent.startswith(u"kyocera") or 391 user_agent.startswith(u"QC-") or 392 user_agent.startswith(u"KWC-"))
393
394 395 -class LGMatcher(AbstractMatcher):
396 - def can_handle(self, user_agent):
397 return (user_agent.startswith(u"lg") or u"LG-" in user_agent or 398 u"LGE" in user_agent)
399
400 - def find_matching_ua(self, user_agent):
401 tolerance = iol(user_agent, u"/", 402 start_index=user_agent.upper().index(u"LG")) 403 match = self.ris_matcher(user_agent, tolerance) 404 return match
405
406 407 -class LGUPLUSMatcher(AbstractMatcher):
408 lgpluses = ( 409 (u"generic_lguplus_rexos_facebook_browser", 410 (u"Windows NT 5", u"POLARIS")), 411 (u"generic_lguplus_rexos_webviewer_browser", 412 (u"Windows NT 5",)), 413 (u"generic_lguplus_winmo_facebook_browser", 414 (u"Windows CE", u"POLARIS")), 415 (u"generic_lguplus_android_webkit_browser", 416 (u"Android", u"AppleWebKit"))) 417
418 - def can_handle(self, user_agent):
419 return u"lgtelecom" in user_agent or u"LGUPLUS" in user_agent
420
421 - def conclusive_match(self, user_agent):
422 return u"generic"
423
424 - def recovery_match(self, user_agent):
425 for wid, searches in self.lgpluses: 426 for search in searches: 427 if search not in user_agent: 428 break 429 else: 430 return wid 431 return u"generic_lguplus"
432
433 434 -class MaemoMatcher(AbstractMatcher):
435 - def can_handle(self, user_agent):
436 return u"Maemo " in user_agent
437
438 - def find_matching_ua(self, user_agent):
439 tolerance = first_space(user_agent) 440 match = self.ris_matcher(user_agent, tolerance) 441 return match
442
443 444 -class MitsubishiMatcher(AbstractMatcher):
445 - def can_handle(self, user_agent):
446 return user_agent.startswith(u"Mitsu")
447
448 449 -class MotorolaMatcher(AbstractMatcher):
450 MOTOROLA_TOLERANCE = 5 451
452 - def can_handle(self, user_agent):
453 return (user_agent.startswith(u"Mot-") or 454 u"MOT-" in user_agent or 455 u"Motorola" in user_agent)
456
457 - def find_matching_ua(self, user_agent):
458 if (user_agent.startswith(u"Mot-") or user_agent.startswith(u"MOT-") or 459 user_agent.startswith(u"Motorola")): 460 match = super(MotorolaMatcher, self).find_matching_ua(user_agent) 461 else: 462 match = self.ld_matcher(user_agent, self.MOTOROLA_TOLERANCE) 463 #print "MotorolaMatcher %s -> f_m_ua -> %s" % (user_agent, match) 464 return match
465
466 - def recovery_match(self, user_agent):
467 match = u"generic" 468 if u"MIB/2.2" in user_agent or u"MIB/BER2.2" in user_agent: 469 match = u"mot_mib22_generic" 470 return match
471
472 473 -class MSIEMatcher(AbstractMatcher):
474 - def can_handle(self, user_agent):
475 return (not is_mobile_browser(user_agent) and 476 user_agent.startswith(u"Mozilla") and 477 u"MSIE" in user_agent)
478
479 480 -class NecMatcher(AbstractMatcher):
481 NEC_LD_TOLERANCE = 2 482
483 - def can_handle(self, user_agent):
484 return user_agent.startswith(u"NEC") or user_agent.startswith(u"KGT")
485
486 - def find_matching_ua(self, user_agent):
487 if user_agent.startswith(u"NEC"): 488 match = super(NecMatcher, self).find_matching_ua(user_agent) 489 else: 490 match = self.ld_matcher(user_agent, self.NEC_LD_TOLERANCE) 491 #print "NecMatcher %s -> f_m_ua -> %s" % (user_agent, match) 492 return match
493
494 495 -class NokiaMatcher(AbstractMatcher):
496 - def can_handle(self, user_agent):
497 return u"Nokia" in user_agent
498
499 - def find_matching_ua(self, user_agent):
500 tol1 = iol(user_agent, u"/", start_index=user_agent.index(u"Nokia")) 501 tol2 = iol(user_agent, u" ", start_index=user_agent.index(u"Nokia")) 502 tolerance = tol1 if tol1 < tol2 else tol2 503 #print "NokiaMatcher tolerance %s" % tolerance 504 match = self.ris_matcher(user_agent, tolerance) 505 #print "NokiaMatcher %s -> f_m_ua -> %s" % (user_agent, match) 506 return match
507
508 - def recovery_match(self, user_agent):
509 match = u"generic" 510 if u"Series60" in user_agent: 511 match = u"nokia_generic_series60" 512 elif u"Series80" in user_agent: 513 match = u"nokia_generic_series80" 514 return match
515
516 517 -class OperaMatcher(AbstractMatcher):
518 OPERA_TOLERANCE = 1 519 520 operas = {} 521 operas["7"] = u"opera_7" 522 operas["8"] = u"opera_8" 523 operas["9"] = u"opera_9" 524 operas["10"] = u"opera_10" 525 526 opera_re = re.compile(r".*Opera[\s/](\d+).*") 527
528 - def can_handle(self, user_agent):
529 return not is_mobile_browser(user_agent) and u"Opera" in user_agent
530
531 - def find_matching_ua(self, user_agent):
532 match = self.ld_matcher(user_agent, self.OPERA_TOLERANCE) 533 #print "OperaMatcher %s -> f_m_ua -> %s" % (user_agent, match) 534 return match
535
536 - def recovery_match(self, user_agent):
537 match = self.opera_re.match(user_agent) 538 if match: 539 return self.operas.get(match.group(1), u"opera") 540 return u"opera"
541
542 543 -class OperaMiniMatcher(AbstractMatcher):
544 - def can_handle(self, user_agent):
545 return u"Opera Mini" in user_agent
546
547 - def recovery_match(self, user_agent):
548 match = u"" 549 if u"Opera Mini/1" in user_agent: 550 match = u"browser_opera_mini_release1" 551 elif u"Opera Mini/2" in user_agent: 552 match = u"browser_opera_mini_release2" 553 elif u"Opera Mini/3" in user_agent: 554 match = u"browser_opera_mini_release3" 555 elif u"Opera Mini/4" in user_agent: 556 match = u"browser_opera_mini_release4" 557 elif u"Opera Mini/5" in user_agent: 558 match = u"browser_opera_mini_release5" 559 return match
560
561 562 -class PanasonicMatcher(AbstractMatcher):
563 - def can_handle(self, user_agent):
564 return user_agent.startswith(u"Panasonic")
565
566 567 -class PantechMatcher(AbstractMatcher):
568 PANTECH_LD_TOLERANCE = 4 569
570 - def can_handle(self, user_agent):
571 return (user_agent.startswith(u"Pantech") or 572 user_agent.startswith(u"PT-") or 573 user_agent.startswith(u"PANTECH") or 574 user_agent.startswith(u"PG-"))
575
576 - def find_matching_ua(self, user_agent):
577 if user_agent.startswith(u"Pantech"): 578 match = self.ld_matcher(user_agent, self.PANTECH_LD_TOLERANCE) 579 else: 580 match = super(PantechMatcher, self).find_matching_ua(user_agent) 581 #print "PantechMatcher %s -> f_m_ua -> %s" % (user_agent, match) 582 return match
583
584 585 -class PhilipsMatcher(AbstractMatcher):
586 - def can_handle(self, user_agent):
587 return (user_agent.startswith(u"Philips") or 588 user_agent.startswith(u"PHILIPS"))
589
590 591 -class PortalmmmMatcher(AbstractMatcher):
592 - def can_handle(self, user_agent):
593 return user_agent.startswith(u"portalmmm")
594
595 - def find_matching_ua(self, user_agent):
596 return u""
597
598 599 -class QtekMatcher(AbstractMatcher):
600 - def can_handle(self, user_agent):
601 return user_agent.startswith(u"Qtek")
602
603 604 -class SafariMatcher(AbstractMatcher):
605 - def can_handle(self, user_agent):
606 return (not is_mobile_browser(user_agent) and 607 user_agent.startswith(u"Mozilla") and 608 u"Safari" in user_agent)
609
610 - def recovery_match(self, user_agent):
611 if u"Macintosh" in user_agent or u"Windows" in user_agent: 612 match = u"generic_web_browser" 613 else: 614 match = u"generic" 615 return match
616
617 618 -class SagemMatcher(AbstractMatcher):
619 - def can_handle(self, user_agent):
620 return (user_agent.startswith(u"Sagem") or 621 user_agent.startswith(u"SAGEM"))
622
623 624 -class SamsungMatcher(AbstractMatcher):
625 SAMSUNGS = [u"SEC-", u"SAMSUNG-", u"SCH", u"Samsung", u"SPH", u"SGH", 626 u"SAMSUNG/"] 627
628 - def can_handle(self, user_agent):
629 return (u"Samsung/SGH" in user_agent or 630 u"Samsung" in user_agent or 631 user_agent.startswith(u"SEC-") or 632 user_agent.startswith(u"SAMSUNG") or 633 user_agent.startswith(u"SPH") or 634 user_agent.startswith(u"SGH") or 635 user_agent.startswith(u"SCH"))
636
637 - def find_matching_ua(self, user_agent):
638 for sams in self.SAMSUNGS: 639 if sams in user_agent: 640 tol1 = iol(user_agent, u"/", start_index=user_agent.index(sams)) 641 tol2 = iol(user_agent, u" ", start_index=user_agent.index(sams)) 642 tolerance = tol1 if tol1 < tol2 else tol2 643 break 644 else: 645 tolerance = len(user_agent) 646 647 match = self.ris_matcher(user_agent, tolerance) 648 #print "SamsungMatcher %s -> f_m_ua -> %s" % (user_agent, match) 649 return match
650
651 652 -class SanyoMatcher(AbstractMatcher):
653 - def can_handle(self, user_agent):
654 return (user_agent.startswith(u"Sanyo") or 655 user_agent.startswith(u"SANYO"))
656
657 658 -class SharpMatcher(AbstractMatcher):
659 - def can_handle(self, user_agent):
660 return (user_agent.startswith(u"Sharp") or 661 user_agent.startswith(u"SHARP"))
662
663 664 -class SiemensMatcher(AbstractMatcher):
665 - def can_handle(self, user_agent):
666 return user_agent.startswith(u"SIE-")
667
668 669 -class SonyEricssonMatcher(AbstractMatcher):
670 - def can_handle(self, user_agent):
671 return u"SonyEricsson" in user_agent
672
673 - def find_matching_ua(self, user_agent):
674 if user_agent.startswith(u"SonyEricsson"): 675 match = super(SonyEricssonMatcher, self).find_matching_ua(user_agent) 676 else: 677 tolerance = second_slash(user_agent) 678 match = self.ris_matcher(user_agent, tolerance) 679 #print "SonyEricssonMatcher %s -> f_m_ua -> %s" % (user_agent, match) 680 return match
681
682 683 -class SPVMatcher(AbstractMatcher):
684 - def can_handle(self, user_agent):
685 return u"SPV" in user_agent
686
687 - def find_matching_ua(self, user_agent):
688 tolerance = iol(user_agent, u";", start_index=iol(user_agent, u"SPV")) 689 match = self.ris_matcher(user_agent, tolerance) 690 return match
691
692 693 -class ToshibaMatcher(AbstractMatcher):
694 - def can_handle(self, user_agent):
695 return user_agent.startswith(u"Toshiba")
696
697 698 -class VodafoneMatcher(AbstractMatcher):
699 - def can_handle(self, user_agent):
700 return user_agent.startswith(u"Vodafone")
701
702 - def find_matching_ua(self, user_agent):
703 tolerance = iol(user_agent, u"/", 3) 704 match = self.ris_matcher(user_agent, tolerance) 705 #print "VodafoneMatcher %s -> f_m_ua -> %s" % (user_agent, match) 706 return match
707
708 709 -class WindowsCEMatcher(AbstractMatcher):
710 WINDOWS_CE_TOLERANCE = 3 711
712 - def can_handle(self, user_agent):
713 return (u"Mozilla/" in user_agent and (u"Windows CE" in user_agent or 714 u"WindowsCE" in user_agent or 715 u"ZuneWP7" in user_agent))
716
717 - def find_matching_ua(self, user_agent):
718 match = self.ld_matcher(user_agent, self.WINDOWS_CE_TOLERANCE) 719 return match
720
721 - def recovery_match(self, user_agent):
722 return u"generic_ms_mobile_browser_ver1"
723 724 725 handlers = [NokiaMatcher(), 726 LGUPLUSMatcher(), 727 AndroidMatcher(normalizers.android), 728 SonyEricssonMatcher(), 729 MotorolaMatcher(), 730 BlackberryMatcher(), 731 SiemensMatcher(), 732 SagemMatcher(), 733 SamsungMatcher(), 734 PanasonicMatcher(), 735 NecMatcher(), 736 QtekMatcher(), 737 MitsubishiMatcher(), 738 PhilipsMatcher(), 739 LGMatcher(normalizers.lg), 740 AppleMatcher(), 741 KyoceraMatcher(), 742 AlcatelMatcher(), 743 SharpMatcher(), 744 SanyoMatcher(), 745 BenQMatcher(), 746 PantechMatcher(), 747 ToshibaMatcher(), 748 GrundigMatcher(), 749 HTCMatcher(), 750 BotMatcher(), 751 SPVMatcher(), 752 WindowsCEMatcher(), 753 PortalmmmMatcher(), 754 DoCoMoMatcher(), 755 KDDIMatcher(), 756 VodafoneMatcher(), 757 OperaMiniMatcher(), 758 MaemoMatcher(normalizers.maemo), 759 ChromeMatcher(normalizers.chrome), 760 AOLMatcher(), 761 OperaMatcher(), 762 KonquerorMatcher(normalizers.konqueror), 763 SafariMatcher(normalizers.safari), 764 FirefoxMatcher(normalizers.firefox), 765 MSIEMatcher(normalizers.msie), 766 CatchAllMatcher()] 767