俺Pla

いろんなとこからコピペしてPublish::Plamailとかでっちあげてみた。

package Plagger::Plugin::Publish::Plamail;
use strict;
use base qw( Plagger::Plugin );

use DateTime;
use DateTime::Format::Mail;
use Encode;
use Encode::MIME::Header;
use HTML::Entities;
use HTML::Parser;
use Jcode;
use MIME::Lite;

our %TLSConn;

sub rule_hook { 'publish.feed' }

sub register {
    my($self, $context) = @_;
    $context->register_hook(
        $self,
        'publish.init' => \&initialize,
        'publish.feed' => \&notify,
    );
}

sub init {
    my $self = shift;
    $self->SUPER::init(@_);

    $self->conf->{mailto} or Plagger->context->error("mailto is required");
    $self->conf->{mailfrom} ||= 'plagger@localhost';
}

sub initialize {
    my($self,$context) = @_;

    # authenticate POP before SMTP
    if (my $conf = $self->conf->{pop3}) {
        require Net::POP3;
        my $pop = Net::POP3->new($conf->{host});
        if ($pop->apop($conf->{username}, $conf->{password})) {
            $context->log(info => 'APOP login succeed');
        } elsif ($pop->login($conf->{username}, $conf->{password})) {
            $context->log(info => 'POP3 login succeed');
        } else {
            $context->log(error => 'POP3 login error');
        }
        $pop->quit;
    }
}

sub notify {
    my($self, $context, $args) = @_;

    return if $args->{feed}->count == 0;

    my $feed = $args->{feed};
    my $subject = $feed->title || '(no-title)';

    my @enclosure_cb;
    if ($self->conf->{attach_enclosures}) {
        for my $entry ($args->{feed}->entries) {
            push @enclosure_cb, $self->prepare_enclosures($entry);
        }
    }

    my $body = $self->templatize('plamail_notify.tt', { feed => $feed });

    my $cfg = $self->conf;
    $context->log(info => "Sending $subject to $cfg->{mailto}");

    my $feed_title = $feed->title;
       $feed_title =~ tr/,//d;

    my $now = Plagger::Date->now(timezone => $context->conf->{timezone});

    my $msg = MIME::Lite->new(
        Date => $now->format('Mail'),
        From => encode('MIME-Header-ISO_2022_JP', qq("$feed_title" <$cfg->{mailfrom}>)),
        To   => $cfg->{mailto},
        Subject => encode('MIME-Header-ISO_2022_JP', $subject),
        Type => 'text/plain; charset=iso-2022-jp',
        Encoding=> '7bit',
        Data => encode_body($args->{entry}->body),
    );
    $msg->replace("X-Mailer" => "Plagger/$Plagger::VERSION");

#    $msg->attach(
#        Type => 'text/html; charset=utf-8',#'text/html; charset=utf-8'
#        Data => encode("utf-8", $body),#("utf-8", $body)
#        Encoding => 'quoted-printable',
#    );

    for my $cb (@enclosure_cb) {
        $cb->($msg);
    }

    my $route = $cfg->{mailroute} || { via => 'smtp', host => 'localhost' };
    $route->{via} ||= 'smtp';

    eval {
        if ($route->{via} eq 'smtp_tls') {
            $self->{tls_args} = [
                $route->{host},
                User     => $route->{username},
                Password => $route->{password},
                Port     => $route->{port} || 587,
            ];
            $msg->send_by_smtp_tls(@{ $self->{tls_args} });
        } elsif ($route->{via} eq 'sendmail') {
            my %param = (FromSender => "<$cfg->{mailfrom}>");
            $param{Sendmail} = $route->{command} if defined $route->{command};
            $msg->send('sendmail', %param);
        } else {
            my @args  = $route->{host} ? ($route->{host}) : ();
            $msg->send($route->{via}, @args);
        }
    };

    if ($@) {
        $context->log(error => "Error while sending emails: $@");
    }
}

sub encode_body {
   my $str = shift;
   $str = remove_utf8_flag($str);
   $str =~ s/\x0D\x0A/\n/g;
   $str =~ tr/\r/\n/;
   return Jcode->new($str, guess_encoding($str))->jis;
 }

sub guess_encoding {
   my $str = shift;
   my $enc = Jcode::getcode($str) || 'euc';
   $enc = 'euc' if $enc eq 'ascii' || $enc eq 'binary';
   return $enc;
 }

sub remove_utf8_flag { pack 'C0A*', $_[0] }

sub prepare_enclosures {
    my($self, $entry) = @_;

    if (grep $_->is_inline, $entry->enclosures) {
        # replace inline enclosures to cid: entities
        my %url2enclosure = map { $_->url => $_ } $entry->enclosures;

        my $output;
        my $p = HTML::Parser->new(api_version => 3);
        $p->handler( default => sub { $output .= $_[0] }, "text" );
        $p->handler( start => sub {
                         my($tag, $attr, $attrseq, $text) = @_;
                         # TODO: use HTML::Tagset?
                         if (my $url = $attr->{src}) {
                             if (my $enclosure = $url2enclosure{$url}) {
                                 $attr->{src} = "cid:" . $self->enclosure_id($enclosure);
                             }
                             $output .= $self->generate_tag($tag, $attr, $attrseq);
                         } else {
                             $output .= $text;
                         }
                     }, "tag, attr, attrseq, text");
        $p->parse($entry->body);
        $p->eof;

        $entry->body($output);
    }

    return sub {
        my $msg = shift;

        for my $enclosure (grep $_->local_path, $entry->enclosures) {
            my %param = (
                Type => $enclosure->type,
                Path => $enclosure->local_path,
                Filename => $enclosure->filename,
            );

            if ($enclosure->is_inline) {
                $param{Id} = '<' . $self->enclosure_id($enclosure) . '>';
                $param{Disposition} = 'inline';
            } else {
                $param{Disposition} = 'attachment';
            }

            $msg->attach(%param);
        }
    }
}

sub generate_tag {
    my($self, $tag, $attr, $attrseq) = @_;

    return "<$tag " .
        join(' ', map { $_ eq '/' ? '/' : sprintf qq(%s="%s"), $_, encode_entities($attr->{$_}, q(<>"')) } @$attrseq) .
        '>';
}

sub enclosure_id {
    my($self, $enclosure) = @_;
    return Digest::MD5::md5_hex($enclosure->url->as_string) . '@Plagger';
}

sub DESTORY {
    my $self = shift;
    return unless $self->{tls_args};

    my $conn_key = join "|", @{ $self->{tls_args} };
    eval {
        local $SIG{__WARN__} = sub { };
        $TLSConn{$conn_key} && $TLSConn{$conn_key}->quit;
    };

1;


Can't call method "body" on an undefined value
とか出て動かねえよばーかばーか。


ぐすん。

日経ソフトウェア12月号

結城先生のPlagger後編。
早速読んだ。
スラスラ読めてとても嬉しかった。
我ながら成長したもんだぜ。


内容の方は、正直言って期待はずれだった。
結城先生の、口調は優しいけど内容は超スパルタって、いつものアメと鞭両面作戦を期待してたのに全然物足りない。
具体的に言うと、Plaggerのメソッド呼び出し順解読とかPluginの書き方とか教えてくれると思ってたのに、config.yamlの書き方に終始してる。残念だ。


ていうか、いきなりPlugin作ろうとしてる僕が変態だって今気づいた。
残念、それは私のお稲荷さんだ。

Publish::Iso_2022_jp_mailその後

コピペして実行してみたら、えらいことモジュールが足りなかったので、CPANからダウンロードしてみた。
なんかCPAN.pmとかってモジュール使うと便利にインストールできるみたいだけど、怖いのでフル手動。
グリグリドラッグしてやったもんね。

Missing right curly or square bracket at /Users/USER/Plagger-Mac-0.7.11-2/CPAN/lib/perl5/site_perl/Plagger/Plugin/Filter/FormatText.pm line 1, at end of line

なんだこれ。
カッコが足りないとか言われてるみたい。
だけどなんのことかわからん。


確かに僕はカッコ悪いかもしれないが、
外見をけなすのはいけない事だって先生も言ってたぞ。

僕は僕なりに

Publish::Iso_2022_jp_mail。
まだつかってないけど、良いもののような気がする。ひしひしとする。


ただ、僕的にはsendmailとか使いたくないのでGmailを間借りしようってのがあったりする。


ので、Publish::Gmailを盗み見てごにょごにょさせてもらおうかな。

Type => 'text/plain; charset=ISO-8859-1'

転んでも泣かない。
できたぜ。
携帯から読めるようになったぜ。


結果から言えば、テキストエンコードUTF-8になってたから読めなかった。
テンプレートは関係なかった。
でも、結局はテンプレートいじらないとソースコード垂れ流しで読みにくいのでごっそり削って、

[% USE util = Plagger.Util -%]

[% FOREACH entry = feed.entries -%]

[% entry.body %]

[%- END %]

とかにしちゃったんだけどな。


エンコード変更は、Publish::Gmailの89,90行目を、怖いもの知らずにも直接書き換えてやったわ。
ぬわははは。
怖いよー。

$msg->attach(
        Type => 'text/plain; charset=ISO-8859-1',
        Data => encode("ISO-8859-1", $body),
        Encoding => 'quoted-printable',

赤字のとこな


えー、頑張ってみましたが、ここで詰みです。
このままだと、万能Plaggerは僕の携帯にしかメールを送れない貧弱君になってしまいます。
gmail_notify.ttを書き換えるだけだったら、ファイル名をちょこちょこ打ち変えればなんとか運用できそうなんですけど、Publish::Gmailを書き換えるのはダメだ。色々怖すぎる。モジュールの中身をいじくっちゃなんねえってラクダに言われたような気もするし。
元に戻そう。


ていうか、auユニコード読めるようにしろよなー。