bring Moo to the Dispatcher for more flexibility and easier testing
[p5sagit/Promulger.git] / lib / Promulger / Dispatch.pm
CommitLineData
f5baca29 1package Promulger::Dispatch;
9e4ca637 2use Moo;
3use Method::Signatures::Simple;
4use autodie ':all';
f5baca29 5
8ad89cb2 6use Email::Address;
b179831b 7use Email::MIME;
9e4ca637 8use Email::Sender::Simple ();
9f8395b9 9# XXX not yet -- apeiron, 2010-06-25
10#use Mail::Verp;
f5baca29 11
21baaef0 12use Promulger::Config;
13
9e4ca637 14has transport => (
15 is => 'rw',
16 isa => sub {
17 my $proto = $_[0];
18 blessed $proto and
19 $proto->can('does') and
20 $proto->does('Email::Sender::Transport')
21 or die "transport must do Email::Sender::Transport role";
22 },
23 default => sub {
24 Email::Sender::Transport::Sendmail->new
25 },
26);
27
21baaef0 28# XXX no bounce parsing yet -- apeiron, 2010-03-13
9e4ca637 29method dispatch ($message) {
21baaef0 30 my $config = Promulger::Config->config;
f5baca29 31
b179831b 32 my $email = Email::MIME->new($message);
f7a55eac 33 my $recipient = $email->header('To');
9e4ca637 34 my $local_user = $self->user_for_address($recipient);
f7a55eac 35 my $sender = $email->header('From');
36 my $subject = $email->header('Subject');
f5baca29 37
8ad89cb2 38 my $list = Promulger::List->resolve($local_user);
f5baca29 39 unless($list) {
9e4ca637 40 $self->reject($recipient, $sender);
8ad89cb2 41 return;
f5baca29 42 }
43
8ad89cb2 44 if($local_user =~ /-request$/) {
9e4ca637 45 $self->handle_request($list, $sender, $local_user, $subject, $config);
8ad89cb2 46 return;
f5baca29 47 }
48
49 # they don't have a request for us, so they want to post a message
9e4ca637 50 $self->post_message($list, $email, $config);
8ad89cb2 51 return;
f5baca29 52}
53
9e4ca637 54method handle_request ($list, $sender, $recipient, $subject) {
55 my $sender_address = $self->bare_address($sender);
8ad89cb2 56 if($subject =~ /^\s*subscribe/i) {
57 $list->subscribe($sender_address)
9e4ca637 58 or $self->already_subscribed($list, $recipient, $sender_address);
8ad89cb2 59 } elsif($subject =~ /^\s*unsubscribe/i) {
60 $list->unsubscribe($sender_address)
9e4ca637 61 or $self->not_subscribed($list, $recipient, $sender_address);
f5baca29 62 }
63}
64
9e4ca637 65method post_message ($list, $email, $config) {
f7a55eac 66 my $sender = $email->header('From');
9e4ca637 67 my $sender_address = $self->bare_address($sender);
f7a55eac 68 my $recipient = $email->header('To');
f5baca29 69
8ad89cb2 70 unless($list->accept_posts_from($sender_address) && $list->active) {
9e4ca637 71 $self->reject($recipient, $sender);
8ad89cb2 72 return;
73 }
f5baca29 74
f5baca29 75 # XXX no MIME or other fancy handling for now -- apeiron, 2010-03-13
b179831b 76 my $body = $email->body_str;
8ad89cb2 77 for my $subscriber (keys %{$list->subscribers}) {
f7a55eac 78 # my $verped_from = Mail::Verp->encode($recipient, $subscriber);
79
f5baca29 80 # XXX we let the MTA create the message-id for us for now -- apeiron,
81 # 2010-03-13
b179831b 82 my $new_message = Email::MIME->create(
f5baca29 83 header => [
e9b4d3bc 84 From => $sender_address,
85 To => $subscriber,
f7a55eac 86 Subject => $email->header('Subject'),
e9b4d3bc 87 'Reply-to' => $recipient,
f5baca29 88 ],
89 body => $body,
90 );
91 # XXX no queuing or job distribution for now beyond what the MTA provides
92 # -- apeiron, 2010-03-13
9e4ca637 93 $self->send_message($new_message);
f5baca29 94 }
95}
96
9e4ca637 97method send_message ($message) {
f7a55eac 98 my $config = Promulger::Config->config;
99 my ($class, $transport);
98d1255d 100 if($class = $config->{mailer}) {
f7a55eac 101 if($class !~ /::/) {
102 $class = "Email::Sender::Transport::${class}";
103 }
104 } else {
105 $class = 'Email::Sender::Transport::Sendmail';
106 }
107 Class::MOP::load_class($class);
108 $transport = $class->new;
9e4ca637 109 Email::Sender::Simple::sendmail(
f7a55eac 110 $message,
111 {
9e4ca637 112 transport => $self->transport,
f7a55eac 113 }
114 );
115}
116
21baaef0 117# XXX make this actually not suck -- apeiron, 2010-03-13
9e4ca637 118method reject ($recipient, $sender) {
b179831b 119 my $email = Email::MIME->create(
21baaef0 120 header => [
121 From => $recipient,
122 To => $sender,
123 Subject => 'Rejected',
124 ],
125 body => <<BODY,
126Sorry, your message to $recipient has been denied.
127BODY
128 );
9e4ca637 129 $self->send_message($email);
21baaef0 130}
131
9e4ca637 132method not_subscribed ($list, $recipient, $sender) {
b179831b 133 my $email = Email::MIME->create(
8ad89cb2 134 # XXX need admin address
21baaef0 135 header => [
8ad89cb2 136 From => $recipient,
21baaef0 137 To => $sender,
138 Subject => 'Not subscribed',
139 ],
140 body => <<BODY,
8ad89cb2 141Sorry, you are not subscribed to $list.
21baaef0 142BODY
143 );
9e4ca637 144 $self->send_message($email);
21baaef0 145}
146
9e4ca637 147method already_subscribed ($list, $recipient, $sender) {
b179831b 148 my $email = Email::MIME->create(
21baaef0 149 header => [
8ad89cb2 150 From => $recipient,
21baaef0 151 To => $sender,
152 Subject => 'Already subscribed',
153 ],
154 body => <<BODY,
8ad89cb2 155Sorry, you are already subscribed to $list.
21baaef0 156BODY
157 );
9e4ca637 158 $self->send_message($email);
21baaef0 159}
f5baca29 160
9e4ca637 161method bare_address ($full_addr) {
8ad89cb2 162 my ($addr_obj) = Email::Address->parse($full_addr);
163 return $addr_obj->address;
164}
165
9e4ca637 166method user_for_address ($full_addr) {
8ad89cb2 167 my ($addr_obj) = Email::Address->parse($full_addr);
168 return $addr_obj->user;
169}
170
f5baca29 171'http://www.shadowcat.co.uk/blog/matt-s-trout/oh-subdispatch-oh-subdispatch/';