/[drupal]/contributions/modules/og2list/mail-out.pl
ViewVC logotype

Contents of /contributions/modules/og2list/mail-out.pl

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.37 - (show annotations) (download) (as text)
Fri Nov 3 08:39:15 2006 UTC (3 years ago) by killes
Branch: MAIN
CVS Tags: HEAD
Changes since 1.36: +37 -9 lines
File MIME type: text/x-perl
#85964, make digests fully work, patch by galapas
1 #!/usr/bin/perl -w
2
3 # $Id: mail-out.pl,v 1.36 2006/09/06 00:17:10 killes Exp $
4
5 # THIS IS PROTOTYPE CODE AND SHOULD NOT BE USED IN PRODUCTION SYSTEMS!
6
7 # To quickly read the Perldoc below on a Unix system, use
8 #
9 # $ pod2man <FILE> | man -l -
10
11 =pod
12
13 =head1 NAME
14
15 mail-out.pl - outgoing mail handler for og2list.module
16
17 =head1 Synopsis
18
19 C<mail-out.pl [-d]>
20
21 =head1 Description
22
23 mail-out.pl reads messages fed into the og2list outgoing queue and
24 sends them out via a locelly installed MTA's /usr/bin/sendmail
25 interface.
26
27 If the -d ("digest") switch is set, send multipart/digest messages to
28 those users that have digest delivery configured.
29
30 =head1 Unfinished work, TODO's
31
32 =item ...
33
34 =head1 License
35
36 mail-out.pl, a helper script to send mail queued from the og2list
37 Drupal module.
38
39 Copyright (C) 2006 Hilko Bengen
40
41 This program is free software; you can redistribute it and/or modify
42 it under the terms of the GNU General Public License as published by
43 the Free Software Foundation; either version 2 of the License, or
44 (at your option) any later version.
45
46 This program is distributed in the hope that it will be useful,
47 but WITHOUT ANY WARRANTY; without even the implied warranty of
48 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
49 GNU General Public License for more details.
50
51 You should have received a copy of the GNU General Public License
52 along with this program; if not, write to the Free Software
53 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
54
55 =cut
56
57 use strict;
58
59 use FindBin;
60 use Mail::Verp; Mail::Verp->separator('+');
61 use Net::SMTP;
62 use MIME::Entity;
63 use Getopt::Std;
64 # Used for encoding the subject (if necessary)
65 use Encode qw(encode);
66 use DBI;
67
68 use vars qw(
69 $dsn $dbh
70
71 $get_content_stmt $get_rcpt_stmt $set_sentflag_stmt $get_sender_stmt
72 $get_arg_stmt $get_create_mail_stmt $get_del_arg_stmt
73
74 $get_digest_rcpt_stmt $clear_digest_rcpt_stmt
75
76 $get_content_handle $get_rcpt_handle $set_sentflag_handle $get_sender_handle
77 $get_arg_handle $get_create_mail_handle $get_del_arg_handle
78
79 $get_digest_rcpt_handle $clear_digest_rcpt_handle
80
81 $dbtype $dbuser $dbauth $dbhost $dbase $mail_domain
82
83 $set_reply_to
84
85 $send_method $batch_size
86
87 $sendmail_binary @sendmail_args $bsmtp_binary @bsmtp_args $smtp_server
88
89 %opts
90 $do_digest
91
92 $mid $nid $from_name $from_address $to_name $to_address
93 $subject $message_id $content_type $body
94 %digest_msgs
95 );
96
97 use constant {
98 OG2LIST_OUTGOING_NOT_SENT => 1,
99 OG2LIST_OUTGOING_RECEIVED_BY_MTA => 2,
100 OG2LIST_OUTGOING_LOCAL_ERROR => 3,
101 OG2LIST_OUTGOING_REMOTE_ERROR => 4,
102 OG2LIST_OUTGOING_POSTPONED => 5,
103 OG2LIST_OUTGOING_MODERATED => 6,
104 OG2LIST_OUTGOING_DIGEST => 7,
105 };
106
107 # ------------------------------------------------------------------------
108
109 # Default values
110 $mail_domain = "localhost.localdomain";
111
112 $smtp_server = "localhost:25";
113 $sendmail_binary = "/usr/lib/sendmail";
114 @sendmail_args = ("-oi","-oem","-f");
115 $bsmtp_binary = "/usr/sbin/rsmtp";
116 @bsmtp_args = ();
117
118 $dbtype = "mysql";
119 $dbase = "";
120 $dbhost = "localhost";
121 $dbuser = "";
122 $dbauth = "";
123
124 $set_reply_to = 0;
125
126 do "$FindBin::Bin/mail.conf";
127
128 # ------------------------------------------------------------------------
129
130 $get_content_stmt =<<EOF;
131 SELECT DISTINCT c.mid,
132 c.from_name,
133 c.from_address,
134 c.to_name,
135 c.to_address,
136 c.subject,
137 c.msgid,
138 c.content_type,
139 c.body,
140 r.nid
141 FROM og2list_outgoing_recipients AS r,
142 og2list_outgoing_content AS c
143 WHERE (r.mid = c.mid) AND (r.status = ?)
144 EOF
145
146 $get_arg_stmt =<<EOF;
147 SELECT mid,
148 nid,
149 timestamp,
150 status,
151 uid
152 FROM og2list_outgoing_arguments WHERE status NOT IN (?, ?)
153 EOF
154
155 $get_del_arg_stmt =<<EOF;
156 DELETE FROM og2list_outgoing_arguments WHERE mid = ?
157 EOF
158
159 $get_create_mail_stmt =<<EOF;
160 INSERT INTO og2list_outgoing_recipients
161 (mid, nid, recipient_name, recipient_address, timestamp, status)
162 SELECT ?, ?, u.name AS recipient_name, u.mail AS recipient_address, ?, IF(ou.mail_type = 7, 7, 1)
163 FROM og_uid ou INNER JOIN users u ON ou.uid = u.uid WHERE ((ou.mail_type = 1 AND u.uid != ?) OR ou.mail_type = 7) AND ou.nid = ? AND u.status > 0 AND ou.is_active >= 1
164 EOF
165
166 $get_rcpt_stmt=<<EOF;
167 SELECT recipient_address
168 FROM og2list_outgoing_recipients
169 WHERE (mid = ?) AND (status = ?)
170 EOF
171
172 $get_digest_rcpt_stmt=<<EOF;
173 SELECT DISTINCT recipient_address
174 FROM og2list_outgoing_recipients
175 WHERE (nid = ?) AND (status = ?)
176 EOF
177
178 $get_sender_stmt=<<EOF;
179 SELECT DISTINCT g.recipient
180 FROM og2list_outgoing_recipients AS r, og2list_groups AS g
181 WHERE (r.nid = g.nid) AND (r.mid = ?)
182 EOF
183
184 # FIXME: Misleading name
185 $set_sentflag_stmt=<<EOF;
186 DELETE FROM og2list_outgoing_recipients
187 WHERE (mid = ?) AND (recipient_address = ?)
188 EOF
189
190 $clear_digest_rcpt_stmt=<<EOF;
191 DELETE FROM og2list_outgoing_recipients
192 WHERE (nid = ?) AND (status = ?)
193 EOF
194
195 # ----------------------------------------------------------------------
196
197 sub send_bsmtp($$$$) {
198 my $mids = shift;
199 my $content = shift;
200 my $sender = shift;
201 my $recipients = shift;
202
203 open(BSMTP, , '|-') || exec($bsmtp_binary, @bsmtp_args);
204 foreach my $rcpt_addr (@$recipients) {
205 my $verp_addr = Mail::Verp->encode($sender, $rcpt_addr);
206 print BSMTP "MAIL FROM:<$verp_addr>\n";
207 print BSMTP "RCPT TO:<$rcpt_addr>\n";
208 print BSMTP "DATA\n";
209 $content =~ s/^\./\.\./mg;
210 print BSMTP $content;
211 print BSMTP "\n.\n";
212 }
213 close(BSMTP) && map {$set_sentflag_handle->execute($mid, $_)} @$recipients;
214 }
215
216 sub send_sendmail($$$$) {
217 my $mids = shift;
218 my $content = shift;
219 my $sender = shift;
220 my $recipients = shift;
221
222 foreach my $rcpt_addr (@$recipients) {
223 my $verp_addr = Mail::Verp->encode($sender, $rcpt_addr);
224 open(SENDMAIL, '|-') || exec($sendmail_binary, @sendmail_args,
225 $verp_addr, $rcpt_addr);
226 print SENDMAIL $content;
227 close(SENDMAIL) && $set_sentflag_handle->execute($mid, $rcpt_addr);
228 }
229 }
230
231 sub send_smtp($$$$) {
232 my $mids = shift;
233 my $content = shift;
234 my $sender = shift;
235 my $recipients = shift;
236
237 my $smtp = Net::SMTP->new($smtp_server);
238 unless ($smtp) {
239 print STDERR "ERROR: Could not connect to $smtp_server.\n";
240 return;
241 }
242
243 foreach my $rcpt_addr (@$recipients) {
244 my $verp_addr = Mail::Verp->encode($sender, $rcpt_addr);
245 $smtp->mail($verp_addr) or do {$smtp->reset(); next};
246 $smtp->to($rcpt_addr) or do {$smtp->reset(); next};
247 $smtp->data($content) or do {$smtp->reset(); next};
248
249 $set_sentflag_handle->execute($mid, $rcpt_addr);
250 }
251 $smtp->quit();
252 }
253
254 sub send_blackhole($$$$) {
255 my $mids = shift;
256 my $content = shift;
257 my $sender = shift;
258 my $recipients = shift;
259
260 map {$set_sentflag_handle->execute($mid, $_)} @$recipients;
261 return;
262 }
263
264 # ----------------------------------------------------------------------
265
266 getopts('d', \%opts);
267 $do_digest = $opts{'d'};
268
269 # Make database connection
270 $dsn = "DBI:$dbtype:$dbase:$dbhost";
271 $dbh = DBI->connect($dsn, $dbuser, $dbauth) or die;
272
273 # Work around charset encoding confusion.
274 if ($dbtype eq 'mysql') { $dbh->do('SET NAMES utf8'); }
275
276 # Set up queries
277 $get_content_handle = $dbh->prepare($get_content_stmt) or die;
278 $get_rcpt_handle = $dbh->prepare($get_rcpt_stmt) or die;
279 $get_digest_rcpt_handle = $dbh->prepare($get_digest_rcpt_stmt) or die;
280 $set_sentflag_handle = $dbh->prepare($set_sentflag_stmt) or die;
281 $clear_digest_rcpt_handle = $dbh->prepare($clear_digest_rcpt_stmt) or die;
282 $get_sender_handle = $dbh->prepare($get_sender_stmt) or die;
283 $get_arg_handle = $dbh->prepare($get_arg_stmt) or die;
284 $get_del_arg_handle = $dbh->prepare($get_del_arg_stmt) or die;
285 $get_create_mail_handle = $dbh->prepare($get_create_mail_stmt) or die;
286
287
288 if ($do_digest) {
289 $get_content_handle->execute(OG2LIST_OUTGOING_DIGEST);
290 while ( ($mid, $from_name, $from_address, $to_name, $to_address,
291 $subject, $message_id, $content_type, $body, $nid) =
292 $get_content_handle->fetchrow_array() ) {
293 # Build an entry ($nid) in %digest_msgs for every ogroup and add
294 # the digest message
295 unless (exists $digest_msgs{$nid}) {
296 $get_sender_handle->execute($mid);
297 (my $localpart) = $get_sender_handle->fetchrow_array();
298 my $sender = "$localpart\@$mail_domain";
299 ${$digest_msgs{$nid}}{sender} = $sender;
300
301 ${$digest_msgs{$nid}}{content} = MIME::Entity->build
302 ("Subject" => "Digest for $sender",
303 "From" => "$sender",
304 "To" => "$sender",
305 "Type" => "multipart/digest",
306 "Encoding" => "-SUGGEST",
307 "Charset" => "utf-8",
308 "X-Mailer" => undef);
309
310 # Get the list of addresses that are currently waiting a message
311 # for this digest
312 #
313 $get_digest_rcpt_handle->execute($nid, OG2LIST_OUTGOING_DIGEST);
314
315 my $recipient_address;
316 while ( ($recipient_address =
317 $get_digest_rcpt_handle->fetchrow_array()) ) {
318 # print "- $recipient_address \n";
319 push @{${$digest_msgs{$nid}}{recipients}}, $recipient_address;
320 }
321 }
322
323 # Add each message to the multipart/digest container.
324 my $msg = MIME::Entity->build
325 ("From" => "$from_name <$from_address>",
326 "To" => "$to_name <$to_address\@$mail_domain>",
327 "Subject" => encode('MIME-Header', "$subject"),
328 "Type" => "$content_type",
329 "Encoding" => "-SUGGEST",
330 "Charset" => "utf-8",
331 "Message-ID" => "$message_id",
332 "Data" => "$body",
333 "X-Mailer" => undef);
334 if ($set_reply_to != 0) {
335 $msg->head()->add('Reply-To', "<$to_address\@$mail_domain>");
336 }
337 my $container = MIME::Entity->build
338 ("Type" => "message/rfc822",
339 "Data" => $msg->stringify(),
340 "Subject" => encode('MIME-Header', "$subject"),
341 "Description" => encode('MIME-Header', "$subject"),
342 "X-Mailer" => undef);
343 ${$digest_msgs{$nid}}{content}->add_part($container);
344 push @{${$digest_msgs{$nid}}{mids}}, $mid;
345 }
346
347 # Actually send the message
348 foreach (keys %digest_msgs) {
349 my %msg = %{$digest_msgs{$_}};
350 # print "Sending Message $mid to\n";
351 my $content = $msg{content}->stringify();
352 my $sender = $msg{sender};
353 my @mids = @{$msg{mids}};
354 # Get a bunch of recipients
355 while (my @recipients =
356 splice @{$digest_msgs{$_}{recipients}},0,$batch_size) {
357 # print "- ".join(', ', @recipients)."\n";
358 foreach ($send_method) {
359 /^sendmail$/i && do { send_sendmail([$mid], $content, $sender,
360 [@recipients]); last; };
361 /^bsmtp$/i && do { send_bsmtp([$mid], $content, $sender,
362 [@recipients]); last; };
363 /^smtp$/i && do { send_smtp([$mid], $content, $sender,
364 [@recipients]); last; };
365 /^blackhole$/i && do { send_blackhole([$mid], $content, $sender,
366 [@recipients]); last; };
367 die("Value of \$send_method not recognized: $send_method");
368 }
369 }
370
371 # mids for this nid (key) have been sent, clear it from
372 # the outgoing_recipients table
373 ##
374 $clear_digest_rcpt_handle->execute($_, OG2LIST_OUTGOING_DIGEST);
375 }
376 } else {
377 $get_content_handle->execute(1);
378 while ( ($mid, $from_name, $from_address, $to_name, $to_address,
379 $subject, $message_id, $content_type, $body, $nid) =
380 $get_content_handle->fetchrow_array() ) {
381 my $msg = MIME::Entity->build
382 ("From" => "$from_name <$from_address>",
383 "To" => "$to_name <$to_address\@$mail_domain>",
384 "Subject" => encode('MIME-Header', "$subject"),
385 "Type" => "$content_type",
386 "Encoding" => "-SUGGEST",
387 "Charset" => "utf-8",
388 "Message-ID" => "$message_id",
389 "Data" => "$body",
390 "X-Mailer" => undef);
391 if ($set_reply_to != 0) {
392 $msg->head()->add('Reply-To', "<$to_address\@$mail_domain>");
393 }
394
395 # print "Sending Message $mid to\n";
396 $get_sender_handle->execute($mid);
397 (my $localpart) = $get_sender_handle->fetchrow_array();
398 my $sender = "$localpart\@$mail_domain";
399 my $content = $msg->stringify();
400 $get_rcpt_handle->execute($mid,1);
401
402 my $r;
403 # Get a bunch of recipients through $get_rcpt_handle
404 while (($r = $get_rcpt_handle->fetchall_arrayref( undef, $batch_size))
405 and ($#$r >=0 ) ) {
406 my @recipients = map { $$_[0] } @$r;
407 # print "- ".join(', ', @recipients)."\n";
408 foreach ($send_method) {
409 /^sendmail$/i && do { send_sendmail([$mid], $content, $sender,
410 [@recipients]); last; };
411 /^bsmtp$/i && do { send_bsmtp([$mid], $content, $sender,
412 [@recipients]); last; };
413 /^smtp$/i && do { send_smtp([$mid], $content, $sender,
414 [@recipients]); last; };
415 /^blackhole$/i && do { send_blackhole([$mid], $content, $sender,
416 [@recipients]); last; };
417 die("Value of \$send_method not recognized: $send_method");
418 }
419 }
420 }
421 }
422
423 # Generate new mails
424 $get_arg_handle->execute(5,6);
425
426 while ( (my $mid, my $nid, my $timestamp, my $status, my $uid) =
427 $get_arg_handle->fetchrow_array()) {
428 $get_create_mail_handle->execute($mid, $nid, $timestamp, $uid, $nid);
429 $get_del_arg_handle->execute($mid);
430 }
431
432
433 # Local Variables:
434 # mode:cperl
435 # End:

  ViewVC Help
Powered by ViewVC 1.1.2