| 1 | package HTTP::MobileAgent::DoCoMo; |
|---|
| 2 | |
|---|
| 3 | use strict; |
|---|
| 4 | use vars qw($VERSION); |
|---|
| 5 | $VERSION = 0.19; |
|---|
| 6 | |
|---|
| 7 | use base qw(HTTP::MobileAgent); |
|---|
| 8 | |
|---|
| 9 | __PACKAGE__->make_accessors( |
|---|
| 10 | qw(version model status bandwidth |
|---|
| 11 | serial_number is_foma card_id xhtml_compliant comment) |
|---|
| 12 | ); |
|---|
| 13 | |
|---|
| 14 | use HTTP::MobileAgent::DoCoMoDisplayMap qw($DisplayMap); |
|---|
| 15 | |
|---|
| 16 | # various preferences |
|---|
| 17 | use vars qw($DefaultCacheSize $HTMLVerMap $GPSModels); |
|---|
| 18 | $DefaultCacheSize = 5; |
|---|
| 19 | |
|---|
| 20 | # http://www.nttdocomo.co.jp/service/imode/make/content/spec/useragent/ |
|---|
| 21 | $HTMLVerMap = [ |
|---|
| 22 | # regex => version |
|---|
| 23 | qr/[DFNP]501i/ => '1.0', |
|---|
| 24 | qr/502i|821i|209i|691i|(F|N|P|KO)210i|^F671i$/ => '2.0', |
|---|
| 25 | qr/(D210i|SO210i)|503i|211i|SH251i|692i|200[12]|2101V/ => '3.0', |
|---|
| 26 | qr/504i|251i|^F671iS$|^F661i$|^F672i$|212i|SO213i|2051|2102V|2701|850i/ => '4.0', |
|---|
| 27 | qr/eggy|P751v/ => '3.2', |
|---|
| 28 | qr/505i|506i|252i|253i|P213i|600i|700i|701i|800i|880i|SH851i|P851i|881i|900i|901i/ => '5.0', |
|---|
| 29 | qr/702i|D851iWM|902i/ => '6.0', |
|---|
| 30 | ]; |
|---|
| 31 | |
|---|
| 32 | $GPSModels = { map { $_ => 1 } qw(F661i F505iGPS) }; |
|---|
| 33 | |
|---|
| 34 | sub is_docomo { 1 } |
|---|
| 35 | |
|---|
| 36 | sub carrier { 'I' } |
|---|
| 37 | |
|---|
| 38 | sub carrier_longname { 'DoCoMo' } |
|---|
| 39 | |
|---|
| 40 | sub parse { |
|---|
| 41 | my $self = shift; |
|---|
| 42 | my($main, $foma_or_comment) = split / /, $self->user_agent, 2; |
|---|
| 43 | |
|---|
| 44 | if ($foma_or_comment && $foma_or_comment =~ s/^\((.*)\)$/$1/) { |
|---|
| 45 | # DoCoMo/1.0/P209is (Google CHTML Proxy/1.0) |
|---|
| 46 | $self->{comment} = $1; |
|---|
| 47 | $self->_parse_main($main); |
|---|
| 48 | } elsif ($foma_or_comment) { |
|---|
| 49 | # DoCoMo/2.0 N2001(c10;ser0123456789abcde;icc01234567890123456789) |
|---|
| 50 | $self->{is_foma} = 1; |
|---|
| 51 | @{$self}{qw(name version)} = split m!/!, $main; |
|---|
| 52 | $self->_parse_foma($foma_or_comment); |
|---|
| 53 | } else { |
|---|
| 54 | # DoCoMo/1.0/R692i/c10 |
|---|
| 55 | $self->_parse_main($main); |
|---|
| 56 | } |
|---|
| 57 | |
|---|
| 58 | $self->{xhtml_compliant} = |
|---|
| 59 | ( $self->is_foma && !( $self->html_version && $self->html_version == 3.0 ) ) |
|---|
| 60 | ? 1 |
|---|
| 61 | : 0; |
|---|
| 62 | } |
|---|
| 63 | |
|---|
| 64 | sub _parse_main { |
|---|
| 65 | my($self, $main) = @_; |
|---|
| 66 | my($name, $version, $model, $cache, @rest) = split m!/!, $main; |
|---|
| 67 | $self->{name} = $name; |
|---|
| 68 | $self->{version} = $version; |
|---|
| 69 | $self->{model} = $model; |
|---|
| 70 | $self->{model} = 'SH505i' if $self->{model} eq 'SH505i2'; |
|---|
| 71 | |
|---|
| 72 | if ($cache) { |
|---|
| 73 | $cache =~ s/^c// or return $self->no_match; |
|---|
| 74 | $self->{cache_size} = $cache; |
|---|
| 75 | } |
|---|
| 76 | |
|---|
| 77 | for (@rest) { |
|---|
| 78 | /^ser(\w{11})$/ and do { $self->{serial_number} = $1; next }; |
|---|
| 79 | /^(T[CDBJ])$/ and do { $self->{status} = $1; next }; |
|---|
| 80 | /^s(\d+)$/ and do { $self->{bandwidth} = $1; next }; |
|---|
| 81 | /^W(\d+)H(\d+)$/ and do { $self->{display_bytes} = "$1*$2"; next; }; |
|---|
| 82 | } |
|---|
| 83 | } |
|---|
| 84 | |
|---|
| 85 | sub _parse_foma { |
|---|
| 86 | my($self, $foma) = @_; |
|---|
| 87 | |
|---|
| 88 | $foma =~ s/^([^\(]+)// or return $self->no_match; |
|---|
| 89 | $self->{model} = $1; |
|---|
| 90 | $self->{model} = 'SH2101V' if $1 eq 'MST_v_SH2101V'; # Huh? |
|---|
| 91 | |
|---|
| 92 | if ($foma =~ s/^\((.*?)\)$//) { |
|---|
| 93 | my @options = split /;/, $1; |
|---|
| 94 | for (@options) { |
|---|
| 95 | /^c(\d+)$/ and $self->{cache_size} = $1, next; |
|---|
| 96 | /^ser(\w{15})$/ and $self->{serial_number} = $1, next; |
|---|
| 97 | /^icc(\w{20})$/ and $self->{card_id} = $1, next; |
|---|
| 98 | /^(T[CDBJ])$/ and $self->{status} = $1, next; |
|---|
| 99 | /^W(\d+)H(\d+)$/ and $self->{display_bytes} = "$1*$2", next; |
|---|
| 100 | $self->no_match; |
|---|
| 101 | } |
|---|
| 102 | } |
|---|
| 103 | } |
|---|
| 104 | |
|---|
| 105 | sub html_version { |
|---|
| 106 | my $self = shift; |
|---|
| 107 | |
|---|
| 108 | my @map = @$HTMLVerMap; |
|---|
| 109 | while (my($re, $version) = splice(@map, 0, 2)) { |
|---|
| 110 | return $version if $self->model =~ /$re/; |
|---|
| 111 | } |
|---|
| 112 | return undef; |
|---|
| 113 | } |
|---|
| 114 | |
|---|
| 115 | sub cache_size { |
|---|
| 116 | my $self = shift; |
|---|
| 117 | return $self->{cache_size} || $DefaultCacheSize; |
|---|
| 118 | } |
|---|
| 119 | |
|---|
| 120 | sub series { |
|---|
| 121 | my $self = shift; |
|---|
| 122 | my $model = $self->model; |
|---|
| 123 | |
|---|
| 124 | if ($self->is_foma && $model =~ /\d{4}/) { |
|---|
| 125 | return 'FOMA'; |
|---|
| 126 | } |
|---|
| 127 | |
|---|
| 128 | $model =~ /(\d{3}i)/; |
|---|
| 129 | return $1; |
|---|
| 130 | } |
|---|
| 131 | |
|---|
| 132 | sub vendor { |
|---|
| 133 | my $self = shift; |
|---|
| 134 | my $model = $self->model; |
|---|
| 135 | $model =~ /^([A-Z]+)\d/; |
|---|
| 136 | return $1; |
|---|
| 137 | } |
|---|
| 138 | |
|---|
| 139 | sub _make_display { |
|---|
| 140 | my $self = shift; |
|---|
| 141 | my $display = $DisplayMap->{uc($self->model)}; |
|---|
| 142 | if ($self->{display_bytes}) { |
|---|
| 143 | my($w, $h) = split /\*/, $self->{display_bytes}; |
|---|
| 144 | $display->{width_bytes} = $w; |
|---|
| 145 | $display->{height_bytes} = $h; |
|---|
| 146 | } |
|---|
| 147 | return HTTP::MobileAgent::Display->new(%$display); |
|---|
| 148 | } |
|---|
| 149 | |
|---|
| 150 | sub is_gps { |
|---|
| 151 | my $self = shift; |
|---|
| 152 | return exists $GPSModels->{$self->model}; |
|---|
| 153 | } |
|---|
| 154 | |
|---|
| 155 | sub user_id { |
|---|
| 156 | my $self = shift; |
|---|
| 157 | return $self->get_header( 'x-dcmguid' ); |
|---|
| 158 | } |
|---|
| 159 | |
|---|
| 160 | 1; |
|---|
| 161 | __END__ |
|---|
| 162 | |
|---|
| 163 | =head1 NAME |
|---|
| 164 | |
|---|
| 165 | HTTP::MobileAgent::DoCoMo - NTT DoCoMo implementation |
|---|
| 166 | |
|---|
| 167 | =head1 SYNOPSIS |
|---|
| 168 | |
|---|
| 169 | use HTTP::MobileAgent; |
|---|
| 170 | |
|---|
| 171 | local $ENV{HTTP_USER_AGENT} = "DoCoMo/1.0/P502i/c10"; |
|---|
| 172 | my $agent = HTTP::MobileAgent->new; |
|---|
| 173 | |
|---|
| 174 | printf "Name: %s\n", $agent->name; # "DoCoMo" |
|---|
| 175 | printf "Ver: %s\n", $agent->version; # 1.0 |
|---|
| 176 | printf "HTML ver: %s\n", $agent->html_version; # 2.0 |
|---|
| 177 | printf "Model: %s\n", $agent->model; # "P502i" |
|---|
| 178 | printf "Cache: %dk\n", $agent->cache_size; # 10 |
|---|
| 179 | print "FOMA\n" if $agent->is_foma; # false |
|---|
| 180 | printf "Vendor: %s\n", $agent->vendor; # 'P' |
|---|
| 181 | printf "Series: %s\n", $agent->series; # "502i" |
|---|
| 182 | |
|---|
| 183 | # only available with <form utn> |
|---|
| 184 | # e.g.) "DoCoMo/1.0/P503i/c10/serNMABH200331"; |
|---|
| 185 | printf "Serial: %s\n", $agent->serial_number; # "NMABH200331" |
|---|
| 186 | |
|---|
| 187 | # e.g.) "DoCoMo/2.0 N2001(c10;ser0123456789abcde;icc01234567890123456789)"; |
|---|
| 188 | printf "Serial: %s\n", $agent->serial_number; # "0123456789abcde" |
|---|
| 189 | printf "Card ID: %s\n", $agent->card_id; # "01234567890123456789" |
|---|
| 190 | |
|---|
| 191 | # e.g.) "DoCoMo/1.0/P502i (Google CHTML Proxy/1.0)" |
|---|
| 192 | printf "Comment: %s\n", $agent->comment; # "Google CHTML Proxy/1.0 |
|---|
| 193 | |
|---|
| 194 | # e.g.) "DoCoMo/1.0/D505i/c20/TB/W20H10" |
|---|
| 195 | printf "Status: %s\n", $agent->status; # "TB" |
|---|
| 196 | |
|---|
| 197 | # only available in eggy/M-stage |
|---|
| 198 | # e.g.) "DoCoMo/1.0/eggy/c300/s32/kPHS-K" |
|---|
| 199 | printf "Bandwidth: %dkbps\n", $agent->bandwidth; # 32 |
|---|
| 200 | |
|---|
| 201 | # e.g.) "DoCoMo/2.0 SO902i(c100;TB;W30H16)" |
|---|
| 202 | print "XHTML compiant!\n" if $agent->xhtml_compliant; # true |
|---|
| 203 | |
|---|
| 204 | =head1 DESCRIPTION |
|---|
| 205 | |
|---|
| 206 | HTTP::MobileAgent::DoCoMo is a subclass of HTTP::MobileAgent, which |
|---|
| 207 | implements NTT docomo i-mode user agents. |
|---|
| 208 | |
|---|
| 209 | =head1 METHODS |
|---|
| 210 | |
|---|
| 211 | See L<HTTP::MobileAgent/"METHODS"> for common methods. Here are |
|---|
| 212 | HTTP::MobileAgent::DoCoMo specific methods. |
|---|
| 213 | |
|---|
| 214 | =over 4 |
|---|
| 215 | |
|---|
| 216 | =item version |
|---|
| 217 | |
|---|
| 218 | $version = $agent->version; |
|---|
| 219 | |
|---|
| 220 | returns DoCoMo version number like "1.0". |
|---|
| 221 | |
|---|
| 222 | =item html_version |
|---|
| 223 | |
|---|
| 224 | $html_version = $agent->html_version; |
|---|
| 225 | |
|---|
| 226 | returns supported HTML version like '3.0'. retuns undef if unknown. |
|---|
| 227 | |
|---|
| 228 | =item model |
|---|
| 229 | |
|---|
| 230 | $model = $agent->model; |
|---|
| 231 | |
|---|
| 232 | returns name of the model like 'P502i'. |
|---|
| 233 | |
|---|
| 234 | =item cache_size |
|---|
| 235 | |
|---|
| 236 | $cache_size = $agent->cache_size; |
|---|
| 237 | |
|---|
| 238 | returns cache size as killobytes unit. returns 5 if unknown. |
|---|
| 239 | |
|---|
| 240 | =item is_foma |
|---|
| 241 | |
|---|
| 242 | if ($agent->is_foma) { } |
|---|
| 243 | |
|---|
| 244 | retuns whether it's FOMA or not. |
|---|
| 245 | |
|---|
| 246 | =item vendor |
|---|
| 247 | |
|---|
| 248 | $vendor = $agent->vendor; |
|---|
| 249 | |
|---|
| 250 | returns vender code like 'SO' for Sony. returns undef if unknown. |
|---|
| 251 | |
|---|
| 252 | =item series |
|---|
| 253 | |
|---|
| 254 | $series = $agent->series; |
|---|
| 255 | |
|---|
| 256 | returns series name like '502i'. returns undef if unknown. |
|---|
| 257 | |
|---|
| 258 | =item serial_number |
|---|
| 259 | |
|---|
| 260 | $serial_number = $agent->serial_number; |
|---|
| 261 | |
|---|
| 262 | returns hardware unique serial number (15 digit in FOMA, 11 digit |
|---|
| 263 | otherwise alphanumeric). Only available with E<lt>form utnE<gt> |
|---|
| 264 | attribute. returns undef otherwise. |
|---|
| 265 | |
|---|
| 266 | =item card_id |
|---|
| 267 | |
|---|
| 268 | $card_id = $agent->card_id; |
|---|
| 269 | |
|---|
| 270 | returns FOMA Card ID (20 digit alphanumeric). Only available in FOMA |
|---|
| 271 | with E<lt>form utnE<gt> attribute. returns undef otherwise. |
|---|
| 272 | |
|---|
| 273 | =item comment |
|---|
| 274 | |
|---|
| 275 | $comment = $agent->comment; |
|---|
| 276 | |
|---|
| 277 | returns comment on user agent string like 'Google Proxy'. returns |
|---|
| 278 | undef otherwise. |
|---|
| 279 | |
|---|
| 280 | =item bandwidth |
|---|
| 281 | |
|---|
| 282 | $bandwidth = $agent->bandwidth; |
|---|
| 283 | |
|---|
| 284 | returns bandwidth like 32 as killobytes unit. Only vailable in eggy, |
|---|
| 285 | returns undef otherwise. |
|---|
| 286 | |
|---|
| 287 | =item status |
|---|
| 288 | |
|---|
| 289 | $status = $agent->status; |
|---|
| 290 | |
|---|
| 291 | returns status like "TB", "TC", "TD" or "TJ", which means: |
|---|
| 292 | |
|---|
| 293 | TB | Browsers |
|---|
| 294 | TC | Browsers with image off (only Available in HTML 5.0) |
|---|
| 295 | TD | Fetching JAR |
|---|
| 296 | TJ | i-Appli |
|---|
| 297 | |
|---|
| 298 | =item xhtml_compliant |
|---|
| 299 | |
|---|
| 300 | if ($agent->xhtml_compliant) { } |
|---|
| 301 | |
|---|
| 302 | returns if the agent is XHTML compliant. |
|---|
| 303 | |
|---|
| 304 | =back |
|---|
| 305 | |
|---|
| 306 | =head1 AUTHOR |
|---|
| 307 | |
|---|
| 308 | Tatsuhiko Miyagawa E<lt>miyagawa@bulknews.netE<gt> |
|---|
| 309 | |
|---|
| 310 | This library is free software; you can redistribute it and/or modify |
|---|
| 311 | it under the same terms as Perl itself. |
|---|
| 312 | |
|---|
| 313 | =head1 SEE ALSO |
|---|
| 314 | |
|---|
| 315 | L<HTTP::MobileAgent> |
|---|
| 316 | |
|---|
| 317 | http://www.nttdocomo.co.jp/p_s/imode/spec/useragent.html |
|---|
| 318 | |
|---|
| 319 | http://www.nttdocomo.co.jp/p_s/imode/spec/ryouiki.html |
|---|
| 320 | |
|---|
| 321 | http://www.nttdocomo.co.jp/p_s/imode/tag/utn.html |
|---|
| 322 | |
|---|
| 323 | http://www.nttdocomo.co.jp/p_s/mstage/visual/contents/cnt_mpage.html |
|---|
| 324 | |
|---|
| 325 | |
|---|
| 326 | =cut |
|---|