3 # $Id: keitairc,v 1.57 2008-06-25 07:05:52 matusita Exp $
4 # $Source: /home/ishikawa/work/keitairc/tmp/keitairc/keitairc,v $
6 # Copyright (c) 2003-2008 Jun Morimoto <morimoto@mrmt.net>
7 # This program is covered by the GNU General Public License 2
9 # Depends: libpoe-component-irc-perl,
10 # liburi-perl, libwww-perl, libappconfig-perl, libproc-daemon-perl,
11 # libhtml-template-perl
13 # 00location_receiver plugin use XML::Simple, so if you want to use it
14 # Depends: libxml-simple-perl
16 use lib qw(lib /usr/share/keitairc/lib);
20 use POE::Filter::HTTPD;
21 use POE::Component::IRC;
22 use POE::Component::Server::TCP;
28 use Keitairc::IrcBuffer;
29 use Keitairc::IrcCallback;
30 use Keitairc::ClientInfo;
31 use Keitairc::SessionManager;
32 use Keitairc::Plugins;
34 our $cf = new Keitairc::Config('2.0b5', @ARGV);
35 our $ib = new Keitairc::IrcBuffer({history => $cf->web_lines()});
36 our $sm = new Keitairc::SessionManager({default_ttl => $cf->session_ttl()});
37 our $pl = new Keitairc::Plugins({config => $cf});
44 if(length $cf->pid_dir()){
45 if (open(PID, '> ' . $cf->pid_dir() . '/' . $cf->pid_file())) {
52 # create irc component
53 our $irc = POE::Component::IRC->spawn(
54 Alias => 'keitairc_irc',
55 Nick => $cf->irc_nick(),
56 Username => $cf->irc_username(),
57 Ircname => $cf->irc_desc(),
58 Server => $cf->irc_server(),
59 Port => $cf->irc_port(),
60 Password => $cf->irc_password());
72 _start => \&Keitairc::IrcCallback::irc_start,
73 autoping => \&Keitairc::IrcCallback::irc_autoping,
74 connect => \&Keitairc::IrcCallback::irc_connect,
75 irc_registered => \&Keitairc::IrcCallback::irc_registered,
76 irc_001 => \&Keitairc::IrcCallback::irc_001,
77 irc_join => \&Keitairc::IrcCallback::irc_join,
78 irc_part => \&Keitairc::IrcCallback::irc_part,
79 irc_quit => \&Keitairc::IrcCallback::irc_quit,
80 irc_public => \&Keitairc::IrcCallback::irc_public,
81 irc_notice => \&Keitairc::IrcCallback::irc_notice,
82 irc_mode => \&Keitairc::IrcCallback::irc_mode,
83 irc_nick => \&Keitairc::IrcCallback::irc_nick,
84 irc_msg => \&Keitairc::IrcCallback::irc_msg,
85 irc_topic => \&Keitairc::IrcCallback::irc_topic,
86 irc_332 => \&Keitairc::IrcCallback::irc_topicraw,
87 irc_352 => \&Keitairc::IrcCallback::irc_whoreply,
88 irc_ctcp_action => \&Keitairc::IrcCallback::irc_ctcp_action,
89 irc_disconnected => \&Keitairc::IrcCallback::irc_reconnect,
90 irc_error => \&Keitairc::IrcCallback::irc_reconnect,
91 irc_socketerr => \&Keitairc::IrcCallback::irc_reconnect,
94 # create web server component
95 POE::Component::Server::TCP->new(
97 Port => $cf->web_port(),
98 ClientFilter => 'POE::Filter::HTTPD',
99 ClientInput => \&http_request);
105 ################################################################
107 my ($kernel, $heap, $request) = @_[KERNEL, HEAP, ARG0];
109 # Filter::HTTPD sometimes generates HTTP::Response objects.
110 # They indicate (and contain the response for) errors that occur
111 # while parsing the client's HTTP request. It's easiest to send
112 # the responses as they are and finish up.
113 if($request->isa('HTTP::Response')){
114 $heap->{client}->put($request);
115 }elsif(my $response = dispatch($request)){
116 $heap->{client}->put($response);
119 $kernel->yield('shutdown');
122 ################################################################
125 my $uri = $request->uri();
126 my $ci = new Keitairc::ClientInfo($request);
128 ::log_debug("dispatch: $uri");
131 # chop off $cf->web_root()
132 my $root = $cf->web_root();
137 return action_root($request);
140 if($uri eq '/login'){
141 return action_login($request);
144 if($uri eq '/login_icc'){
145 return action_login_icc($request);
148 if($uri eq '/login_imodeid?guid=ON'){
149 return action_login_imodeid($request);
152 if($uri eq '/robots.txt'){
153 return action_robots_txt($request);
156 for my $name ($pl->list_action_plugins()){
157 if($uri =~ m|^/(S[a-zA-Z]{10})/$name/(.*)| ||
158 $uri =~ m|^/(S[a-zA-Z]{10})/$name$|){
159 if($sm->verify({session_id => $1, user_agent => $ci->user_agent()})){
160 return add_cookie($pl->{plugins}->{$name}->{action_imprementation}($request, $name, $1, $2), $1);
162 return action_redirect_root($request);
166 ::log("dispatch: don't know how to dispatch uri[$uri]");
167 return action_404($request);
170 ################################################################
171 # adds session id cookie to http response object
173 my $response = shift;
174 my $session_id = shift;
176 my ($sec, $min, $hour, $mday, $mon, $year, $wday) = localtime(time + $cf->cookie_ttl());
178 sprintf('%.3s, %.2d-%.3s-%.4s %.2d:%.2d:%.2d',
179 qw(Sun Mon Tue Wed Thu Fri Sat)[$wday],
181 qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)[$mon],
186 my $content = sprintf("sid=%s; expires=%s; \n", $session_id, $expiration);
187 $response->push_header('Set-Cookie', $content);
191 ################################################################
192 #
\92Ê
\8fí
\83\8d\83O
\83C
\83\93\82ÌPOST
\90æ
193 #
\83p
\83X
\83\8f\81[
\83h
\82ð
\83`
\83F
\83b
\83N
\82µ
\82Ä
194 #
\8aÔ
\88á
\82Á
\82Ä
\82¢
\82½
\82ç /
\82Ö
\83\8a\83\93\83N
\82µ
\82Ä
\8fI
\82í
\82è
195 #
\8d\87\82Á
\82Ä
\82¢
\82½
\82ç
\83Z
\83b
\83V
\83\87\83\93\82ð
\94
\8ds
\82µ /{SESSION}/index
\82Ö
198 my $ci = new Keitairc::ClientInfo($request);
199 my $content = $request->decoded_content();
200 my ($password) = ($content =~ /^password=(.*)/);
202 ::log_debug("password [$password]");
203 ::log_debug("web_password [" . $cf->web_password() . "]");
205 if($cf->web_password() eq $password){
206 my $s = $sm->add($ci->{header}->{user_agent}, $ci->serial_key());
207 my $view = new Keitairc::View($cf, $ci, $s->{id});
208 return $view->redirect("/$s->{id}/index");
212 my $view = new Keitairc::View($cf, $ci);
213 return $view->redirect('/');
216 ################################################################
219 my $ci = new Keitairc::ClientInfo($request);
220 my $view = new Keitairc::View($cf, $ci);
221 return $view->render('404.html', { action => $request->uri() });
224 ################################################################
225 sub action_robots_txt{
227 my $ci = new Keitairc::ClientInfo($request);
228 my $view = new Keitairc::View($cf, $ci);
229 return $view->render('robots.txt', { content_type => 'text/plain' });
232 ################################################################
233 #
\82©
\82ñ
\82½
\82ñ
\83\8d\83O
\83C
\83\93\82ÌPOST
\90æ
234 # DoCoMo
\82¾
\82Á
\82½
\82çicc
\82ª
\97\88\82Ä
\82¢
\82é
\82Í
\82¸
\82È
\82Ì
\82Å, icc + user_agent
\82Å
\83`
\83F
\83b
\83N
\81B
235 #
\8d\87\82Á
\82Ä
\82¢
\82½
\82ç
\83Z
\83b
\83V
\83\87\83\93\95\9c\8bA
\82µ
\82Ä /{SESSION}/index
\82Ö
236 sub action_login_icc{
238 my $ci = new Keitairc::ClientInfo($request);
239 if($ci->is_docomo()){
240 my $docomo_foma_icc = $ci->docomo_foma_icc();
241 if(length $docomo_foma_icc){
242 if(my $s = $sm->verify({serial_key => $docomo_foma_icc,
243 user_agent => $ci->user_agent()})){
244 ::log_debug("redirect to /$s->{id}/index from docomo_foma_icc");
245 my $view = new Keitairc::View($cf, $ci, $s->{id});
246 return $view->redirect("/$s->{id}/index");
249 if($docomo_foma_icc eq $cf->docomo_foma_icc()){
250 my $s = $sm->add($ci->user_agent(), $docomo_foma_icc);
251 ::log_debug("redirect to /$s->{id}/index from docomo_foma_icc");
252 my $view = new Keitairc::View($cf, $ci, $s->{id});
253 return $view->redirect("/$s->{id}/index");
256 my $view = new Keitairc::View($cf, $ci);
257 return $view->render('login_icc.html', { icc => $docomo_foma_icc });
261 my $view = new Keitairc::View($cf, $ci);
262 return $view->render('root.html', {
263 docomo_foma_icc => $cf->docomo_foma_icc(),
264 docomo_imodeid => $cf->docomo_imodeid(),
268 ################################################################
269 #
\82©
\82ñ
\82½
\82ñ
\83\8d\83O
\83C
\83\93\82ÌPOST
\90æ
270 # DoCoMo
\82¾
\82Á
\82½
\82çi
\83\82\81[
\83hID
\82ª
\97\88\82Ä
\82¢
\82é
\82Í
\82¸
\82È
\82Ì
\82Å, i
\83\82\81[
\83hID + user_agent
\82Å
\83`
\83F
\83b
\83N
\81B
271 #
\8d\87\82Á
\82Ä
\82¢
\82½
\82ç
\83Z
\83b
\83V
\83\87\83\93\95\9c\8bA
\82µ
\82Ä /{SESSION}/index
\82Ö
272 sub action_login_imodeid{
274 my $ci = new Keitairc::ClientInfo($request);
275 if($ci->is_docomo()){
276 my $docomo_imodeid = $ci->{header}->{x_dcmguid};
277 if(length $docomo_imodeid){
278 if(my $s = $sm->verify({serial_key => $docomo_imodeid,
279 user_agent => $ci->user_agent()})){
280 ::log_debug("redirect to /$s->{id}/index from docomo_imodeid");
281 my $view = new Keitairc::View($cf, $ci, $s->{id});
282 return $view->redirect("/$s->{id}/index");
285 if($docomo_imodeid eq $cf->docomo_imodeid()){
286 my $s = $sm->add($ci->user_agent(), $docomo_imodeid);
287 ::log_debug("redirect to /$s->{id}/index from docomo_imodeid");
288 my $view = new Keitairc::View($cf, $ci, $s->{id});
289 return $view->redirect("/$s->{id}/index");
292 my $view = new Keitairc::View($cf, $ci);
293 return $view->render('login_imodeid.html', { imodeid => $docomo_imodeid });
297 my $view = new Keitairc::View($cf, $ci);
298 return $view->render('root.html', {
299 docomo_foma_icc => $cf->docomo_foma_icc(),
300 docomo_imodeid => $cf->docomo_imodeid(),
304 ################################################################
307 my $ci = new Keitairc::ClientInfo($request);
309 if($ci->cookie_available()){
310 my $session_id = $ci->{cookie}->{sid};
311 if(length $session_id){
312 if($sm->verify({session_id => $session_id,
313 user_agent => $ci->user_agent()})){
314 ::log_debug("redirect to /$session_id/index from cookie");
315 my $view = new Keitairc::View($cf, $ci, $session_id);
316 return $view->redirect("/$session_id/index");
322 my $subscriber_id = $ci->{header}->{x_up_subno};
323 if(length $subscriber_id){
324 if(my $s = $sm->verify({serial_key => $subscriber_id,
325 user_agent => $ci->user_agent()})){
326 ::log_debug("redirect to /$s->{id}/index from subscriber_id");
327 my $view = new Keitairc::View($cf, $ci, $s->{id});
328 return $view->redirect("/$s->{id}/index");
331 if($subscriber_id eq $cf->au_subscriber_id()){
332 my $s = $sm->add($ci->user_agent(), $subscriber_id);
333 ::log_debug("redirect to /$s->{id}/index from au_subscriber_id");
334 my $view = new Keitairc::View($cf, $ci, $s->{id});
335 return $view->redirect("/$s->{id}/index");
340 if($ci->is_softbank()){
341 my $serial_key = $ci->softbank_serial();
342 if(length $serial_key){
343 if(my $s = $sm->verify({serial_key => $serial_key,
344 user_agent => $ci->user_agent()})){
345 ::log_debug("redirect to /$s->{id}/index from softbank serial_key");
346 my $view = new Keitairc::View($cf, $ci, $s->{id});
347 return $view->redirect("/$s->{id}/index");
349 if($serial_key eq $cf->softbank_serial_key()){
350 my $s = $sm->add($ci->user_agent(), $serial_key);
351 ::log_debug("redirect to /$s->{id}/index from softbank_serial_key");
352 my $view = new Keitairc::View($cf, $ci, $s->{id});
353 return $view->redirect("/$s->{id}/index");
358 if($ci->is_emobile()){
359 my $userid = $ci->{header}->{x_em_uid};
361 if(my $s = $sm->verify({serial_key => $userid,
362 user_agent => $ci->user_agent()})){
363 ::log_debug("redirect to /$s->{id}/index from userid");
364 my $view = new Keitairc::View($cf, $ci, $s->{id});
365 return $view->redirect("/$s->{id}/index");
368 if($userid eq $cf->emobile_userid()){
369 my $s = $sm->add($ci->user_agent(), $userid);
370 ::log_debug("redirect to /$s->{id}/index from emobile_userid");
371 my $view = new Keitairc::View($cf, $ci, $s->{id});
372 return $view->redirect("/$s->{id}/index");
377 my $view = new Keitairc::View($cf, $ci);
378 return $view->render('root.html', {
379 docomo_foma_icc => $cf->docomo_foma_icc(),
380 docomo_imodeid => $cf->docomo_imodeid(),
384 ################################################################
385 sub action_redirect_root{
387 my $ci = new Keitairc::ClientInfo($request);
388 my $view = new Keitairc::View($cf, $ci);
389 return $view->redirect('/');
392 ################################################################
397 my $message = $request->content();
399 $message =~ s/\+/ /g;
400 $message = uri_unescape($message);
402 if(length($message)){
405 Encode::from_to($jis, 'shiftjis', 'jis');
406 Encode::from_to($euc, 'shiftjis', 'euc-jp');
408 my ($params, $trailing) = split(/ :/, $jis, 2);
409 my @postcmd = split(/ /, $params);
410 push @postcmd, $trailing if defined $trailing;
411 # This parser may be incomplete.
412 if($postcmd[0] =~ /join/i) {
413 if($postcmd[1] =~ /^\w/) {
414 $ib->join($postcmd[1]);
417 } elsif($postcmd[0] =~ /part/i) {
418 if($postcmd[1] =~ /^\w/) {
419 $ib->part($ib->name2cid($postcmd[1]));
423 $irc->yield(@postcmd);
424 } elsif(length($channel)){
425 $irc->yield(privmsg => $channel => $jis);
426 my $cid = $ib->name2cid($channel);
427 $ib->add_message($cid, $euc, $cf->irc_nick());
428 $ib->message_added(1);
433 ################################################################
434 #
\93ü
\97Í
\82Í euc-jp
438 my $session_id = shift;
443 @message = (split("\n", $in))[0 .. $cf->web_lines()];
445 @message = reverse(@message);
451 $_ = $ib->simple_escape($_);
452 $_ = $ib->colorize($_);
454 for my $name ($pl->list_replace_plugins()){
455 last if s/$pl->{plugins}->{$name}->{message_replace_regexp}/$pl->{plugins}->{$name}->{message_replace_imprementation}($session_id, $1, $2, $3, $4, $5, $6, $7, $8, $9)/eg;
463 Encode::from_to($buf, 'euc-jp', 'shiftjis');
467 ################################################################
470 warn "keitairc: $m\n";
475 die "keitairc: $m\n";
481 warn "keitairc(debug): $m\n";