OSDN Git Service

applied patch, closes #14238
[keitairc/keitairc.git] / lib / plugins / 00location_receiver
1 # -*- mode: perl; coding: utf-8 -*-
2 # keitairc/lib/plugins/00location_receiver
3 # 位置情報送信、のコールバック
4 # $Id: 00location_receiver,v 1.13 2008-12-20 12:46:28 morimoto Exp $
5 # $Source: /home/ishikawa/work/keitairc/tmp/keitairc/lib/plugins/00location_receiver,v $
6
7 # The line number (1 incremented) and filename below must be
8 # actual. see perlsyn.
9 # line 10 "keitairc/lib/plugins/00location_receiver"
10
11 use Net::HTTP;
12 use XML::Simple;
13 use Encode;
14
15 # WGS84系を渡すこと
16 sub get_rgeocode_xml {
17         my ($lat, $lon) = @_;
18         my $s = Net::HTTP->new(Host => 'refits.cgk.affrc.go.jp') || return;
19         $s->write_request(GET => "/tsrv/jp/rgeocode.php?lat=$lat&lon=$lon");
20         $s->read_response_headers();
21         my $xml;
22         for(;;){
23                 my $buf;
24                 my $n = $s->read_entity_body($buf, 1024);
25                 return unless defined $n;
26                 last unless $n;
27                 $xml .= $buf;
28         }
29         $xml;
30 }
31
32 sub dms_to_degree{
33         my $dms = shift;
34         my ($degree, $min, $sec, $secc) = ($dms =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/);
35         $degree + $min/60 + $sec/3600 + $secc/360000;
36 }
37
38 sub wgs84_to_tokyo{
39         my ($lat, $lon) = @_;
40         return ($lat + 0.00010696*$lat - 0.000017467*$lat - 0.0046020,
41                 $lon + 0.000046047*$lon + 0.000083049*$lon - 0.010041);
42 }
43
44 sub tokyo_to_wgs84{
45         my ($lat, $lon) = @_;
46         return ($lat - 0.00010695*$lat + 0.000017464*$lat + 0.0046017,
47                 $lon - 0.000046038*$lon - 0.000083043*$lon + 0.010040);
48 }
49
50 # see http://labs.anoncom.net/others/GoogleMap/NoAjaxInterface.html
51 sub google_map_image{
52         my ($wx, $wy, $format) = @_;
53         my $gwx = sprintf('%0.6f', $wx);
54         my $gwy = sprintf('%0.6f', $wy);
55         $gwx =~ s/\.//;
56         $gwy =~ s/\.//;
57         my %format = (
58                 gif => 1,
59                 png => 2,
60                 jpeg => 3,
61         );
62         my $iconid = 15;
63         my $zoom = 2000;
64         my $width = 160;
65         my $height = 240;
66         sprintf('http://maps.google.com/mapdata?cc=JP&min_priority=1&w=%d&h=%d&latitude_e6=%d&longitude_e6=%d&zm=%d&Point=b&Point.latitude_e6=%d&Point.longitude_e6=%d&Point.iconid=%d&Point=e&image_format=%d',
67                 $width, $height,
68                 $gwx, $gwy, $zoom, $gwx, $gwy, $iconid, $format{$format});
69 }
70
71 $plugin = {
72         name => 'location_receiver',
73
74         action_imprementation => sub {
75                 my ($request, $name, $session_id, $param_string) = @_;
76                 my ($cid) = ($param_string =~ /^(\d+)/);
77                 my $uri = $request->uri();;
78                 $uri =~ s/.*\?//;
79                 my %h;
80                 for my $pair (split(/&/, $uri)){
81                         my ($k, $v) = split(/=/, $pair);
82                         $h{$k} = $v;
83                 }
84
85                 my $ci = new Keitairc::ClientInfo($request);
86                 my $view = new Keitairc::View($::cf, $ci);
87                 my $p;
88                 $p->{session_id} = $session_id;
89                 $p->{cid} = $cid;
90                 $p->{stamp} = time;
91                 $p->{channel_compact} = $::ib->simple_escape(encode($::cf->web_charset(), $::ib->compact_channel_name($cid)));
92
93                 # 測地系
94                 # 以下の2つの測地系の中から使用している測地系を示す。
95                 # wgs84 WGS84系: GPS測量で算出される座標系。数回の改定
96                 # により現在ではITRF座標系と実用上の差異はなくなってい
97                 # る。
98                 # tokyo 日本測地系: 測量法施行令第2条で定められた日本標
99                 # 準の測地系。
100                 # 備考: 引数内容としては"tokyo"という表示になるが、実際
101                 # の測地系はWGS84系のデータを使用。
102                 # from http://www.au.kddi.com/ezfactory/tec/spec/eznavi.html
103
104                 # NTT DoCoMo
105                 if($ci->is_docomo()){
106                         # iエリアはPOSTで来る
107                         # ACTN=OK&LAT=%2B35.44.27.996&LON=%2B139.35.37.932&GEO=wgs84&XACC=1&POSINFO=2
108                         my ($wx, $wy);
109                         my $posted = $request->content();
110                         my %posted;
111                         for my $pair (split(/&/, $posted)){
112                                 my ($k, $v) = split(/=/, $pair);
113                                 $posted{$k} = $v;
114                         }
115                         if(defined $posted{LAT}){
116                                 $posted{LAT} =~ s/^%2b//i;
117                                 $posted{LON} =~ s/^%2b//i;
118                                 ($wx, $wy) = (dms_to_degree($posted{LAT}), dms_to_degree($posted{LON}));
119                         }else{
120                                 # iエリアじゃないからlcsかな
121                                 # GET /loc.jsp?lat=%2B35.40.53.008&lon=%2B139.45.57.971&geo=WGS84&x-acc=3 
122                                 # see http://www.utilz.jp/wiki/Gps
123                                 unless(defined $h{lat}){
124                                         $p->{error} = 1;
125                                         $p->{error_lcs} = 1;
126                                         return $view->render('location_receiver.html', $p);
127                                 }
128                                 $h{lat} =~ s/^%2b//i;
129                                 $h{lon} =~ s/^%2b//i;
130                                 ($wx, $wy) = (dms_to_degree($h{lat}), dms_to_degree($h{lon}));
131                         }
132
133                         my ($tx, $ty) = wgs84_to_tokyo($wx, $wy);
134                         my $xml_code = get_rgeocode_xml($wx, $wy);
135                         unless($xml_code){
136                                 $p->{error} = 1;
137                                 $p->{rgeocode_noresponse} = 1;
138                                 return $view->render('location_receiver.html', $p);
139                         }
140
141                         my $xml = XMLin($xml_code);
142                         if($xml->{status} ne 'true'){
143                                 $p->{error} = 1;
144                                 $p->{rgeocode_invalid} = 1;
145                                 return $view->render('location_receiver.html', $p);
146                         }
147                         $p->{wx} = $wx;
148                         $p->{wy} = $wy;
149                         $p->{tx} = $tx;
150                         $p->{ty} = $ty;
151                         $p->{map_image_url} = google_map_image($wx, $wy, 'gif');
152                         $p->{address} = $xml->{prefecture}->{pname} .
153                                         $xml->{municipality}->{mname} .
154                                         $xml->{local}->{section};
155                         Encode::_utf8_off($p->{address}) if Encode::is_utf8($p->{address});
156                         Encode::from_to($p->{address}, 'utf8', $::cf->web_charset());
157                         return $view->render('location_receiver.html', $p);
158                 }
159
160                 # Softbank
161                 # HTTPヘッダーのx-jphone-geocodeに位置情報が通知されます。
162                 # x-jphone-geocode: 354053%1A1394557%1A(住所がSJISでエ
163                 # ンコードされたもの) "%1A"(SUB)で区切られて lat, lon,
164                 # 住所(SJISでエンコード)の形式になります。住所はドキュ
165                 # メントを見る限りSJISでエスケープしたものとなっていま
166                 # すが、正しくデコードできない場合がありました。この情
167                 # 報は利用しない方が良いのかも知れません。
168                 # see http://www.utilz.jp/wiki/Gps
169                 if($ci->is_softbank()){
170                         my ($lat, $lon);
171                         if(defined $request->{_headers}->{'x-jphone-geocode'}){
172                                 ($lat, $lon) = split(/%1A/, $request->{_headers}->{'x-jphone-geocode'});
173                                 # sigh
174                                 $lat =~ s/^(\d\d)(\d\d)(\d\d)/$1.$2.$3.00/;
175                                 $lon =~ s/^(\d\d\d)(\d\d)(\d\d)/$1.$2.$3.00/;
176                         }else{
177                                 # GET /loc.jsp?pos=N35.40.53.00E139.45.57.97&geo=wgs84&x-acr=1 
178                                 ($lat, $lon) = ($h{pos} =~ /^N([\d.]+)E([\d.]+)$/);
179                         }
180                         my ($wx, $wy) = (dms_to_degree($lat), dms_to_degree($lon));
181                         my ($tx, $ty) = wgs84_to_tokyo($wx, $wy);
182                         my $xml_code = get_rgeocode_xml($wx, $wy);
183                         unless($xml_code){
184                                 $p->{error} = 1;
185                                 $p->{rgeocode_noresponse} = 1;
186                                 return $view->render('location_receiver.html', $p);
187                         }
188
189                         my $xml = XMLin($xml_code);
190                         if($xml->{status} ne 'true'){
191                                 $p->{error} = 1;
192                                 $p->{rgeocode_invalid} = 1;
193                                 return $view->render('location_receiver.html', $p);
194                         }
195                         $p->{wx} = $wx;
196                         $p->{wy} = $wy;
197                         $p->{tx} = $tx;
198                         $p->{ty} = $ty;
199                         $p->{map_image_url} = google_map_image($wx, $wy, 'png');
200                         $p->{address} = $xml->{prefecture}->{pname} .
201                                         $xml->{municipality}->{mname} .
202                                         $xml->{local}->{section};
203                         Encode::_utf8_off($p->{address}) if Encode::is_utf8($p->{address});
204                         Encode::from_to($p->{address}, 'utf8', $::cf->web_charset());
205                         return $view->render('location_receiver.html', $p);
206                 }
207
208                 # see KDDI au: 技術情報 > 簡易位置情報
209                 # http://www.au.kddi.com/ezfactory/tec/spec/eznavi.html
210                 if($ci->is_ezweb()){
211                         # au W53S location の戻り例
212                         #   3/?datum=tokyo&unit=dms&lat=35.44.51.75&lon=139.35.15.0
213                         # au W53S gpsone の戻り例
214                         # /?ver=1&datum=0&unit=0&lat=%2b35.44.29.09&lon=%2b139.35.38.97&alt=71&time=20080114183222&smaj=116&smin=96&vert=46&majaa=24&fm=2
215                         $h{lat} =~ s/^%2b//i; # au GPSOneの場合
216                         $h{lon} =~ s/^%2b//i; # au GPSOneの場合
217                         my ($wx, $wy) = (dms_to_degree($h{lat}), dms_to_degree($h{lon}));
218                         my ($tx, $ty) = wgs84_to_tokyo($wx, $wy);
219                         my $xml_code = get_rgeocode_xml($wx, $wy);
220                         unless($xml_code){
221                                 $p->{error} = 1;
222                                 $p->{rgeocode_noresponse} = 1;
223                                 return $view->render('location_receiver.html', $p);
224                         }
225
226                         my $xml = XMLin($xml_code);
227                         if($xml->{status} ne 'true'){
228                                 $p->{error} = 1;
229                                 $p->{rgeocode_invalid} = 1;
230                                 return $view->render('location_receiver.html', $p);
231                         }
232                         $p->{wx} = $wx;
233                         $p->{wy} = $wy;
234                         $p->{tx} = $tx;
235                         $p->{ty} = $ty;
236                         $p->{map_image_url} = google_map_image($wx, $wy, 'png');
237                         $p->{address} = $xml->{prefecture}->{pname} .
238                                         $xml->{municipality}->{mname} .
239                                         $xml->{local}->{section};
240                         Encode::_utf8_off($p->{address}) if Encode::is_utf8($p->{address});
241                         Encode::from_to($p->{address}, 'utf8', $::cf->web_charset());
242                         return $view->render('location_receiver.html', $p);
243                 }
244
245                 # http://developer.emnet.ne.jp/browser3-1.html
246                 # Example:
247                 # http://www.emobilemap.net/positioning.cgi?ver=MOPA-001-2001&pos=N35.44.33.156E135.22.33.124&geo=wgs84&x-acy=1
248                 if($ci->is_emobile()){
249                         unless(defined $h{pos}) {
250                                 $p->{error} = 1;
251                                 $p->{error_lcs} = 1;
252                                 return $view->render('location_receiver.html', $p);
253                         }
254
255                         my ($wx, $wy);
256                         if($h{pos} =~ /N([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)E([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/){
257                                 ($wx, $wy) = ($1, $2);
258                         }
259
260                         ($wx, $wy) = (dms_to_degree($wx), dms_to_degree($wy));
261                         my ($tx, $ty) = wgs84_to_tokyo($wx, $wy);
262                         my $xml_code = get_rgeocode_xml($wx, $wy);
263                         unless($xml_code){
264                                 $p->{error} = 1;
265                                 $p->{rgeocode_noresponse} = 1;
266                                 return $view->render('location_receiver.html', $p);
267                         }
268
269                         my $xml = XMLin($xml_code);
270                         if($xml->{status} ne 'true'){
271                                 $p->{error} = 1;
272                                 $p->{rgeocode_invalid} = 1;
273                                 return $view->render('location_receiver.html', $p);
274                         }
275                         $p->{wx} = $wx;
276                         $p->{wy} = $wy;
277                         $p->{tx} = $tx;
278                         $p->{ty} = $ty;
279                         $p->{map_image_url} = google_map_image($wx, $wy, 'gif');
280                         $p->{address} = $xml->{prefecture}->{pname} .
281                                         $xml->{municipality}->{mname} .
282                                         $xml->{local}->{section};
283                         Encode::_utf8_off($p->{address}) if Encode::is_utf8($p->{address});
284                         Encode::from_to($p->{address}, 'utf8', $::cf->web_charset());
285                         return $view->render('location_receiver.html', $p);
286                 }
287
288                 return $view->render('location_receiver.html', $p);
289         }
290 };
291
292 1;