~mailman-coders/mailman/2.1

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