X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=keitairc;h=fc7afd4353b87648a0ca790b0225875ffa81b938;hb=911efc4e3a629ad7cc491ac836cac93a2da9e2e7;hp=f6768df8a6884e7cfb427abb3a838c1ff37be159;hpb=fe827ca02bb0a71e385565c1fa6b9a071a33819b;p=keitairc%2Fkeitairc.git diff --git a/keitairc b/keitairc index f6768df..fc7afd4 100755 --- a/keitairc +++ b/keitairc @@ -1,17 +1,17 @@ #!/usr/bin/perl +# -*- mode: perl; coding: utf-8 -*- # keitairc -# $Id: keitairc,v 1.47 2008-05-02 14:40:27 matusita Exp $ -# $Source: /home/ishikawa/work/keitairc/tmp/keitairc/keitairc,v $ # -# Copyright (c) 2003-2008 Jun Morimoto +# Copyright (c) 2003-2010 Jun Morimoto # This program is covered by the GNU General Public License 2 # # Depends: libpoe-component-irc-perl, # liburi-perl, libwww-perl, libappconfig-perl, libproc-daemon-perl, # libhtml-template-perl +# +# 00location_receiver plugin use XML::Simple, so if you want to use it +# Depends: libxml-simple-perl -use lib qw(lib /usr/share/keitairc/lib); -use strict; use Encode; use POE; use POE::Filter::HTTPD; @@ -20,7 +20,10 @@ use POE::Component::Server::TCP; use URI::Escape; use HTML::Template; use HTTP::Response; -use Proc::Daemon; +use HTTP::Status; + +use FindBin; +use lib ("$FindBin::Bin/lib", '/usr/share/keitairc/lib'); use Keitairc::Config; use Keitairc::View; use Keitairc::IrcBuffer; @@ -28,23 +31,34 @@ use Keitairc::IrcCallback; use Keitairc::ClientInfo; use Keitairc::SessionManager; use Keitairc::Plugins; +use Keitairc::Log; +use strict; +use warnings; -our $cf = new Keitairc::Config('2.0b5', @ARGV); -our $ib = new Keitairc::IrcBuffer({history => $cf->web_lines()}); -our $sm = new Keitairc::SessionManager({default_ttl => $cf->session_ttl()}); -our $pl = new Keitairc::Plugins({config => $cf}); +our $cf = new Keitairc::Config({version => '2.1a1', argv => \@ARGV}); # daemonize if($cf->daemonize()){ - Proc::Daemon::Init; - if(length $cf->pid_dir()){ - if (open(PID, '> ' . $cf->pid_dir() . '/' . $cf->pid_file())) { - print PID $$, "\n"; - close(PID); + if (eval 'require Proc::Daemon') { + require Proc::Daemon; + Proc::Daemon::Init(); + if(length $cf->pid_dir()){ + if (open(PID, '> ' . $cf->pid_dir() . '/' . $cf->pid_file())) { + print PID $$, "\n"; + close(PID); + } } + $poe_kernel->has_forked if ($poe_kernel->can('has_forked')); + } else { + warn('Proc::Daemon module is not installed, could not daemonize'); } } +our $log = new Keitairc::Log({config => $cf}); +our $ib = new Keitairc::IrcBuffer({history => $cf->web_lines()}); +our $sm = new Keitairc::SessionManager({default_ttl => $cf->session_ttl()}); +our $pl = new Keitairc::Plugins({config => $cf}); + # create irc component our $irc = POE::Component::IRC->spawn( Alias => 'keitairc_irc', @@ -68,12 +82,15 @@ POE::Session->create( _start => \&Keitairc::IrcCallback::irc_start, autoping => \&Keitairc::IrcCallback::irc_autoping, connect => \&Keitairc::IrcCallback::irc_connect, + irc_registered => \&Keitairc::IrcCallback::irc_registered, irc_001 => \&Keitairc::IrcCallback::irc_001, irc_join => \&Keitairc::IrcCallback::irc_join, irc_part => \&Keitairc::IrcCallback::irc_part, + irc_quit => \&Keitairc::IrcCallback::irc_quit, irc_public => \&Keitairc::IrcCallback::irc_public, irc_notice => \&Keitairc::IrcCallback::irc_notice, irc_mode => \&Keitairc::IrcCallback::irc_mode, + irc_nick => \&Keitairc::IrcCallback::irc_nick, irc_msg => \&Keitairc::IrcCallback::irc_msg, irc_topic => \&Keitairc::IrcCallback::irc_topic, irc_332 => \&Keitairc::IrcCallback::irc_topicraw, @@ -87,7 +104,7 @@ POE::Session->create( # create web server component POE::Component::Server::TCP->new( Alias => 'keitairc', - Port => $cf->web_port(), + Port => $cf->web_listen_port(), ClientFilter => 'POE::Filter::HTTPD', ClientInput => \&http_request); @@ -105,8 +122,10 @@ sub http_request{ # the responses as they are and finish up. if($request->isa('HTTP::Response')){ $heap->{client}->put($request); + $log->log_error($request->as_string()); }elsif(my $response = dispatch($request)){ $heap->{client}->put($response); + $log->log_access($heap->{'remote_ip'}, $request, $response); } $kernel->yield('shutdown'); @@ -118,7 +137,7 @@ sub dispatch{ my $uri = $request->uri(); my $ci = new Keitairc::ClientInfo($request); - ::log_debug("dispatch: $uri"); + $log->log_debug("dispatch: $uri"); { # chop off $cf->web_root() @@ -142,22 +161,21 @@ sub dispatch{ return action_login_imodeid($request); } - if($uri eq '/robots.txt'){ - return action_robots_txt($request); - } - for my $name ($pl->list_action_plugins()){ if($uri =~ m|^/(S[a-zA-Z]{10})/$name/(.*)| || $uri =~ m|^/(S[a-zA-Z]{10})/$name$|){ if($sm->verify({session_id => $1, user_agent => $ci->user_agent()})){ return add_cookie($pl->{plugins}->{$name}->{action_imprementation}($request, $name, $1, $2), $1); } - return action_redirect_root($request); + if ($ci->is_webkit() && $cf->webkit_newui()) { + return action_error($request, 401); + } else { + return action_redirect_root($request); + } } } - ::log("dispatch: don't know how to dispatch uri[$uri]"); - return action_404($request); + return action_public($request, $uri) || action_error($request, 404); } ################################################################ @@ -176,29 +194,33 @@ sub add_cookie{ $hour, $min, $sec); - my $content = sprintf("sid=%s; expires=%s; \n", $session_id, $expiration); + my $content = sprintf("sid=%s; expires=%s; path=%s; \n", $session_id, $expiration, $cf->web_root()); $response->push_header('Set-Cookie', $content); $response; } ################################################################ -# ’ʏ탍ƒOƒCƒ“‚ÌPOSTæ -# ƒpƒXƒ[ƒh‚ðƒ`ƒFƒbƒN‚µ‚Ä -# ŠÔˆá‚Á‚Ä‚¢‚½‚ç / ‚ÖƒŠƒ“ƒN‚µ‚ďI‚í‚è -# ‡‚Á‚Ä‚¢‚½‚çƒZƒbƒVƒ‡ƒ“‚𔭍s‚µ /{SESSION}/index ‚Ö +# 通常ログインのPOST先 +# パスワードをチェックして +# 間違っていたら / へリンクして終わり +# 合っていたらセッションを発行し /{SESSION}/index へ sub action_login{ my $request = shift; my $ci = new Keitairc::ClientInfo($request); my $content = $request->decoded_content(); my ($password) = ($content =~ /^password=(.*)/); - ::log_debug("password [$password]"); - ::log_debug("web_password [" . $cf->web_password() . "]"); + $log->log_debug("password [$password]"); + $log->log_debug("web_password [" . $cf->web_password() . "]"); if($cf->web_password() eq $password){ - my $s = $sm->add($ci->{header}->{user_agent}, $ci->serial_key()); + my $s = $sm->add($ci->user_agent(), $ci->serial_key()); my $view = new Keitairc::View($cf, $ci, $s->{id}); - return $view->redirect("/$s->{id}/index"); + if ($ci->is_webkit() && $cf->webkit_newui()) { + return add_cookie($view->redirect('/'), $s->{id}); + } else { + return $view->redirect("/$s->{id}/index"); + } } # password mismatch @@ -207,25 +229,29 @@ sub action_login{ } ################################################################ -sub action_404{ +sub action_error { my $request = shift; + my $error_code = shift; my $ci = new Keitairc::ClientInfo($request); my $view = new Keitairc::View($cf, $ci); - return $view->render('404.html', { action => $request->uri() }); + return $view->render('error.html', { action => $request->uri(), + _http_status_code => $error_code, + _http_status_message => status_message($error_code) }); } ################################################################ -sub action_robots_txt{ +sub action_public { my $request = shift; + my $uri = shift; # such as '/favicon.ico' my $ci = new Keitairc::ClientInfo($request); my $view = new Keitairc::View($cf, $ci); - return $view->render('robots.txt', { content_type => 'text/plain' }); + return $view->public($request, $uri); } ################################################################ -# ‚©‚ñ‚½‚ñƒƒOƒCƒ“‚ÌPOSTæ -# DoCoMo‚¾‚Á‚½‚çicc‚ª—ˆ‚Ä‚¢‚é‚Í‚¸‚È‚Ì‚Å, icc + user_agent ‚Ń`ƒFƒbƒNB -# ‡‚Á‚Ä‚¢‚½‚çƒZƒbƒVƒ‡ƒ“•œ‹A‚µ‚Ä /{SESSION}/index ‚Ö +# かんたんログインのPOST先 +# DoCoMoだったらiccが来ているはずなので, icc + user_agent でチェック。 +# 合っていたらセッション復帰して /{SESSION}/index へ sub action_login_icc{ my $request = shift; my $ci = new Keitairc::ClientInfo($request); @@ -234,14 +260,14 @@ sub action_login_icc{ if(length $docomo_foma_icc){ if(my $s = $sm->verify({serial_key => $docomo_foma_icc, user_agent => $ci->user_agent()})){ - ::log_debug("redirect to /$s->{id}/index from docomo_foma_icc"); + $log->log_debug("redirect to /$s->{id}/index from docomo_foma_icc"); my $view = new Keitairc::View($cf, $ci, $s->{id}); return $view->redirect("/$s->{id}/index"); } if($docomo_foma_icc eq $cf->docomo_foma_icc()){ my $s = $sm->add($ci->user_agent(), $docomo_foma_icc); - ::log_debug("redirect to /$s->{id}/index from docomo_foma_icc"); + $log->log_debug("redirect to /$s->{id}/index from docomo_foma_icc"); my $view = new Keitairc::View($cf, $ci, $s->{id}); return $view->redirect("/$s->{id}/index"); } @@ -252,29 +278,32 @@ sub action_login_icc{ } my $view = new Keitairc::View($cf, $ci); - return $view->render('root.html', { docomo => $ci->is_docomo() }); + return $view->render('root.html', { + docomo_foma_icc => $cf->docomo_foma_icc(), + docomo_imodeid => $cf->docomo_imodeid(), + }); } ################################################################ -# ‚©‚ñ‚½‚ñƒƒOƒCƒ“‚ÌPOSTæ -# DoCoMo‚¾‚Á‚½‚çiƒ‚[ƒhID‚ª—ˆ‚Ä‚¢‚é‚Í‚¸‚È‚Ì‚Å, iƒ‚[ƒhID + user_agent ‚Ń`ƒFƒbƒNB -# ‡‚Á‚Ä‚¢‚½‚çƒZƒbƒVƒ‡ƒ“•œ‹A‚µ‚Ä /{SESSION}/index ‚Ö +# かんたんログインのPOST先 +# DoCoMoだったらiモードIDが来ているはずなので, iモードID + user_agent でチェック。 +# 合っていたらセッション復帰して /{SESSION}/index へ sub action_login_imodeid{ my $request = shift; my $ci = new Keitairc::ClientInfo($request); if($ci->is_docomo()){ - my $docomo_imodeid = $ci->{header}->{x_dcmguid}; + my $docomo_imodeid = $ci->docomo_imodeid(); if(length $docomo_imodeid){ if(my $s = $sm->verify({serial_key => $docomo_imodeid, user_agent => $ci->user_agent()})){ - ::log_debug("redirect to /$s->{id}/index from docomo_imodeid"); + $log->log_debug("redirect to /$s->{id}/index from docomo_imodeid"); my $view = new Keitairc::View($cf, $ci, $s->{id}); return $view->redirect("/$s->{id}/index"); } if($docomo_imodeid eq $cf->docomo_imodeid()){ my $s = $sm->add($ci->user_agent(), $docomo_imodeid); - ::log_debug("redirect to /$s->{id}/index from docomo_imodeid"); + $log->log_debug("redirect to /$s->{id}/index from docomo_imodeid"); my $view = new Keitairc::View($cf, $ci, $s->{id}); return $view->redirect("/$s->{id}/index"); } @@ -285,7 +314,10 @@ sub action_login_imodeid{ } my $view = new Keitairc::View($cf, $ci); - return $view->render('root.html', { docomo => $ci->is_docomo() }); + return $view->render('root.html', { + docomo_foma_icc => $cf->docomo_foma_icc(), + docomo_imodeid => $cf->docomo_imodeid(), + }); } ################################################################ @@ -295,29 +327,33 @@ sub action_root{ if($ci->cookie_available()){ my $session_id = $ci->{cookie}->{sid}; - if(length $session_id){ + if(defined($session_id) && length($session_id)){ if($sm->verify({session_id => $session_id, user_agent => $ci->user_agent()})){ - ::log_debug("redirect to /$session_id/index from cookie"); + $log->log_debug("redirect to /$session_id/index from cookie"); my $view = new Keitairc::View($cf, $ci, $session_id); - return $view->redirect("/$session_id/index"); + if ($ci->is_webkit() && $cf->webkit_newui()) { + return add_cookie($view->render('root_home.html', {sid => $session_id}), $session_id); + } else { + return $view->redirect("/$session_id/index"); + } } } } if($ci->is_ezweb()){ - my $subscriber_id = $ci->{header}->{x_up_subno}; + my $subscriber_id = $ci->au_subscriber_id(); if(length $subscriber_id){ if(my $s = $sm->verify({serial_key => $subscriber_id, user_agent => $ci->user_agent()})){ - ::log_debug("redirect to /$s->{id}/index from subscriber_id"); + $log->log_debug("redirect to /$s->{id}/index from subscriber_id"); my $view = new Keitairc::View($cf, $ci, $s->{id}); return $view->redirect("/$s->{id}/index"); } if($subscriber_id eq $cf->au_subscriber_id()){ my $s = $sm->add($ci->user_agent(), $subscriber_id); - ::log_debug("redirect to /$s->{id}/index from au_subscriber_id"); + $log->log_debug("redirect to /$s->{id}/index from au_subscriber_id"); my $view = new Keitairc::View($cf, $ci, $s->{id}); return $view->redirect("/$s->{id}/index"); } @@ -329,13 +365,32 @@ sub action_root{ if(length $serial_key){ if(my $s = $sm->verify({serial_key => $serial_key, user_agent => $ci->user_agent()})){ - ::log_debug("redirect to /$s->{id}/index from softbank serial_key"); + $log->log_debug("redirect to /$s->{id}/index from softbank serial_key"); my $view = new Keitairc::View($cf, $ci, $s->{id}); return $view->redirect("/$s->{id}/index"); } if($serial_key eq $cf->softbank_serial_key()){ my $s = $sm->add($ci->user_agent(), $serial_key); - ::log_debug("redirect to /$s->{id}/index from au_subscriber_id"); + $log->log_debug("redirect to /$s->{id}/index from softbank_serial_key"); + my $view = new Keitairc::View($cf, $ci, $s->{id}); + return $view->redirect("/$s->{id}/index"); + } + } + } + + if($ci->is_emobile()){ + my $userid = $ci->emobile_userid(); + if(length $userid){ + if(my $s = $sm->verify({serial_key => $userid, + user_agent => $ci->user_agent()})){ + $log->log_debug("redirect to /$s->{id}/index from userid"); + my $view = new Keitairc::View($cf, $ci, $s->{id}); + return $view->redirect("/$s->{id}/index"); + } + + if($userid eq $cf->emobile_userid()){ + my $s = $sm->add($ci->user_agent(), $userid); + $log->log_debug("redirect to /$s->{id}/index from emobile_userid"); my $view = new Keitairc::View($cf, $ci, $s->{id}); return $view->redirect("/$s->{id}/index"); } @@ -343,7 +398,10 @@ sub action_root{ } my $view = new Keitairc::View($cf, $ci); - return $view->render('root.html', { docomo => $ci->is_docomo() }); + return $view->render('root.html', { + docomo_foma_icc => $cf->docomo_foma_icc(), + docomo_imodeid => $cf->docomo_imodeid(), + }); } ################################################################ @@ -355,77 +413,91 @@ sub action_redirect_root{ } ################################################################ -sub send_message{ +sub parse_message{ my $request = shift; - my $channel = shift; + my $ci = new Keitairc::ClientInfo($request); + my $timestamp; my $message = $request->content(); - $message =~ s/^m=//; - $message =~ s/\+/ /g; - $message = uri_unescape($message); if(length($message)){ - my $jis = $message; - my $euc = $message; - Encode::from_to($jis, 'shiftjis', 'jis'); - Encode::from_to($euc, 'shiftjis', 'euc-jp'); - $irc->yield(privmsg => $channel => $jis); - my $cid = $ib->name2cid($channel); - $ib->add_message($cid, $euc, $cf->irc_nick()); - $ib->message_added(1); - } -} + ($message, $timestamp) = split(/&/, $message); -################################################################ -# “ü—Í‚Í euc-jp -sub render_line{ - local($_); - my $in = shift; - my $session_id = shift; - my $reverse = shift; - my @message; - my $buf; + $timestamp =~ s/^stamp=//g; - @message = (split("\n", $in))[0 .. $cf->web_lines()]; - if ($reverse) { - @message = reverse(@message); + $message =~ s/^m=//; + $message =~ s/\+/ /g; + $message = uri_unescape($message); + + if($ci->is_webkit() && !$cf->webkit_newui()){ + $message = fix_webkit_escape($message); + } } - for (@message){ - next unless defined; - next unless length; + if ($cf->webkit_newui()) { + # ajax で投げ込んでるので utf8 できます + $message = Encode::decode('utf8', $message); + } else { + $message = Encode::decode($cf->web_charset(), $message); + } + return ($message, $timestamp); +} + +sub send_message{ + my $request = shift; + my $channel = shift; - $_ = $ib->simple_escape($_); - $_ = $ib->colorize($_); + my ($message, $timestamp) = parse_message($request); - for my $name ($pl->list_replace_plugins()){ - 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; + if(length($message) && length($channel)){ + if($ib->update_timestamp($timestamp)){ + my $enc_message = Encode::encode($cf->irc_charset(), $message); + my $enc_channel = Encode::encode($cf->irc_charset(), $channel); + $irc->yield(privmsg => $enc_channel => $enc_message); + my $cid = $ib->name2cid($channel); + $ib->add_message($cid, $message, $cf->irc_nick()); } - - s/\s+$//; - s/\s+/ /g; - $buf .= "$_
"; } - - Encode::from_to($buf, 'euc-jp', 'shiftjis'); - $buf; } -################################################################ -sub log{ - my $m = shift; - warn "keitairc: $m\n"; -} +sub send_command{ + my $request = shift; -sub log_die{ - my $m = shift; - die "keitairc: $m\n"; -} + my ($message, $timestamp) = parse_message($request); -sub log_debug{ - my $m = shift; - if($cf->debug()){ - warn "keitairc(debug): $m\n"; + if(length($message)){ + if($message =~ s|^/||) { + my ($params, $trailing) = split(/ :/, $message, 2); + my @postcmd = split(/ /, $params); + push @postcmd, $trailing if defined $trailing; + # This parser may be incomplete. + if($postcmd[0] =~ /join/i) { + if($postcmd[1] =~ /^\w/) { + $ib->join($postcmd[1]); + return; + } + } elsif($postcmd[0] =~ /part/i) { + if($postcmd[1] =~ /^\w/) { + $ib->part($ib->name2cid($postcmd[1])); + return; + } + } + $irc->yield(map { Encode::encode($cf->irc_charset(), $_) } @postcmd); + } } } +################################################################ +# posted string from Webkit browser +# contains escaped utf-8 in the form %uXXXX +# and may contains escaped Shift-JIS (web_charset) in the form \xXX +# when operated from Safari/Mac OS X +sub fix_webkit_escape{ + # charset: $cf->irc_charset() + my $in = shift; + $in =~ s/\\x([0-9A-F]{2})/pack('C',hex($1))/egi; + #my $pi = Encode::decode('utf8', $in); + $in =~ s/%u([0-9A-F]{4})/pack('U',hex($1))/egi; + return $in; +} + __END__