File Coverage

blib/lib/Mobile/UserAgent.pm
Criterion Covered Total %
statement 138 170 81.1
branch 79 104 75.9
condition 23 51 45.1
subroutine 11 20 55.0
pod 13 13 100.0
total 264 358 73.7


line stmt bran cond sub pod time code
1             package Mobile::UserAgent;
2             #
3             # Copyright (C) 2005 Craig Manley. All rights reserved.
4             #
5             # This library is free software; you can redistribute it and/or modify
6             # it under the same terms as Perl itself. There is NO warranty; not even for
7             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8             #
9             # $Id: UserAgent.pm,v 1.5 2005/09/25 14:29:18 cmanley Exp $
10             #
11 3     3   35016 use strict;
  3         7  
  3         135  
12 3     3   17 use Carp;
  3         6  
  3         27843  
13            
14             our $VERSION = sprintf "%d.%02d", q$Revision: 1.5 $ =~ m/ (\d+) \. (\d+) /xg;
15            
16            
17            
18             # Contructor
19             # Parameter: optional user-agent string
20             sub new {
21 1991     1991 1 1304952 my $proto = shift;
22 1991   33     8983 my $useragent = shift || $ENV{'HTTP_USER_AGENT'};
23 1991 50       17847 unless(defined($useragent)) {
24 0         0 croak("Environment variable HTTP_USER_AGENT is missing!\n");
25             }
26 1991   33     9851 my $class = ref($proto) || $proto;
27 1991         30839 my $self = {
28             'useragent' => $useragent,
29             'is_standard' => 0,
30             'is_imode' => 0,
31             'is_mozilla' => 0,
32             'is_rubbish' => 0,
33             'is_series60' => undef,
34             };
35 1991         21279 bless($self,$class);
36 1991         4475 my $hashref = $self->_parseUserAgent($useragent);
37 1991 50       4713 if (defined($hashref)) {
38 1991         5626 $self->{'vendor'} = $hashref->{'vendor'};
39 1991         10222 $self->{'model'} = $hashref->{'model'};
40 1991         6662 $self->{'version'} = $hashref->{'version'};
41 1991         3589 $self->{'imode_cache'} = $hashref->{'imode_cache'};
42 1991         3404 $self->{'screendims'} = $hashref->{'screendims'};
43             }
44 1991         8829 return $self;
45             }
46            
47            
48            
49            
50             # Protected class method.
51             # Parses a standard mobile user agent string with the format vendor-model/version.
52             # If no match can be made, undef is returned.
53             # If a match is made, a hash ref is returned containing the compulsory
54             # keys "vendor" and "model", and the optional keys "version", and "screendims".
55             #
56             # Below are a few samples of these user agent strings:
57             #
58             # Nokia8310/1.0 (05.57)
59             # NokiaN-Gage/1.0 SymbianOS/6.1 Series60/1.2 Profile/MIDP-1.0 Configuration/CLDC-1.0
60             # SAGEM-myX-6/1.0 UP.Browser/6.1.0.6.1.c.3 (GUI) MMP/1.0 UP.Link/1.1
61             # SAMSUNG-SGH-A300/1.0 UP/4.1.19k
62             # SEC-SGHE710/1.0
63             #
64             # Parameter: user-agent string.
65             # Returns: hash ref or undef.
66             sub _parseUserAgentStandard {
67 1991     1991   9734 my $proto = shift;
68 1991         3826 my $useragent = shift;
69             # Standard vendor-model/version user agents
70 1991 100       16062 unless ($useragent =~ /^
71             # Match the vendor-model combination (this goes into $1)....
72             (
73            
74             # Match known vendor names (this goes into $2)...
75             (ACER|Alcatel|AUDIOVOX|BlackBerry|CDM|Ericsson|LG\b|LGE|Motorola|MOT|NEC|Nokia|Panasonic|PANTECH|PT|QCI|SAGEM|SAMSUNG|SEC|Sanyo|Sendo|SHARP|SIE|SonyEricsson|Telit|Telit_Mobile_Terminals|TSM)
76            
77             # optionally followed by an irrelevant space or '-' character...
78             [- ]?
79            
80             # followed by the model name (this goes into $3)...
81             ([^\/\s\_]+)
82             )
83            
84             # Match possible version information after the slash seperator (this goes into $5)...
85             (\/(\S+))?
86            
87             /x) {
88 193         646 return undef;
89             }
90 1798         13855 my $both = $1;
91 1798         3051 my $vendor = $2;
92 1798         2856 my $model = $3;
93 1798         2734 my $version = $5;
94             # Fixup vendors and models.
95 1798 100 33     24498 if ($vendor eq 'ACER') {
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    100          
    100          
    100          
    100          
    100          
96 1         3 $vendor = 'Acer';
97             }
98             elsif ($vendor eq 'AUDIOVOX') {
99 4         6 $vendor = 'Audiovox';
100             }
101             elsif ($vendor eq 'CDM') {
102 4         7 $vendor = 'Audiovox';
103 4         9 $model = "CDM-$model";
104             }
105             elsif ($vendor eq 'Ericsson') {
106 67 50       165 if ($model eq 'T68_NIL') {
107 0         0 $model = 'T68';
108             }
109             }
110             elsif (substr($vendor,0,2) eq 'LG') {
111 30         38 $vendor = 'LG';
112 30 100       74 if ($model =~ /^([A-Za-z\d]+)-/) { # LGE510W-V137-AU4.2
113 1         3 $model = $1;
114             }
115             }
116             elsif ($vendor eq 'MOT') {
117 277         355 $vendor = 'Motorola';
118 277         636 $model =~ s/[\._]$//;
119             }
120             elsif (($vendor eq 'PT') || ($vendor eq 'PANTECH')) {
121 0         0 $vendor = 'Pantech';
122             }
123             elsif ($vendor eq 'PHILIPS') {
124 0         0 $model = uc($model);
125             }
126             elsif ($vendor eq 'SAGEM') {
127 80 50       582 if ($model eq '-') {
128 0         0 return undef;
129             }
130             }
131             elsif ($vendor eq 'SEC') {
132 63         87 $vendor = 'SAMSUNG';
133 63         115 $model =~ s/\*.*$//g;
134             }
135             elsif ($vendor eq 'SIE') {
136 240         408 $vendor = 'Siemens';
137             }
138             elsif ($vendor eq 'Telit_Mobile_Terminals') {
139 1         4 $vendor = 'Telit';
140             }
141             elsif ($vendor eq 'TSM') {
142 10         16 $vendor = 'Vitelcom';
143 10         13 $model = $both;
144             }
145 1798         10521 my %result = ('vendor' => $vendor,
146             'model' => $model);
147 1798 100       4411 if (defined($version)) {
148 1670         3542 $result{'version'} = $version;
149             }
150 1798         8433 return \%result;
151             }
152            
153            
154            
155             # Protected class method.
156             # Parses an i-mode user agent string.
157             # If no match can be made, undef is returned.
158             # If a match is made, a hash ref is returned containing the compulsory
159             # keys "vendor" and "model", and the optional keys "version", "imode_cache",
160             # and "screendims".
161             #
162             # Below are a few samples of these user agent strings:
163             #
164             # portalmmm/1.0 m21i-10(c10)
165             # portalmmm/1.0 n21i-10(c10)
166             # portalmmm/1.0 n21i-10(;ser123456789012345;icc1234567890123456789F)
167             # portalmmm/2.0 N400i(c20;TB)
168             # portalmmm/2.0 P341i(c10;TB)
169             # portalmmm/2.0 L341i(c10;TB)
170             # portalmmm/2.0 S341i(c10;TB)
171             # portalmmm/2.0 SI400i(c10;TB)
172             # DoCoMo/1.0/modelname
173             # DoCoMo/1.0/modelname/cache
174             # DoCoMo/1.0/modelname/cache/unique_id_information
175             # DoCoMo/2.0 modelname(cache;individual_identification_information)
176             #
177             # Parameter: user-agent string.
178             # Returns: hash ref or undef.
179             sub _parseUserAgentImode {
180 160     160   195 my $proto = shift;
181 160         215 my $useragent = shift;
182 160         2098 my %vendors = (
183             'D' => 'Mitsubishi',
184             'ER' => 'Ericsson',
185             'F' => 'Fujitsu',
186             'KO' => 'Kokusai', # Hitachi
187             'L' => 'LG',
188             'M' => 'Mitsubishi',
189             'P' => 'Panasonic', # Matsushita
190             'N' => 'NEC',
191             'NM' => 'Nokia',
192             'R' => 'Japan Radio',
193             'S' => 'SAMSUNG', # because of the other vendor codes starting with S below, the regex must try to match them first.
194             'SG' => 'SAGEM',
195             'SH' => 'Sharp',
196             'SI' => 'Siemens',
197             'SO' => 'Sony',
198             'TS' => 'Toshiba');
199            
200             # Standard i-mode user agents
201 160         1839 my $pattern = '^(portalmmm|DoCoMo)\/(\d+\.\d+) ((' . join('|', reverse sort keys(%vendors)) . ')[\w\-]+) ?\((c(\d+))?';
202 160 100       1412 if ($useragent =~ /$pattern/i) {
203 29         88 my $vendor = $vendors{uc($4)};
204 29         64 my $model = $3;
205 29         45 my $version = $2;
206 29         31 my $cache;
207 29 100 66     164 if (defined($6) && length($6)) {
208 26         62 $cache = $6 + 0;
209             }
210             else {
211 3         5 $cache = 5;
212             }
213            
214             # Chop off trailing cache size from model name (e.g. N21i-10 becomes N21i).
215 29 50       59 if (defined($model)) {
216 29         85 $model =~ s/-\d+$//;
217             }
218            
219 29         311 return {'vendor' => $vendor,
220             'model' => $model,
221             'version' => $version,
222             'imode_cache' => $cache};
223             }
224            
225             # DoCoMo HTML i-mode user agents
226 131         6815 $pattern = '^DoCoMo\/(\d+\.\d+)\/((' . join('|', keys(%vendors)) . ')[\w\.\-\_]+)(\/c(\d+))?';
227 131 100       34780 if ($useragent =~ /$pattern/i) {
228             # HTML 1.0: DoCoMo/1.0/modelname
229             # HTML 2.0: DoCoMo/1.0/modelname/cache
230             # HTML 3.0: DoCoMo/1.0/modelname/cache/unique_id_information
231 69         508 my %result = ('vendor' => $vendors{uc($3)},
232             'model' => $2,
233             'version' => $1);
234 69 50 33     233 if (defined($6) && length($6)) {
235 0         0 $result{'imode_cache'} = $5 + 0;
236             }
237             else {
238 69         130 $result{'imode_cache'} = 5;
239             }
240 69         554 return \%result;
241             }
242 62         432 return undef;
243             }
244            
245            
246            
247             # Protected class method.
248             # Parses a Mozilla (so called) compatible user agent string.
249             # If no match can be made, undef is returned.
250             # If a match is made, a hash ref is returned containing the compulsory
251             # keys "vendor" and "model", and the optional keys "version", and "screendims".
252             #
253             # Below are a few samples of these user agent strings:
254             #
255             # Mozilla/4.1 (compatible; MSIE 5.0; Symbian OS; Nokia 3650;424) Opera 6.10 [en]
256             # Mozilla/4.0 (compatible; MSIE 6.0; Nokia7650) ReqwirelessWeb/2.0.0.0
257             # Mozilla/1.22 (compatible; MMEF20; Cellphone; Sony CMD-Z5)
258             # Mozilla/1.22 (compatible; MMEF20; Cellphone; Sony CMD-Z5;Pz063e+wt16)
259             # Mozilla/2.0 (compatible; MSIE 3.02; Windows CE; PPC; 240x320)
260             # mozilla/4.0 (compatible;MSIE 4.01; Windows CE;PPC;240X320) UP.Link/5.1.1.5
261             # Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; PPC; 240x320)
262             # Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; SmartPhone; 176x220)
263             # Mozilla/2.0 (compatible; MSIE 3.02; Windows CE; 240x320; PPC)
264             # Mozilla/2.0 (compatible; MSIE 3.02; Windows CE; Smartphone; 176x220; Mio8380; Smartphone; 176x220)
265             # Mozilla/4.0 (MobilePhone SCP-8100/US/1.0) NetFront/3.0 MMP/2.0
266             # Mozilla/2.0(compatible; MSIE 3.02; Windows CE; Smartphone; 176x220)
267             # Mozilla/4.1 (compatible; MSIE 5.0; Symbian OS Series 60 42) Opera 6.0 [fr]
268             # Mozilla/SMB3(Z105)/Samsung UP.Link/5.1.1.5
269             #
270             # Parameter: user-agent string.
271             # Returns: hash ref or undef.
272             sub _parseUserAgentMozilla {
273 193     193   234 my $proto = shift;
274 193         218 my $useragent = shift;
275             # SAMSUNG browsers
276 193 100       429 if ($useragent =~ /^Mozilla\/SMB3\((Z105)\)\/(Samsung)/) {
277 2         22 return {'vendor' => uc($2), 'model' => $1};
278             }
279             # Extract the string between the brackets.
280 191 100       565 unless($useragent =~ /^Mozilla\/\d+\.\d+\s*\(([^\)]+)\)/i) {
281 160         415 return undef;
282             }
283 31         296 my @parts = split(/\s*;\s*/, $1); # split string between brackets on ';' seperator.
284             # Micro$oft PPC and Smartphone browsers. Unfortunately, one day, if history repeats itself, this will probably be the only user-agent check necessary.
285 31 100 66     229 if ((@parts >= 4) && ($parts[0] eq 'compatible') && ($parts[2] eq 'Windows CE')) {
      100        
286 9         35 my %result = ('vendor' => 'Microsoft');
287 9 100 100     75 if (($parts[3] eq 'PPC') || (lc($parts[3]) eq 'smartphone')) {
    50 33        
      33        
288 8         18 $result{'model'} = 'SmartPhone';
289 8 50 33     64 if ((@parts >= 5) && ($parts[4] =~ /^\d{1,4}x\d{1,4}$/i)) {
290 8         25 $result{'screendims'} = lc($parts[4]);
291             }
292             }
293             elsif ((@parts >= 5) && (($parts[4] eq 'PPC') || (lc($parts[4]) eq 'smartphone'))) {
294 1         4 $result{'model'} = 'SmartPhone';
295 1 50       8 if ($parts[3] =~ /^\d{1,4}x\d{1,4}$/i) {
296 1         4 $result{'screendims'} = lc($parts[3]);
297             }
298             }
299 9 50       25 if (exists($result{'model'})) {
300 9         46 return \%result;
301             }
302             }
303            
304             # Nokia's with Opera browsers or SonyEricssons.
305 22 50 66     193 if ((@parts >= 4) && ($parts[0] eq 'compatible') && ($parts[3] =~ /^(Nokia|Sony)\s*(\S+)$/)) {
      66        
306 18         31 my $vendor = $1;
307 18         29 my $model = $2;
308 18 50       34 if ($vendor eq 'Sony') {
309 18         26 $vendor = 'SonyEricsson';
310             }
311 18         108 return {'vendor' => $vendor, 'model' => $model};
312             }
313            
314             # SANYO browsers
315 4 50 33     69 if (@parts && ($parts[0] =~ /^MobilePhone ([^\/]+)\/([A-Z]+\/)?(\d+\.\d+)$/)) { # MobilePhone PM-8200/US/1.0
316 4         31 return {'vendor' => 'Sanyo', 'model' => $1, 'version' => $3};
317             }
318            
319             # Nokias with ReqwirelessWeb browser
320 0 0 0     0 if ((@parts >= 3) && ($parts[0] eq 'compatible') && ($parts[1] =~ /^(Nokia)\s*(\S+)$/)) {
      0        
321 0         0 return {'vendor' => $1, 'model' => $2};
322             }
323 0         0 return undef;
324             }
325            
326            
327            
328             # Protected class method.
329             # Parses a non-standard mobile user agent string.
330             # If no match can be made, undef is returned.
331             # If a match is made, a hash ref is returned containing the compulsory
332             # keys "vendor" and "model", and the optional keys "version", and "screendims".
333             #
334             # Below are a few samples of these user agent strings:
335             #
336             # LGE/U8150/1.0 Profile/MIDP-2.0 Configuration/CLDC-1.0
337             # PHILIPS855 ObigoInternetBrowser/2.0
338             # PHILIPS 535 / Obigo Internet Browser 2.0
339             # PHILIPS-FISIO 620/3
340             # PHILIPS-Fisio311/2.1
341             # PHILIPS-FISIO311/2.1
342             # PHILIPS-Xenium9@9 UP/4.1.16r
343             # PHILIPS-XENIUM 9@9/2.1
344             # PHILIPS-Xenium 9@9++/3.14
345             # PHILIPS-Ozeo UP/4
346             # PHILIPS-V21WAP UP/4
347             # PHILIPS-Az@lis288 UP/4.1.19m
348             # PHILIPS-SYSOL2/3.11 UP.Browser/5.0.1.11
349             # Vitelcom-Feature Phone1.0 UP.Browser/5.0.2.2(GUI
350             # ReqwirelessWeb/2.0.0 MIDP-1.0 CLDC-1.0 Nokia3650
351             # SEC-SGHE710
352             #
353             # Notice how often one certain brand of these user-agents is handled by this function. I say no more.
354             #
355             # Parameter: user-agent string.
356             # Returns: hash ref or undef.
357             sub _parseUserAgentRubbish {
358 62     62   119 my $proto = shift;
359 62         108 my $useragent = shift;
360             # Old ReqwirelessWeb browsers for Nokia. ReqwirelessWeb/2.0.0 MIDP-1.0 CLDC-1.0 Nokia3650
361 62 50       1451 if ($useragent =~ /(Nokia)\s*(N-Gage|\d+)$/) {
    100          
    100          
    50          
362 0         0 return {'vendor' => $1, 'model' => $2};
363             }
364            
365             # LG Electronics
366             elsif ($useragent =~ /^(LG)E?\/(\w+)(\/(\d+\.\d+))?/) { # LGE/U8150/1.0 Profile/MIDP-2.0 Configuration/CLDC-1.0
367 1         5 my %result = ('vendor' => $1, 'model' => $2);
368 1 50 33     11 if (defined($4) && length($4)) {
369 1         3 $result{'version'} = $4;
370             }
371 1         6 return \%result;
372             }
373            
374             # And now for the worst of all user agents...
375             elsif ($useragent =~ /^(PHILIPS)(.+)/) {
376 60         131 my $vendor = $1;
377 60         72 my $model;
378 60         157 my $garbage = uc($2); # everything after the word PHILIPS in uppercase.
379 60         644 $garbage =~ s/(^\s+|\s+$)//g; # trim
380 60 100       430 if ($garbage =~ /^-?(\d+)/) { # match the model names that are just digits.
    100          
    100          
    50          
381 2         6 $model = $1;
382             # PHILIPS855 ObigoInternetBrowser/2.0
383             # PHILIPS 535 / Obigo Internet Browser 2.0
384             }
385             elsif ($garbage =~ /^-?(FISIO)\s*(\d+)/) { # match the FISIO model names.
386 29         72 $model = "$1$2";
387             # PHILIPS-FISIO 620/3
388             # PHILIPS-Fisio311/2.1
389             # PHILIPS-FISIO311/2.1
390             }
391             elsif ($garbage =~ /^-?(XENIUM)/) { # match the XENIUM model names.
392 8         17 $model = $1;
393             # PHILIPS-Xenium9@9 UP/4.1.16r
394             # PHILIPS-XENIUM 9@9/2.1
395             # PHILIPS-Xenium 9@9++/3.14
396             }
397             elsif ($garbage =~ /^-?([^\s\/]+)/) { # match all other model names that contain no spaces and no slashes.
398 21         43 $model = $1;
399             # PHILIPS-Ozeo UP/4
400             # PHILIPS-V21WAP UP/4
401             # PHILIPS-Az@lis288 UP/4.1.19m
402             # PHILIPS-SYSOL2/3.11 UP.Browser/5.0.1.11
403             }
404 60 50       130 if (defined($model)) {
405 60         354 return {'vendor' => $vendor, 'model' => $model};
406             }
407             }
408            
409             # Vitelcom user-agents (used in Spain)
410             elsif ($useragent =~ /^(Vitelcom)-(Feature Phone)(\d+\.\d+)/) {
411             # Vitelcom-Feature Phone1.0 UP.Browser/5.0.2.2(GUI) -- this is a TSM 3 or a TSM 4.
412 1         11 return {'vendor' => $1,
413             'model' => $2,
414             'version' => $3};
415             }
416 0         0 return undef;
417             }
418            
419            
420            
421             # Protected object method.
422             # Parses a user agent string.
423             # This method simply calls the other 4 _parseUserAgent*() methods to do the work.
424             # If no match can be made, undef is returned.
425             # If a match is made, a hash ref is returned containing the compulsory
426             # keys "vendor" and "model", and the optional keys "version", "imode_cache",
427             # and "screendims".
428             #
429             # Parameter: user-agent string.
430             # Returns: hash ref or undef.
431             sub _parseUserAgent {
432 1991     1991   4529 my $self = shift;
433 1991         2906 my $useragent = shift;
434 1991         2590 my $result;
435 1991 100       5164 if ($result = $self->_parseUserAgentStandard($useragent)) {
436 1798         3110 $self->{'is_standard'} = 1;
437 1798         8520 return $result;
438             }
439 193 100       456 if ($result = $self->_parseUserAgentMozilla($useragent)) {
440 33         53 $self->{'is_mozilla'} = 1;
441 33         64 return $result;
442             }
443 160 100       432 if ($result = $self->_parseUserAgentImode($useragent)) {
444 98         161 $self->{'is_imode'} = 1;
445 98         218 return $result;
446             }
447 62 50       170 if ($result = $self->_parseUserAgentRubbish($useragent)) {
448 62         109 $self->{'is_rubbish'} = 1;
449 62         132 return $result;
450             }
451 0         0 return $result;
452             }
453            
454            
455            
456             # Public object method.
457             # Returns true if the user-agent string passed into the constructor could be parsed, else false.
458             # If this method returns false, then it's probably not a mobile user agent string that was
459             # passed into the constructor.
460             sub success {
461 1991     1991 1 12665 my $self = shift;
462 1991         6096 return defined($self->{'vendor'});
463             }
464            
465            
466             # Public object method.
467             # Returns the user agent string as passed into the constructor or read
468             # from the environment variable HTTP_USER_AGENT.
469             sub userAgent {
470 0     0 1 0 my $self = shift;
471 0         0 return $self->{'useragent'};
472             }
473            
474            
475            
476             # Public object method.
477             # Returns the vendor of the handset if success() returns true, else undef.
478             sub vendor {
479 1991     1991 1 9517 my $self = shift;
480 1991         5173 return $self->{'vendor'};
481             }
482            
483            
484             # Public object method.
485             # Returns the model of the handset if success() returns true, else undef.
486             sub model {
487 1991     1991 1 21629 my $self = shift;
488 1991         23788 return $self->{'model'};
489             }
490            
491            
492             # Public object method.
493             # Returns the version (if any) of the user agent.
494             # The version information isn't always present, nor reliable.
495             #
496             # @return string|null
497             sub version {
498 0     0 1   my $self = shift;
499 0           return $self->{'version'};
500             }
501            
502            
503             # Public object method.
504             # Determines if the parsed user-agent string belongs to an i-mode handset.
505             # Returns boolean.
506             sub isImode() {
507 0     0 1   my $self = shift;
508 0           return $self->{'is_imode'};
509             }
510            
511            
512             # Public object method.
513             # Determines if the parsed user-agent string has a Mozilla 'compatible' format.
514             # Returns boolean.
515             sub isMozilla() {
516 0     0 1   my $self = shift;
517 0           return $self->{'is_mozilla'};
518             }
519            
520            
521             # Public object method.
522             # Determines if the parsed user-agent string has a standard vendor-model/version format.
523             # Returns true, if so, else false.
524             sub isStandard() {
525 0     0 1   my $self = shift;
526 0           return $self->{'is_standard'};
527             }
528            
529            
530             # Public object method.
531             # Determines if the parsed user-agent string has a non-standard or messed up format.
532             # Returns true, if so, else false.
533             sub isRubbish() {
534 0     0 1   my $self = shift;
535 0           return $self->{'is_rubbish'};
536             }
537            
538            
539             # Public object method.
540             # Returns the maximum i-mode cache data size in kb's of the user agent if it is
541             # an i-mode user-agent, else null.
542             sub imodeCache() {
543 0     0 1   my $self = shift;
544 0           return $self->{'imode_cache'};
545             }
546            
547            
548             # Public object method.
549             # Returns the screen dimensions in the format wxh if this information was parsed
550             # from the user agent string itself, else undef.
551             sub screenDims {
552 0     0 1   my $self = shift;
553 0           return $self->{'screendims'};
554             }
555            
556            
557             # Public object method.
558             # Determines if this is a Symbian OS Series 60 user-agent string.
559             sub isSeries60 {
560 0     0 1   my $self = shift;
561 0 0         unless(defined($self->{'is_series60'})) {
562             # NokiaN-Gage/1.0 SymbianOS/6.1 Series60/1.2 Profile/MIDP-1.0 Configuration/CLDC-1.0
563             # Mozilla/4.1 (compatible; MSIE 5.0; Symbian OS Series 60 42) Opera 6.0 [fr]
564 0           $self->{'is_series60'} = $self->{'useragent'} =~ /\b(Symbian OS Series 60|SymbianOS\/\S+ Series60)\b/;
565             }
566 0           return $self->{'is_series60'};
567             }
568            
569            
570             1;
571            
572            
573             __END__