Maildirへ保存するプラグイン

熱狂的な騒ぎはは収まって来たかな?ということで、plaggerStart Pageでもまだ対応されていないPublish::IMAPを書いて見た。
ここで公開したPublish::Gmailの改造版と同様に1記事/1通という仕様になってので興味のある人は試用してみて下さい。


使い方 config.yaml

      - module: Publish::IMAP
config:
username: username
password: password
folder: INBOX # 省略可能
mailfrom: plagger # 省略可能
host: localhost # 省略可能
port: 143 # 省略可能

プラグイン IMAP.pm

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

use DateTime;
use DateTime::Format::Mail;
use Encode qw/ from_to encode/;
use Encode::MIME::Header;
use MIME::Lite;
use IO::File;
use Mail::IMAPClient;

sub register {
my($self, $context) = @_;
$self->{version} = '0.1';
$context->register_hook(
$self,
'publish.init' => \&initialize,
'publish.entry.fixup' => \&store_entry,
'publish.finalize' => \&finalize,
);
}

sub initialize {
my ($self, $context, $args) = @_;
my $cfg = $self->conf;
$self->{imap} = Mail::IMAPClient->new(
User => $cfg->{username},
Password => $cfg->{password},
Server => $cfg->{host} || 'localhost',
Port => $cfg->{port} || 143,
) or die $context->log(error => "Cannot connect; $@");
$context->log(debug => "Connected IMAP-SERVER (".$cfg->{host}.")");
if ($cfg->{folder} && !$self->{imap}->exists($cfg->{folder})) {
$self->{imap}->create($cfg->{folder})
or die $context->log(error => "Could not create $cfg->{folder}: $@");
$context->log(info => "Create new folder ($cfg->{folder})");
}
if (!$cfg->{mailfrom}) {
$cfg->{mailfrom} = 'plagger';
}
}

sub finalize {
my ($self, $context, $args) = @_;
my $cfg = $self->{conf};
$self->{imap}->disconnect();
if (my $msg_count = $self->{msg}) {
$context->log(info => "Store $msg_count Message(s)");
}
$context->log(debug => "Disconnected IMAP-SERVER (".$cfg->{host}.")");
}

sub store_entry {
my($self, $context, $args) = @_;
my $cfg = $self->conf;
my $msg;
my $entry = $args->{entry};
my $feed_title = $args->{feed}->title;
$feed_title =~ tr/,//d;
my $subject = $entry->title || '(no-title)';
my $body = $self->templatize($context, $args);
my $now = Plagger::Date->now(timezone => $context->conf->{timezone});
$msg = MIME::Lite->new(
Date => $now->format('Mail'),
From => encode('MIME-Header', qq("$feed_title" <$cfg->{mailfrom}>)),
To => $cfg->{mailto},
Subject => encode('MIME-Header', $subject),
Type => 'multipart/related',
);
$body = encode("utf-8", $body);
$msg->attach(
Type => 'text/html; charset=utf-8',
Data => $body,
);
$msg->add('X-Tags', encode('MIME-Header',join(' ',@{$entry->tags})));
my $xmailer = "MIME::Lite (Publish::Maildir Ver.$self->{version} in plagger)";
$msg->replace('X-Mailer',$xmailer);
store_maildir($self, $context,$msg->as_string());
$self->{msg} += 1;
}

sub templatize {
my ($self, $context, $args) = @_;
my $tt = $context->template();
$tt->process( 'IMAP.tt', {
entry => $args->{entry},
feed => $args->{feed},
}, \my $out ) or $context->error($tt->error);
$out;
}

sub store_maildir {
my($self,$context,$msg) = @_;
my $folder = $self->conf->{folder} || 'INBOX';
my $uid = $self->{imap}->append_string($folder,$msg)
or die $context->log(error => "Could not append: $@");
}

1;

テンプレート IMAP.tt

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<style TYPE=text/css>
body { padding:0; margin:20px }
strong { font-weight:bold; font-size:1.2em }
div#msgheader { background:#65869E; color:#F5F5F5; padding:10px; margin:-20px -20px 0 -20px }
div#msgbody { margin: 1em }
div#msgfooter { text-align:right; font-size:0.8em }
#msgheader a:link { color:#F5F5F5 }
#msgbody a:link { color:#000000 }
#msgbody img { border:1px solid; background:#F5F5F5 }
#msgbody hr { border:1px solid }
</style>
</head>
<body>
<div>
<div id="msgheader">
[% IF entry.icon %]<a href="[% entry.link | html %]"><img style="border:0" align="right" src="[% entry.icon.url | html %]" alt="[% (entry.icon.title || entry.title) | html %]" /></a>
[% ELSIF feed.image %]<a href="[% feed.link | html %]"><img style="border:0" align="right" src="[% feed.image.url | html %]" alt="[% feed.title | html %]" /></a>
[% END -%]
<strong>[% entry.title %]</strong><br />
[% SET link = entry.link || entry.id -%]
Link: <a href="[% link | html %]">[% link | html %]</a><br />
[% IF entry.author %]by [% entry.author | html %][% END %][% IF entry.tags.size %] on [% entry.tags.join(',') %][% END %]</div>
<div id="msgbody">
[% IF entry.body -%]
[% IF entry.body.match('(?i)^<p[ >]') %][% entry.body %][% ELSE %]<div id="msgbody">[% entry.body %]</div>[% END %]
[% ELSE %]<br />[% END %]
<div id="msgfooter">[% IF entry.date %]Posted on [% entry.date.format('Mail') %][% END %] | <a href="[% entry.permalink | html %]">permalink</a> | <a href="[% feed.link | html %]">[% feed.title | html %]</a>[% FOREACH widget = entry.widgets %] | [% widget.html(entry) %][% END %]<br clear="all" /></div>
</div>
</div>
</body>
</html>