#!/usr/bin/perl
# ===============================================================
# Twitterを携帯とかでスマートに使おうかなとか思って
# でっちあげたPerlスクリプト
#
# "Twimp" v0.9 by iMp / SOU1
$version ="0.9";
#
# ===============================================================
# --------------------------------------
# 以下、通常ユーザー設定項目
# --------------------------------------
# Twitterのアカウント情報
$user = "(Twitterのユーザー名を入力)";
$pass = "(Twitterのパスワードを入力)";
# 画面表示時刻のタイムゾーン
$timezone = 'JST';
# 画面に表示するメッセージ数(最大20)
$msgnum = 10;
# 時刻・名前表示の背景色
$name_bg = "#3377AA";
# 時刻・名前表示の文字色
$name_color = "#FFFFFF";
# ユーザー名のリンクで返信(@〜 )自動追加 : 1で有効/0で無効
$use_reply = 0;
# ユーザー画像 : 1で有効/0で無効
$use_img = 0;
# Status末尾の "from 〜" 表示
# 0 = Twimp
# 1 = web
$stat_from = 0;
# 返信自動追加有効時、BODYタグのリンク色設定
$link ="#88CCFF";
$alink ="#88CCFF";
$vlink ="#88CCFF";
# --------------------------------------
# 以上、ユーザー設定項目
# --------------------------------------
# Twitter投稿先URL
$readuri = "http://twitter.com/statuses/friends_timeline.xml";
$posturi = "http://twitter.com/statuses/update.json";
# Twimp User-Agent
$agent = "twimp/".$version;
# モジュール宣言
use Jcode;
use LWP::UserAgent;
use XML::Simple;
use Data::Dumper;
use HTTP::Date;
# 機種依存文字変換テーブル作成
&init_table;
# スクリプトのファイル名取得
$ENV{'SCRIPT_FILENAME'} =~ /\/([^\/]+)$/;
$filename = $1;
# FORMデータ取得
if ($ENV{'REQUEST_METHOD'} eq "POST") {
read(STDIN, $post_buffer, $ENV{'CONTENT_LENGTH'});
}
$buffer = $ENV{'QUERY_STRING'} . '&' . $post_buffer;
@pairs = split(/&/,$buffer);
# FORMデータ分割
foreach $pair(@pairs) {
($name,$value) = split(/=/,$pair);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$value = &gaiji_conv($value);
Jcode::convert(\$value,'utf8','sjis');
$FORM{$name} = $value;
}
# ----- POST呼び出しの場合→Twitter投稿
if($ENV{'REQUEST_METHOD'} eq "POST") {
# FORMデータ確認
if ($FORM{'message'} eq "") {
&error('メッセージが未記入です');
}
# --- from [appname] の表示内容
if($stat_from == 1) {
$update_source = "web";
} else {
$update_source = "twimp";
}
# メッセージをURLエンコード
$enc_message = url_encode($FORM{'message'});
# ----- LWPを使った投稿処理
# ※twmailを参考にさせて頂きました
# http://polaire.org/r-top/mob/archives/2007/04/twitterperl.html
$req = HTTP::Request->new( POST => $posturi );
$req->authorization_basic( $user, $pass );
if ($FORM{'replyuid'} ne "")
{
$req->content("source=" . $update_source . "&status=" . $enc_message . "&in_reply_to_user_id=" . $FORM{'replyuid'} . "&in_reply_to_status_id=" . $FORM{'replymsgid'} );
}
else
{
$req->content("source=" . $update_source . "&status=" . $enc_message);
}
$req->header("X-Twitter-Client" => "Twimp");
$req->header("X-Twitter-Client-Version" => $version);
$req->header("X-Twitter-Client-URL" => "http://callusnext.com/twimp.xml");
$ua = LWP::UserAgent->new( agent => $agent, keepalive => 4 );
$res = $ua->request( $req );
$status = $res->status_line;
# HTTP Status確認
if ($status !~ m/^200/i) {
&error('取得に失敗しました
ステータス : '.$status);
}
# ----- 成功メッセージ出力
# HTTPヘッダ
&http_header();
# HTML本体
print "
\n";
print "投稿しました。
\n";
print "ステータス:$status
\n";
print "[戻る]
\n";
print "\n";
exit;
}
# 返信先ユーザー名格納
$reply_uid = "";
$reply_msgid = "";
$reply_name = $FORM{'reply'};
if( $reply_name ne "" ) {
Jcode::convert(\$reply_name,'sjis');
$reply_disp = sprintf("@%s ",$reply_name);
$reply_uid = $FORM{'uid'};
$reply_msgid = $FORM{'msgid'};
}
# ----- friends_timeline取得
# LWPを使った取得処理
$req = HTTP::Request->new( GET => $readuri );
$req->authorization_basic( $user, $pass );
$req->header("X-Twitter-Client" => "Twimp");
$req->header("X-Twitter-Client-Version" => $version);
$req->header("X-Twitter-Client-URL" => "http://callusnext.com/twimp.xml");
$ua = LWP::UserAgent->new( agent => $agent, keepalive => 4 );
$res = $ua->request( $req );
$status = $res->status_line;
$content = $res->content;
# HTTP Status確認
if ($status !~ m/^200/i) {
&error('取得に失敗しました
ステータス : '.$status);
}
# XMLパーサ処理(XML::Simple使用)
$xmlparser = XML::Simple->new;
$xmldata = $xmlparser->XMLin($content);
# エントリIDの取得・ソート
@entries_id = sort {$b cmp $a} keys %{$xmldata->{status}};
# ----- HTML出力
# HTTPヘッダ
&http_header();
# HTML本体
print "Twimp\n";
}else {
print "\n";
}
print "[リロード]
\n";
print "\n";
# メッセージ出力
foreach $id (@entries_id) {
# メッセージ数判定
$msgnum--;
if($msgnum < 0)
{
last;
}
# ----- メッセージ整形出力
$uid = $xmldata->{status}->{$id}->{user}->{id};
$text = $xmldata->{status}->{$id}->{text};
$name = $xmldata->{status}->{$id}->{user}->{screen_name};
$img = $xmldata->{status}->{$id}->{user}->{profile_image_url};
$createtime = $xmldata->{status}->{$id}->{created_at};
$createtime =~ s/\+0000/GMT/g;
$createtime = HTTP::Date::str2time($createtime,$timezone);
($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($createtime);
$disptime = sprintf("%02d:%02d",$hour,$min);
$text = &wave_conv($text);
Jcode::convert(\$text,'sjis','utf8');
$name = &wave_conv($name);
Jcode::convert(\$name,'sjis','utf8');
if( $use_reply == 1 ) {
print "$disptime $name
\n";
}else {
print "$disptime $name
\n";
}
if( $use_img == 1 ) {
print "";
}
print "$text\n";
}
print "\n";
exit;
# ========================================================================
# 以下サブルーチン
# ========================================================================
# ================================
# エラー時処理
# ================================
sub error {
# ----- HTML出力
# HTTPヘッダ
&http_header();
# HTML本体
print "Twimp:Error\n";
print "エラー : ".$_[0]."
\n";
print "[戻る]
\n";
print "";
exit;
}
# ================================
# HTTPヘッダ出力
# ================================
sub http_header {
print "Content-type: text/html; charset=Shift_JIS\n";
print "Content-Language: ja\n";
print "Pragma: no-cache\n";
print "Cache-Control: no-cache\n\n";
}
# ================================
# URLエンコード
# ================================
sub url_encode($) {
my $str = shift;
$str =~ s/([^\w ])/'%'.unpack('H2', $1)/eg;
$str =~ tr/ /+/;
return $str;
}
# ================================
# 機種依存文字変換テーブル作成
# ================================
sub init_table {
# windows-932 (Japanese Shift-JIS)
# Gaiji (Lead Byte = 0x87) to Normal
%gaiji_table = (
"\x87\x40" => '(1)',
"\x87\x41" => '(2)',
"\x87\x42" => '(3)',
"\x87\x43" => '(4)',
"\x87\x44" => '(5)',
"\x87\x45" => '(6)',
"\x87\x46" => '(7)',
"\x87\x47" => '(8)',
"\x87\x48" => '(9)',
"\x87\x49" => '(10)',
"\x87\x4a" => '(11)',
"\x87\x4b" => '(12)',
"\x87\x4c" => '(13)',
"\x87\x4d" => '(14)',
"\x87\x4e" => '(15)',
"\x87\x4f" => '(16)',
"\x87\x50" => '(17)',
"\x87\x51" => '(18)',
"\x87\x52" => '(19)',
"\x87\x53" => '(20)',
"\x87\x54" => 'I',
"\x87\x55" => 'II',
"\x87\x56" => 'III',
"\x87\x57" => 'IV',
"\x87\x58" => 'V',
"\x87\x59" => 'VI',
"\x87\x5a" => 'VII',
"\x87\x5b" => 'VIII',
"\x87\x5c" => 'IX',
"\x87\x5d" => 'X',
"\x87\x5f" => 'ミリ',
"\x87\x60" => 'キロ',
"\x87\x61" => 'センチ',
"\x87\x62" => 'メートル',
"\x87\x63" => 'グラム',
"\x87\x64" => 'トン',
"\x87\x65" => 'アール',
"\x87\x66" => 'ヘクタール',
"\x87\x67" => 'リットル',
"\x87\x68" => 'ワット',
"\x87\x69" => 'カロリー',
"\x87\x6a" => 'ドル',
"\x87\x6b" => 'センチ',
"\x87\x6c" => 'パーセント',
"\x87\x6d" => 'ミリバール',
"\x87\x6e" => 'ページ',
"\x87\x6f" => 'mm',
"\x87\x70" => 'cm',
"\x87\x71" => 'km',
"\x87\x72" => 'mg',
"\x87\x73" => 'kg',
"\x87\x74" => 'cc',
"\x87\x75" => 'm2',
"\x87\x7e" => '平成',
"\x87\x80" => '“',
"\x87\x81" => '”',
"\x87\x82" => 'No.',
"\x87\x83" => 'K.K.',
"\x87\x84" => 'TEL',
"\x87\x85" => '(上)',
"\x87\x86" => '(中)',
"\x87\x87" => '(下)',
"\x87\x88" => '(左)',
"\x87\x89" => '(右)',
"\x87\x8a" => '(株)',
"\x87\x8b" => '(有)',
"\x87\x8c" => '(代)',
"\x87\x8d" => '明治',
"\x87\x8e" => '大正',
"\x87\x8f" => '昭和',
"\x87\x90" => '≒',
"\x87\x91" => '≡',
"\x87\x92" => '∫',
"\x87\x93" => 'c∫',
"\x87\x94" => 'Σ',
"\x87\x95" => '√',
"\x87\x96" => '⊥',
"\x87\x97" => '∠',
"\x87\x98" => '└',
"\x87\x99" => 'Δ',
"\x87\x9a" => '∵',
"\x87\x9b" => '∩',
"\x87\x9c" => '∪',
);
}
# ================================
# 機種依存文字変換処理
# from SjisH2Z.pm (c)2005 Niki
# ================================
sub gaiji_conv($) {
my($string) = @_;
my ($j,$c,$c2,@c);
my $ctype = '1'; # 1:ASCII K:半角カナ 2:2バイト文字
my $result;
my $k;
@c = split(//,$string);
for( $j = 0; $j <= $#c; $j++ )
{
$c = $c[$j];
# ASCIIなら
if( $c =~ /[\x00-\x7f]/ )
{
$ctype = '1';
$result .= $c;
}
# 2バイト文字なら
elsif( $c =~ /[\x81-\x9f\xe0-\xff]/ )
{
last if( ++$j > $#c ); $c2 = $c[$j];
if( $c2 =~ /[\x40-\xfc]/ )
{
$ctype = '2';
$result .= $c . $c2;
}
else
{ $result .= $c . $c2; }
}
# それ以外なら
else
{
$ctype = '1';
$result .= $c;
}
}
$ctype = '1';
@c = split(//,$string);
$c = '(?:[\x00-\x7F\xA1-\xDF]|[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])';
$result =~ s/($c)/exists $gaiji_table{$1} ? $gaiji_table{$1} : $1/geo;
return $result;
}
# ================================
# 波線処理
# ================================
sub wave_conv($) {
my($string) = @_;
use bytes;
my $wave_length = length("\xEF\xBD\x9E");
while ((my $i = index($string,"\xEF\xBD\x9E",0)) >= 0)
{
$string = substr($string,0,$i).'~'.substr($string,$i+$wave_length,length($string)-$wave_length) ;
}
no bytes;
return $string;
}
# End of script