1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
|
# Copyright (C) 1998-2006 by the Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
"""Mixin class with message delivery routines."""
from email.MIMEText import MIMEText
from email.MIMEMessage import MIMEMessage
from Mailman import mm_cfg
from Mailman import Errors
from Mailman import Utils
from Mailman import Message
from Mailman import i18n
from Mailman import Pending
from Mailman.Logging.Syslog import syslog
_ = i18n._
try:
True, False
except NameError:
True = 1
False = 0
class Deliverer:
def SendSubscribeAck(self, name, password, digest, text=''):
pluser = self.getMemberLanguage(name)
if self.welcome_msg:
welcome = Utils.wrap(self.welcome_msg) + '\n'
else:
welcome = ''
if self.umbrella_list:
addr = self.GetMemberAdminEmail(name)
umbrella = Utils.wrap(_('''\
Note: Since this is a list of mailing lists, administrative
notices like the password reminder will be sent to
your membership administrative address, %(addr)s.'''))
else:
umbrella = ''
# get the text from the template
text += Utils.maketext(
'subscribeack.txt',
{'real_name' : self.real_name,
'host_name' : self.host_name,
'welcome' : welcome,
'umbrella' : umbrella,
'emailaddr' : self.GetListEmail(),
'listinfo_url': self.GetScriptURL('listinfo', absolute=True),
'optionsurl' : self.GetOptionsURL(name, absolute=True),
'password' : password,
'user' : self.getMemberCPAddress(name),
}, lang=pluser, mlist=self)
if digest:
digmode = _(' (Digest mode)')
else:
digmode = ''
realname = self.real_name
msg = Message.UserNotification(
self.GetMemberAdminEmail(name), self.GetRequestEmail(),
_('Welcome to the "%(realname)s" mailing list%(digmode)s'),
text, pluser)
msg['X-No-Archive'] = 'yes'
msg.send(self, verp=mm_cfg.VERP_PERSONALIZED_DELIVERIES)
def SendUnsubscribeAck(self, addr, lang):
realname = self.real_name
msg = Message.UserNotification(
self.GetMemberAdminEmail(addr), self.GetBouncesEmail(),
_('You have been unsubscribed from the %(realname)s mailing list'),
Utils.wrap(self.goodbye_msg), lang)
msg.send(self, verp=mm_cfg.VERP_PERSONALIZED_DELIVERIES)
def MailUserPassword(self, user):
listfullname = '%s@%s' % (self.real_name, self.host_name)
requestaddr = self.GetRequestEmail()
# find the lowercased version of the user's address
adminaddr = self.GetBouncesEmail()
assert self.isMember(user)
if not self.getMemberPassword(user):
# The user's password somehow got corrupted. Generate a new one
# for him, after logging this bogosity.
syslog('error', 'User %s had a false password for list %s',
user, self.internal_name())
waslocked = self.Locked()
if not waslocked:
self.Lock()
try:
self.setMemberPassword(user, Utils.MakeRandomPassword())
self.Save()
finally:
if not waslocked:
self.Unlock()
# Now send the user his password
cpuser = self.getMemberCPAddress(user)
recipient = self.GetMemberAdminEmail(cpuser)
subject = _('%(listfullname)s mailing list reminder')
# Get user's language and charset
lang = self.getMemberLanguage(user)
cset = Utils.GetCharSet(lang)
password = self.getMemberPassword(user)
# TK: Make unprintables to ?
# The list owner should allow users to set language options if they
# want to use non-us-ascii characters in password and send it back.
password = unicode(password, cset, 'replace').encode(cset, 'replace')
# get the text from the template
text = Utils.maketext(
'userpass.txt',
{'user' : cpuser,
'listname' : self.real_name,
'fqdn_lname' : self.GetListEmail(),
'password' : password,
'options_url': self.GetOptionsURL(user, absolute=True),
'requestaddr': requestaddr,
'owneraddr' : self.GetOwnerEmail(),
}, lang=lang, mlist=self)
msg = Message.UserNotification(recipient, adminaddr, subject, text,
lang)
msg['X-No-Archive'] = 'yes'
msg.send(self, verp=mm_cfg.VERP_PERSONALIZED_DELIVERIES)
def ForwardMessage(self, msg, text=None, subject=None, tomoderators=True):
# Wrap the message as an attachment
if text is None:
text = _('No reason given')
if subject is None:
text = _('(no subject)')
text = MIMEText(Utils.wrap(text),
_charset=Utils.GetCharSet(self.preferred_language))
attachment = MIMEMessage(msg)
notice = Message.OwnerNotification(
self, subject, tomoderators=tomoderators)
# Make it look like the message is going to the -owner address
notice.set_type('multipart/mixed')
notice.attach(text)
notice.attach(attachment)
notice.send(self)
def SendHostileSubscriptionNotice(self, listname, address):
# Some one was invited to one list but tried to confirm to a different
# list. We inform both list owners of the bogosity, but be careful
# not to reveal too much information.
selfname = self.internal_name()
syslog('mischief', '%s was invited to %s but confirmed to %s',
address, listname, selfname)
# First send a notice to the attacked list
msg = Message.OwnerNotification(
self,
_('Hostile subscription attempt detected'),
Utils.wrap(_("""%(address)s was invited to a different mailing
list, but in a deliberate malicious attempt they tried to confirm the
invitation to your list. We just thought you'd like to know. No further
action by you is required.""")))
msg.send(self)
# Now send a notice to the invitee list
try:
# Avoid import loops
from Mailman.MailList import MailList
mlist = MailList(listname, lock=False)
except Errors.MMListError:
# Oh well
return
otrans = i18n.get_translation()
i18n.set_language(mlist.preferred_language)
try:
msg = Message.OwnerNotification(
mlist,
_('Hostile subscription attempt detected'),
Utils.wrap(_("""You invited %(address)s to your list, but in a
deliberate malicious attempt, they tried to confirm the invitation to a
different list. We just thought you'd like to know. No further action by you
is required.""")))
msg.send(mlist)
finally:
i18n.set_translation(otrans)
def sendProbe(self, member, msg):
listname = self.real_name
# Put together the substitution dictionary.
d = {'listname': listname,
'address': member,
'optionsurl': self.GetOptionsURL(member, absolute=True),
'owneraddr': self.GetOwnerEmail(),
}
text = Utils.maketext('probe.txt', d,
lang=self.getMemberLanguage(member),
mlist=self)
# Calculate the VERP'd sender address for bounce processing of the
# probe message.
token = self.pend_new(Pending.PROBE_BOUNCE, member, msg)
probedict = {
'bounces': self.internal_name() + '-bounces',
'token': token,
}
probeaddr = '%s@%s' % ((mm_cfg.VERP_PROBE_FORMAT % probedict),
self.host_name)
# Calculate the Subject header, in the member's preferred language
ulang = self.getMemberLanguage(member)
otrans = i18n.get_translation()
i18n.set_language(ulang)
try:
subject = _('%(listname)s mailing list probe message')
finally:
i18n.set_translation(otrans)
outer = Message.UserNotification(member, probeaddr, subject,
lang=ulang)
outer.set_type('multipart/mixed')
text = MIMEText(text, _charset=Utils.GetCharSet(ulang))
outer.attach(text)
outer.attach(MIMEMessage(msg))
# Turn off further VERP'ing in the final delivery step. We set
# probe_token for the OutgoingRunner to more easily handling local
# rejects of probe messages.
outer.send(self, envsender=probeaddr, verp=False, probe_token=token)
|