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