root/branches/feature-server/plagger/lib/Plagger/Plugin/Publish/Maildir.pm

Revision 1009 (checked in by miyagawa, 3 years ago)

r2680@rock (orig r938): miyagawa | 2006-06-09 10:28:17 +0900
add podtrac TruePermalink?. via http://d.hatena.ne.jp/mryfmo/20060608
r2681@rock (orig r939): miyagawa | 2006-06-09 10:30:48 +0900
TruePermalink?: add feedburner podcast redirector. Refs #226
r2682@rock (orig r940): miyagawa | 2006-06-09 16:11:35 +0900
use Last-Modified header to populate entry date, even if handler can't find one.
via http://subtech.g.hatena.ne.jp/otsune/20060608/norkdailymemo
r2683@rock (orig r941): miyagawa | 2006-06-09 16:12:52 +0900
take off utf-8 flag when taking digest value
r2684@rock (orig r942): miyagawa | 2006-06-09 17:04:38 +0900

Publish
CHTML: Don't die if body contains non-sjis mappable characters
r2685@rock (orig r943): miyagawa | 2006-06-09 17:26:01 +0900
defaults to cp932 would be better
r2686@rock (orig r944): miyagawa | 2006-06-09 17:37:37 +0900

r2687@rock (orig r945): miyagawa | 2006-06-09 18:48:15 +0900
add pya.cc upgrader via http://subtech.g.hatena.ne.jp/otsune/20060608/pya2feed
r2688@rock (orig r946): miyagawa | 2006-06-09 21:21:47 +0900
CustomFeed?
2chSearch
r2689@rock (orig r947): miyagawa | 2006-06-09 21:26:31 +0900
oops, remove </b>
r2690@rock (orig r948): miyagawa | 2006-06-09 21:44:42 +0900
fix date if it found true entry
r2691@rock (orig r949): miyagawa | 2006-06-09 21:59:05 +0900
need quotes
r2692@rock (orig r950): miyagawa | 2006-06-09 22:06:35 +0900
Planet: Scrubber support back inlib/Plagger/Plugin/Publish/Planet.pm
r2693@rock (orig r951): miyagawa | 2006-06-09 22:08:01 +0900
oops
r2694@rock (orig r952): otsune | 2006-06-09 22:11:04 +0900
fix extract http://pyc.cc/

r2695@rock (orig r953): otsune | 2006-06-09 22:12:28 +0900
add EntryFulltext? for seesaa blog

r2696@rock (orig r954): otsune | 2006-06-09 23:27:11 +0900
fix %3A

r2697@rock (orig r955): miyagawa | 2006-06-10 02:26:28 +0900
MixiDiarySearch?: decode keyword query
r2698@rock (orig r956): miyagawa | 2006-06-10 02:53:41 +0900
TruePermalink? enbug stuff. Use permlalink to find handlers
r2699@rock (orig r957): otsune | 2006-06-10 03:08:33 +0900
add EntryFulltext? http://headlines.yahoo.co.jp/

r2700@rock (orig r958): otsune | 2006-06-10 04:38:27 +0900
add Apple KB and TIL document

r2701@rock (orig r959): otsune | 2006-06-10 04:43:22 +0900
oops.

r2702@rock (orig r960): miyagawa | 2006-06-10 23:07:48 +0900
set Bloglines n=100
r2703@rock (orig r961): miyagawa | 2006-06-11 01:35:38 +0900
MixiDiarySearch?: allow no_photo.gif
r2704@rock (orig r962): miyagawa | 2006-06-11 01:45:53 +0900
2chSearh: Fix error handling
r2705@rock (orig r963): miyagawa | 2006-06-11 02:07:11 +0900
added takesako-san for his patch
r2706@rock (orig r964): otsune | 2006-06-11 05:59:58 +0900
modified Chugoku SHinbun, add EFT for http://www.zianplus.net/

r2707@rock (orig r965): otsune | 2006-06-11 10:17:02 +0900
add pMachine ExpressionEngine? http://www.pmachine.com/

r2708@rock (orig r966): youpy | 2006-06-11 12:38:21 +0900
fix regexp

r2709@rock (orig r967): otsune | 2006-06-12 04:09:24 +0900
fix extract regexp

r2710@rock (orig r968): otsune | 2006-06-12 04:13:19 +0900
update regexp

r2711@rock (orig r969): otsune | 2006-06-12 04:29:18 +0900
support http://www.mainichi-msn.co.jp/photo/etc/photo_feature/

r2712@rock (orig r970): otsune | 2006-06-12 06:08:15 +0900
fix wordpress.
Add mainichi-msn Photo and separate handle.
Add http://www.actiblog.com/

r2713@rock (orig r971): otsune | 2006-06-12 07:02:23 +0900
refine livedoorblog.pl
fix miss.

r2714@rock (orig r972): miyagawa | 2006-06-12 13:25:28 +0900
extract_title should be case insensitive. via http://d.hatena.ne.jp/sfujiwara/20060611/1150051152
r2715@rock (orig r973): miyagawa | 2006-06-12 13:39:12 +0900
rewrite config doesn't die even if it can't rewrite because of permission problem
r2716@rock (orig r974): miyagawa | 2006-06-12 13:43:25 +0900
skip all livedoorkeyword link
r2719@rock (orig r975): otsune | 2006-06-12 14:50:19 +0900
fix misc regexp

r2720@rock (orig r976): miyagawa | 2006-06-12 15:44:57 +0900
support handle only in livedoorblog.pl to work with aggregated feeds
r2721@rock (orig r977): miyagawa | 2006-06-12 18:22:40 +0900
TruePermalink? for blogpeople redirector
r2722@rock (orig r978): otsune | 2006-06-12 22:14:03 +0900
opps 'Unmatched ( in regex;'

r2723@rock (orig r979): youpy | 2006-06-13 10:21:42 +0900
add mailman upgrader


r2724@rock (orig r980): youpy | 2006-06-13 10:28:19 +0900
fix handle regexp


r2727@rock (orig r983): miyagawa | 2006-06-13 19:00:22 +0900
Subscription
Planet: add feedster.jp
r2728@rock (orig r984): miyagawa | 2006-06-13 19:06:06 +0900
use lang/all on feedster.jp
r2734@rock (orig r985): otsune | 2006-06-13 22:11:21 +0900
fix regexp

r2735@rock (orig r986): miyagawa | 2006-06-14 00:34:01 +0900
new plugin Notify
Beep
r2736@rock (orig r987): miyagawa | 2006-06-14 00:34:40 +0900
planet: remove unnecessary bit
r2737@rock (orig r988): miyagawa | 2006-06-14 00:35:03 +0900
update example to use sixapart-std
r2738@rock (orig r989): otsune | 2006-06-14 02:55:47 +0900
remove icon_re. RecentComment? can't get it

r2745@rock (orig r990): miyagawa | 2006-06-14 12:07:29 +0900
t/core is for developer test and not needed for installers
r2746@rock (orig r991): miyagawa | 2006-06-14 12:49:00 +0900
support mixi_tos_paranoia mode
r2747@rock (orig r992): miyagawa | 2006-06-14 13:10:40 +0900
title would be ok
r2792@rock (orig r993): miyagawa | 2006-06-16 15:04:12 +0900
  • New plugin Subscription::Bookmarks (and its IE subclass) to read IE favorites.
r2793@rock (orig r994): miyagawa | 2006-06-16 15:11:52 +0900
added TODO as comment
r2794@rock (orig r995): youpy | 2006-06-17 20:36:18 +0900
add Plugin::Subscription::Bookmarks
Safari


r2795@rock (orig r996): youpy | 2006-06-17 21:39:18 +0900
add tag support by folder name


r2796@rock (orig r997): youpy | 2006-06-18 15:41:59 +0900
use $uri->file when scheme is 'file'


r2797@rock (orig r998): youpy | 2006-06-18 15:42:56 +0900
add Plugin::Subscription::Bookmarks
Mozilla


r2798@rock (orig r999): miyagawa | 2006-06-19 15:23:13 +0900
bump URI
Fetch req
r2800@rock (orig r1000): miyagawa | 2006-06-22 00:26:46 +0900
dependency for Bookmarks
Safari. 1000th commit!
r2801@rock (orig r1001): miyagawa | 2006-06-22 00:30:57 +0900
fix config rewriting bug when the password contains regexp metachars. via http://d.hatena.ne.jp/sfujiwara/20060621/1150899012
r2802@rock (orig r1002): otsune | 2006-06-22 00:54:24 +0900
add http://www.computerworld.jp/ http://autopage.teacup.com/
fix headlines_yahoo_jp (Thanks woremacx)
fix goo blog

r2803@rock (orig r1003): miyagawa | 2006-06-22 01:10:00 +0900
import drawnboy's EntryFullText? yamls via http://svn.nowherenear.net/repos/public/misc/eft/
r2804@rock (orig r1004): miyagawa | 2006-06-22 01:10:39 +0900
update AUTHOR
r2805@rock (orig r1005): s_nobu | 2006-06-22 06:17:15 +0900
require HTML
Entities for enclosure support.

r2807@rock (orig r1006): miyagawa | 2006-06-22 15:46:30 +0900
URI
Fetch 0.07 is broken (i was a moron), reverting back to 0.06 for now
r2808@rock (orig r1007): miyagawa | 2006-06-22 16:04:48 +0900
packaging 0.7.3
Line 
1 package Plagger::Plugin::Publish::Maildir;
2 use strict;
3 use base qw( Plagger::Plugin );
4
5 use DateTime;
6 use DateTime::Format::Mail;
7 use Encode qw/ from_to encode/;
8 use Encode::MIME::Header;
9 use HTML::Entities;
10 use MIME::Lite;
11 use Digest::MD5 qw/ md5_hex /;;
12 use File::Find;
13
14 our $VERSION = '0.3';
15
16 sub register {
17     my($self, $context) = @_;
18     $context->register_hook(
19       $self,
20       'publish.init' => \&initialize,
21       'publish.entry.fixup' => \&store_entry,
22        'publish.finalize' => \&finalize,
23     );
24 }
25
26 sub initialize {
27   my ($self, $context, $args) = @_;
28   my $cfg = $self->conf;
29   my $permission = $cfg->{permission} || 0700;
30   if (-d $cfg->{maildir}) {
31     my $path = "$cfg->{maildir}/.$cfg->{folder}";
32        $path =~ s/\/\//\//g;
33        $path =~ s/\/$//g;
34     unless (-d $path) {
35       mkdir($path,0700)
36         or die $context->log(error => "Could not create $path");
37       $context->log(info => "Create new folder ($path)");
38     }
39     unless (-d $path."/new") {
40       mkdir($path."/new",0700)
41         or die $context->log(error => "Could not Create $path/new");
42       $context->log(info => "Create new folder($path/new)");
43     }
44     $self->{path} = $path;
45   }else{
46     die $context->log(error => "Could not access $cfg->{maildir}");
47   }
48 }
49
50 sub finalize {
51   my ($self, $context, $args) = @_;
52   if (my $msg_count = $self->{msg}) {
53     if (my $update_count = $self->{update_msg}) {
54       $context->log(info => "Store $msg_count message(s) ($update_count message(s) updated)");
55     }else{
56       $context->log(info => "Store $msg_count message(s)");
57     }
58   }
59 }
60
61 sub store_entry {
62   my($self, $context, $args) = @_;
63   my $cfg = $self->conf;
64   my $msg;
65   my $entry = $args->{entry};
66   my $feed_title = $args->{feed}->title;
67      $feed_title =~ tr/,//d;
68   my $subject    = $entry->title || '(no-title)';
69   my $body       = $self->templatize($context, $args);
70      $body       = encode("utf-8", $body);
71   my $from       = $cfg->{mailfrom} || 'plagger@localhost';
72   my $id     = md5_hex($entry->id_safe);
73   my $now = Plagger::Date->now(timezone => $context->conf->{timezone});
74   my @enclosure_cb;
75   if ($self->conf->{attach_enclosures}) {
76     for my $entry ($args->{feed}->entries) {
77       push @enclosure_cb, $self->prepare_enclosures($entry);
78     }
79   }
80   $msg = MIME::Lite->new(
81     Date    => $now->format('Mail'),
82     From    => encode('MIME-Header', qq("$feed_title" <$from>)),
83     To      => $cfg->{mailto},
84     Subject => encode('MIME-Header', $subject),
85     Type    => 'multipart/related',
86   );
87   $msg->attach(
88     Type => 'text/html; charset=utf-8',
89     Data => $body,
90     Encoding => 'quoted-printable',
91   );
92   for my $cb (@enclosure_cb) {
93     $cb->($msg);
94   }
95   $msg->add('Message-Id', "<$id.plagger\@localhost>");
96   $msg->add('X-Tags', encode('MIME-Header',join(' ',@{$entry->tags})));
97   my $xmailer = "MIME::Lite (Plagger/$Plagger::VERSION with Publish::Maildir/$VERSION)";
98   $msg->replace('X-Mailer',$xmailer);
99   store_maildir($self, $context,$msg->as_string(),$id);
100   $self->{msg} += 1;
101 }
102
103 sub prepare_enclosures {
104     my($self, $entry) = @_;
105
106     if (grep $_->is_inline, $entry->enclosures) {
107         # replace inline enclosures to cid: entities
108         my %url2enclosure = map { $_->url => $_ } $entry->enclosures;
109
110         my $output;
111         my $p = HTML::Parser->new(api_version => 3);
112         $p->handler( default => sub { $output .= $_[0] }, "text" );
113         $p->handler( start => sub {
114                          my($tag, $attr, $attrseq, $text) = @_;
115                          # TODO: use HTML::Tagset?
116                          if (my $url = $attr->{src}) {
117                              if (my $enclosure = $url2enclosure{$url}) {
118                                  $attr->{src} = "cid:" . $self->enclosure_id($enclosure);
119                              }
120                              $output .= $self->generate_tag($tag, $attr, $attrseq);
121                          } else {
122                              $output .= $text;
123                          }
124                      }, "tag, attr, attrseq, text");
125         $p->parse($entry->body);
126         $p->eof;
127
128         $entry->body($output);
129     }
130
131     return sub {
132         my $msg = shift;
133
134         for my $enclosure (grep $_->local_path, $entry->enclosures) {
135             my %param = (
136                 Type => $enclosure->type,
137                 Path => $enclosure->local_path,
138                 Filename => $enclosure->filename,
139             );
140
141             if ($enclosure->is_inline) {
142                 $param{Id} = '<' . $self->enclosure_id($enclosure) . '>';
143                 $param{Disposition} = 'inline';
144             } else {
145                 $param{Disposition} = 'attachment';
146             }
147
148             $msg->attach(%param);
149         }
150     }
151 }
152
153 sub generate_tag {
154     my($self, $tag, $attr, $attrseq) = @_;
155
156     return "<$tag " .
157         join(' ', map { $_ eq '/' ? '/' : sprintf qq(%s="%s"), $_, encode_entities($attr->{$_}, q(<>"')) } @$attrseq) .
158         '>';
159 }
160
161 sub templatize {
162   my ($self, $context, $args) = @_;
163   my $tt = $context->template();
164 #  $tt->process( 'gmail_notify.tt', {
165   $tt->process( 'mail.tt', {
166     entry => $args->{entry},
167     feed  => $args->{feed},
168   }, \my $out ) or $context->error($tt->error);
169   $out;
170 }
171
172 sub enclosure_id {
173   my($self, $enclosure) = @_;
174   return Digest::MD5::md5_hex($enclosure->url->as_string) . '@Plagger';
175 }
176
177 sub store_maildir {
178   my($self,$context,$msg,$id) = @_;
179   my $filename = $id.".plagger";
180   find(
181     sub {
182       if ($_ =~ m!$id.*!) {
183         unlink $_;
184         $self->{update_msg} += 1;
185       }
186     },
187     $self->{path}."/cur"
188   );
189   $context->log(debug=> "writing: new/$filename");
190   my $path = $self->{path}."/new/".$filename;
191   open my $fh, ">", $path or $context->error("$path: $!");
192   print $fh $msg;
193   close $fh;
194 }
195
196 1;
197
198 =head1 NAME
199
200 Plagger::Plugin::Publish::Maildir - Store Maildir
201
202 =head1 SYNOPSIS
203
204   - module: Publish::Maildir
205     config:
206       maildir: /home/foo/Maildir
207       folder: plagger
208       attach_enclosures: 1
209       mailfrom: plagger@localhost
210
211 =head1 DESCRIPTION
212
213 This plugin changes an entry into e-mail, and saves it to Maildir.
214
215 =head1 AUTHOR
216
217 Nobuhito Sato
218
219 =head1 SEE ALSO
220
221 L<Plagger>
222
223 =cut
224
Note: See TracBrowser for help on using the browser.