1
by
This commit was manufactured by cvs2svn to create branch |
1 |
# Copyright (C) 1998,1999,2000,2001,2002 by the Free Software Foundation, Inc.
|
2 |
#
|
|
3 |
# This program is free software; you can redistribute it and/or
|
|
4 |
# modify it under the terms of the GNU General Public License
|
|
5 |
# as published by the Free Software Foundation; either version 2
|
|
6 |
# of the License, or (at your option) any later version.
|
|
7 |
#
|
|
8 |
# This program is distributed in the hope that it will be useful,
|
|
9 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11 |
# GNU General Public License for more details.
|
|
12 |
#
|
|
13 |
# You should have received a copy of the GNU General Public License
|
|
14 |
# along with this program; if not, write to the Free Software
|
|
749
by tkikuchi
FSF office has moved to 51 Franklin Street. |
15 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
1
by
This commit was manufactured by cvs2svn to create branch |
16 |
|
17 |
"""Deliver a message via command-line drop-off.
|
|
18 |
||
19 |
WARNING WARNING WARNING: This module is provided for example purposes only.
|
|
20 |
It should not be used in a production environment for reasons described
|
|
21 |
below. Because of this, you must explicitly enable it with by editing the
|
|
22 |
code. See the WARN section in the process() function.
|
|
23 |
||
24 |
This module delivers the message via the command line interface to the
|
|
25 |
sendmail program. It should work for sendmail clones like Postfix. It is
|
|
26 |
expected that sendmail handles final delivery, message queueing, etc. The
|
|
27 |
recipient list is only trivially split so that the command line is less than
|
|
28 |
about 3k in size.
|
|
29 |
||
30 |
SECURITY WARNING: Because this module uses os.popen(), it goes through the
|
|
31 |
shell. This module does not scan the arguments for potential exploits and so
|
|
32 |
it should be considered unsafe for production use. For performance reasons,
|
|
33 |
it's not recommended either -- use the SMTPDirect delivery module instead,
|
|
34 |
even if you're using the sendmail MTA.
|
|
35 |
||
36 |
DUPLICATES WARNING: Using this module can cause duplicates to be delivered to
|
|
37 |
your membership, depending on your MTA! E.g. It is known that if you're using
|
|
38 |
the sendmail MTA, and if a message contains a single dot on a line by itself,
|
|
39 |
your list members will receive many duplicates.
|
|
40 |
"""
|
|
41 |
||
42 |
import string |
|
43 |
import os |
|
44 |
||
45 |
from Mailman import mm_cfg |
|
46 |
from Mailman import Errors |
|
47 |
from Mailman.Logging.Syslog import syslog |
|
48 |
||
49 |
MAX_CMDLINE = 3000 |
|
50 |
||
51 |
||
52 |
||
53 |
def process(mlist, msg, msgdata): |
|
54 |
"""Process the message object for the given list.
|
|
55 |
||
56 |
The message object is an instance of Mailman.Message and must be fully
|
|
57 |
prepared for delivery (i.e. all the appropriate headers must be set). The
|
|
58 |
message object can have the following attributes:
|
|
59 |
||
60 |
recips - the list of recipients for the message (required)
|
|
61 |
||
62 |
This function processes the message by handing off the delivery of the
|
|
63 |
message to a sendmail (or sendmail clone) program. It can raise a
|
|
64 |
SendmailHandlerError if an error status was returned by the sendmail
|
|
65 |
program.
|
|
66 |
|
|
67 |
"""
|
|
68 |
# WARN: If you've read the warnings above and /still/ insist on using this
|
|
69 |
# module, you must comment out the following line. I still recommend you
|
|
70 |
# don't do this!
|
|
71 |
assert 0, 'Use of the Sendmail.py delivery module is highly discouraged' |
|
72 |
recips = msgdata.get('recips') |
|
73 |
if not recips: |
|
74 |
# Nobody to deliver to!
|
|
75 |
return
|
|
76 |
# Use -f to set the envelope sender
|
|
77 |
cmd = mm_cfg.SENDMAIL_CMD + ' -f ' + mlist.GetBouncesEmail() + ' ' |
|
78 |
# make sure the command line is of a manageable size
|
|
79 |
recipchunks = [] |
|
80 |
currentchunk = [] |
|
81 |
chunklen = 0 |
|
82 |
for r in recips: |
|
83 |
currentchunk.append(r) |
|
84 |
chunklen = chunklen + len(r) + 1 |
|
85 |
if chunklen > MAX_CMDLINE: |
|
86 |
recipchunks.append(string.join(currentchunk)) |
|
87 |
currentchunk = [] |
|
88 |
chunklen = 0 |
|
89 |
# pick up the last one
|
|
90 |
if chunklen: |
|
91 |
recipchunks.append(string.join(currentchunk)) |
|
92 |
# get all the lines of the message, since we're going to do this over and
|
|
93 |
# over again
|
|
94 |
msgtext = str(msg) |
|
95 |
msglen = len(msgtext) |
|
96 |
# cycle through all chunks
|
|
97 |
failedrecips = [] |
|
98 |
for chunk in recipchunks: |
|
99 |
# TBD: SECURITY ALERT. This invokes the shell!
|
|
100 |
fp = os.popen(cmd + chunk, 'w') |
|
101 |
fp.write(msgtext) |
|
102 |
status = fp.close() |
|
103 |
if status: |
|
104 |
errcode = (status & 0xff00) >> 8 |
|
105 |
syslog('post', 'post to %s from %s, size=%d, failure=%d', |
|
106 |
mlist.internal_name(), msg.get_sender(), |
|
107 |
msglen, errcode) |
|
108 |
# TBD: can we do better than this? What if only one recipient out
|
|
109 |
# of the entire chunk failed?
|
|
110 |
failedrecips.append(chunk) |
|
111 |
# Log the successful post
|
|
112 |
syslog('post', 'post to %s from %s, size=%d, success', |
|
113 |
mlist.internal_name(), msg.get_sender(), msglen) |
|
114 |
if failedrecips: |
|
115 |
msgdata['recips'] = failedrecips |
|
116 |
raise Errors.SomeRecipientsFailed |