1# -*- python -*-
2#
3# Copyright (C) 2000-2018 by the Free Software Foundation, Inc.
4#
5# This program is free software; you can redistribute it and/or
6# modify it under the terms of the GNU General Public License
7# as published by the Free Software Foundation; either version 2
8# of the License, or (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
19"""Automatically send a message to a mailing list.
20"""
21
22# To use with Postfix, set the following in your main.cf file:
23#
24# recipient_delimiter = +
25# luser_relay = mm+$user@yourdomain.com
26# owner_request_special = no
27
28import sys
29import os
30import time
31
32import paths
33from Mailman import mm_cfg
34from Mailman import Utils
35from Mailman import MailList
36from Mailman import Errors
37from Mailman.Queue.sbcache import get_switchboard
38from Mailman.Logging.Utils import LogStdErr
39
40# Error code if it's really not a Mailman list addr destination
41EX_NOUSER = 67
42
43LogStdErr('auto', 'auto')
44
45DISPOSE_MAP = {None     : 'tolist',
46               'request': 'torequest',
47               'admin'  : 'toadmin',
48               'owner'  : 'toadmin',
49               }
50
51
52
53def fqdn_listname(listname, hostname):
54    return ('%s@%s' % (listname, hostname)).lower()
55
56
57
58def main():
59    # Postfix sets some environment variables based on information gleaned
60    # from the original message.  This is the most direct way to figure out
61    # which list the message was intended for.
62    extension = os.environ.get('EXTENSION', '').lower()
63    i = extension.rfind('-')
64    if i < 0:
65        listname = extension
66        subdest = 'tolist'
67    else:
68        missing = []
69        listname = extension[:i]
70        subdest = DISPOSE_MAP.get(extension[i+1:], missing)
71        if not Utils.list_exists(listname) or subdest is missing:
72            # must be a list that has a `-' in it's name
73            listname = extension
74            subdest = 'tolist'
75    if not listname:
76        print >> sys.stderr, 'Empty list name (someone being subversive?)'
77        return EX_NOUSER
78    try:
79        mlist = MailList.MailList(listname, lock=0)
80    except Errors.MMListError:
81        print >> sys.stderr, 'List not found:', listname
82        return EX_NOUSER
83
84    # Make sure that the domain part of the incoming address matches the
85    # domain of the mailing list.  Actually, it's possible that one or the
86    # other is more fully qualified, and thus longer.  So we split the domains
87    # by dots, reverse them and make sure that whatever parts /are/ defined
88    # for both are equivalent.
89    domain = os.environ.get('DOMAIN', '').lower()
90    domainp = domain.split('.')
91    hostname = mlist.host_name.split('.')
92    domainp.reverse()
93    hostname.reverse()
94    for ca, cb in zip(domainp, hostname):
95        if ca <> cb:
96            print >> sys.stderr, 'Domain mismatch: %s@%s (expected @%s)' \
97                  % (listname, domain, mlist.host_name)
98            return EX_NOUSER
99
100    if subdest is None:
101        print >> sys.stderr, 'Bad sub-destination:', extension
102        return EX_NOUSER
103
104    inq = get_switchboard(mm_cfg.INQUEUE_DIR)
105    inq.enqueue(sys.stdin.read(),
106                listname=listname,
107                received_time=time.time(),
108                _plaintext=1,
109                **{subdest: 1})
110    return 0
111
112
113
114if __name__ == '__main__':
115    code = main()
116    sys.exit(code)
117