summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Mailman/Cgi/admin.py28
-rw-r--r--Mailman/Cgi/subscribe.py87
-rw-r--r--Mailman/Defaults.py.in24
-rw-r--r--Mailman/Errors.py3
-rw-r--r--Mailman/MailCommandHandler.py134
-rw-r--r--Mailman/MailList.py134
-rw-r--r--Mailman/Makefile.in2
-rw-r--r--Mailman/versions.py9
8 files changed, 236 insertions, 185 deletions
diff --git a/Mailman/Cgi/admin.py b/Mailman/Cgi/admin.py
index 3a16d3760..95a671765 100644
--- a/Mailman/Cgi/admin.py
+++ b/Mailman/Cgi/admin.py
@@ -428,7 +428,18 @@ def GetItemCharacteristics(table_entry):
def GetItemGuiValue(lst, kind, varname, params):
"""Return a representation of an item's settings."""
if kind == mm_cfg.Radio or kind == mm_cfg.Toggle:
- return RadioButtonArray(varname, params, getattr(lst, varname))
+ #
+ # if we are sending returning the option for subscribe
+ # policy and this site doesn't allow open subscribes,
+ # then we have to alter the value of lst.subscribe_policy
+ # as passed to RadioButtonArray in order to compensate
+ # for the fact that there is one fewer option. correspondingly,
+ # we alter the value back in the change options function -scott
+ #
+ if varname == "subscribe_policy" and not mm_cfg.ALLOW_OPEN_SUBSCRIBE:
+ return RadioButtonArray(varname, params, getattr(lst, varname) - 1)
+ else:
+ return RadioButtonArray(varname, params, getattr(lst, varname))
elif (kind == mm_cfg.String or kind == mm_cfg.Email or
kind == mm_cfg.Host or kind == mm_cfg.Number):
return TextBox(varname, getattr(lst, varname), params)
@@ -669,6 +680,15 @@ def ChangeOptions(lst, category, cgi_info, document):
#
if category != 'members' and not cgi_info.has_key("request_login") and\
len(cgi_info.keys()) > 1:
+ if cgi_info.has_key("subscribe_policy"):
+ if not mm_cfg.ALLOW_OPEN_SUBSCRIBE:
+ #
+ # we have to add one to the value because the
+ # page didn't present an open list as an option
+ #
+ page_setting = string.atoi(cgi_info["subscribe_policy"].value)
+ cgi_info["subscribe_policy"].value = str(page_setting + 1)
+
opt_list = GetConfigOptions(lst, category)
for item in opt_list:
if len(item) < 5:
@@ -699,10 +719,6 @@ def ChangeOptions(lst, category, cgi_info, document):
names.remove('')
subscribe_success = []
subscribe_errors = []
- if lst.send_welcome_msg:
- noack = 0
- else:
- noack = 1
for new_name in map(string.strip,names):
digest = 0
if not lst.digestable:
@@ -711,7 +727,7 @@ def ChangeOptions(lst, category, cgi_info, document):
digest = 1
try:
lst.ApprovedAddMember(new_name, (Utils.GetRandomSeed() +
- Utils.GetRandomSeed()), digest, noack)
+ Utils.GetRandomSeed()), digest)
subscribe_success.append(new_name)
except Errors.MMAlreadyAMember:
subscribe_errors.append((new_name, 'Already a member'))
diff --git a/Mailman/Cgi/subscribe.py b/Mailman/Cgi/subscribe.py
index 1366ab6ca..f6a5e68b2 100644
--- a/Mailman/Cgi/subscribe.py
+++ b/Mailman/Cgi/subscribe.py
@@ -34,7 +34,7 @@ def main():
if len(list_info) < 1:
doc.AddItem(htmlformat.Header(2, "Error"))
doc.AddItem(htmlformat.Bold("Invalid options to CGI script."))
- print doc.Format()
+ print doc.Format(bgcolor="#ffffff")
sys.exit(0)
try:
@@ -42,14 +42,14 @@ def main():
except:
doc.AddItem(htmlformat.Header(2, "Error"))
doc.AddItem(htmlformat.Bold("%s: No such list." % list_name ))
- print doc.Format()
+ print doc.Format(bgcolor="#ffffff")
sys.exit(0)
if not list._ready:
doc.AddItem(htmlformat.Header(2, "Error"))
doc.AddItem(htmlformat.Bold("%s: No such list." % list_name ))
- print doc.Format()
+ print doc.Format(bgcolor="#ffffff")
list.Unlock()
sys.exit(0)
@@ -80,7 +80,7 @@ def main():
doc.AddItem(
htmlformat.Bold("You must supply your email address."))
doc.AddItem(list.GetMailmanFooter())
- print doc.Format()
+ print doc.Format(bgcolor="#ffffff")
list.Unlock()
sys.exit(0)
addr = form['info'].value
@@ -90,7 +90,7 @@ def main():
doc.AddItem(htmlformat.Bold("%s has no subscribed addr <i>%s</i>."
% (list.real_name, addr)))
doc.AddItem(list.GetMailmanFooter())
- print doc.Format()
+ print doc.Format(bgcolor="#ffffff")
list.Unlock()
sys.exit(0)
list.Unlock()
@@ -150,41 +150,11 @@ def main():
digesting = " digest"
else:
digesting = ""
- cookie = Pending.gencookie()
- Pending.add2pending(email, pw, digest, cookie)
- frmremote = " from %s" % remote
- text = Utils.maketext('verify.txt',
- {"email" : email,
- "listaddr" : list.GetListEmail(),
- "listname" : list.real_name,
- "cookie" : cookie,
- "hostname" : frmremote,
- "requestaddr": list.GetRequestEmail(),
- "remote" : frmremote,
- "listadmin" : list.GetAdminEmail(),
- })
- list.SendTextToUser(
- subject=("%s -- confirmation of subscription -- request %d" %
- (list.real_name, cookie)),
- recipient = email,
- sender = list.GetRequestEmail(),
- text = text,
- add_headers = ["Reply-to: %s" % list.GetRequestEmail(),
- "Errors-To: %s" % list.GetAdminEmail()])
- results = results + ("Confirmation from your email address is "
- "required, to prevent anyone from covertly "
- "subscribing you. Instructions are being "
- "sent to you at %s." % email)
- if remote:
- by = " " + remote
- else:
- by = ""
- list.LogMsg("subscribe", "%s: pending %s %s%s",
- list._internal_name,
- "web",
- email,
- by)
-
+ list.AddMember(email, pw, digest, remote)
+ #
+ # check for all the errors that list.AddMember can throw
+ # options on the web page for this cgi
+ #
except Errors.MMBadEmailError:
results = results + ("Mailman won't accept the given email "
"address as a valid address. (Does it "
@@ -192,22 +162,35 @@ def main():
except Errors.MMListNotReady:
results = results + ("The list is not fully functional, and "
"can not accept subscription requests.<p>")
- #
- # deprecating this, it might be useful if we decide to
- # allow approved based subscriptions without confirmation
- #
- ## except Errors.MMNeedApproval, x:
- ## results = results + ("Subscription was <em>deferred</em> "
- ## "because:<br> %s<p>Your request must "
- ## "be approved by the list admin. "
- ## "You will receive email informing you "
- ## "of the moderator's descision when they "
- ## "get to your request.<p>" % x)
+ except Errors.MMSubscribeNeedsConfirmation:
+ results = results + ("Confirmation from your email address is "
+ "required, to prevent anyone from covertly "
+ "subscribing you. Instructions are being "
+ "sent to you at %s." % email)
+
+ except Errors.MMNeedApproval, x:
+ results = results + ("Subscription was <em>deferred</em> "
+ "because:<br> %s<p>Your request must "
+ "be approved by the list admin. "
+ "You will receive email informing you "
+ "of the moderator's descision when they "
+ "get to your request.<p>" % x)
except Errors.MMHostileAddress:
results = results + ("Your subscription is not allowed because "
"the email address you gave is insecure.<p>")
except Errors.MMAlreadyAMember:
results = results + "You are already subscribed!<p>"
+ #
+ # these shouldn't happen, but if someone's futzing with the cgi
+ # they might -scott
+ #
+ except Errors.MMCantDigestError:
+ results = results + "No one can subscribe to the digest of this list!"
+ except Errors.MMMustDigestError:
+ results = results + "This list only supports digest subscriptions!"
+ else:
+ results = results + "You have been successfully subscribed to %s." % (list.real_name)
+
PrintResults(list, results, doc)
@@ -221,7 +204,7 @@ def PrintResults(list, results, doc):
output = list.ParseTags('subscribe.html', replacements)
doc.AddItem(output)
- print doc.Format()
+ print doc.Format(bgcolor="#ffffff")
list.Unlock()
sys.exit(0)
diff --git a/Mailman/Defaults.py.in b/Mailman/Defaults.py.in
index 780d06fc6..45a88301d 100644
--- a/Mailman/Defaults.py.in
+++ b/Mailman/Defaults.py.in
@@ -51,6 +51,7 @@ PRIVATE_ARCHIVE_URL_EXT = '/'
HOME_PAGE = 'index.html'
MAILMAN_OWNER = 'mailman-owner@%s' % DEFAULT_HOST_NAME
+
# System ceiling on number of batches into which deliveries are divided:
MAX_SPAWNS = 40
@@ -113,8 +114,23 @@ from: .*@uplinkpro.com
"""
# Replies to posts inherently directed to list or original sender?
DEFAULT_REPLY_GOES_TO_LIST = 0
-# Admin approval unnecessary for subscribes?
-DEFAULT_OPEN_SUBSCRIBE = 1
+#
+# SUBSCRIBE POLICY
+# 0 - open list (only when ALLOW_OPEN_SUBSCRIBE is set to 1) **
+# 1 - confirmations required for subscribes
+# 2 - admin approval required for subscribes
+# 3 - both confirmations and admin approval required
+#
+# ** please do not choose option 0 if you are not allowing open
+# subscribes (next variable)
+#
+DEFAULT_SUBSCRIBE_POLICY = 1
+#
+# does this site allow completely unchecked subscriptions?
+#
+ALLOW_OPEN_SUBSCRIBE = 0
+
+
# Private_roster == 0: anyone can see, 1: members only, 2: admin only.
DEFAULT_PRIVATE_ROSTER = 0
# When exposing members, make them unrecognizable as email addrs. To
@@ -122,8 +138,6 @@ DEFAULT_PRIVATE_ROSTER = 0
DEFAULT_OBSCURE_ADDRESSES = 1
# Make it 1 when it works.
DEFAULT_MEMBER_POSTING_ONLY = 0
-# 1 for email subscription verification, 2 for admin confirmation:
-DEFAULT_WEB_SUBSCRIBE_REQUIRES_CONFIRMATION = 1
# Digestification Defaults #
@@ -229,4 +243,4 @@ PRIVATE_ARCHIVE_FILE_DIR = os.path.join(PREFIX, 'archives/private')
VERSION = '@VERSION@'
# Data file version number
-DATA_FILE_VERSION = 3
+DATA_FILE_VERSION = 5
diff --git a/Mailman/Errors.py b/Mailman/Errors.py
index 224d4c4bb..5cdfc1b88 100644
--- a/Mailman/Errors.py
+++ b/Mailman/Errors.py
@@ -32,13 +32,14 @@ MMListNotReady = "MMListNotReady"
MMNoSuchUserError = "MMNoSuchUserError"
MMBadPasswordError = "MMBadPasswordError"
MMNeedApproval = "MMNeedApproval"
+MMSubscribeNeedsConfirmation = "MMSubscribeNeedsConfirmation"
+MMBadConfirmation = "MMBadConfirmation"
MMHostileAddress = "MMHostileAddress"
MMAlreadyAMember = "MMAlreadyAMember"
MMPasswordsMustMatch = "MMPasswordsMustMatch"
MMAlreadyDigested = "MMAlreadyDigested"
MMAlreadyUndigested = "MMAlreadyUndigested"
MMBadRequestId = "MMBadRequestId"
-MMWebSubscribeRequiresConfirmation = "MMWebSubscribeRequiresConfirmation"
MODERATED_LIST_MSG = "Moderated list"
IMPLICIT_DEST_MSG = "Implicit destination"
diff --git a/Mailman/MailCommandHandler.py b/Mailman/MailCommandHandler.py
index 4459b36d4..9ef4a5c42 100644
--- a/Mailman/MailCommandHandler.py
+++ b/Mailman/MailCommandHandler.py
@@ -445,45 +445,46 @@ class MailCommandHandler:
password = "%s%s" % (Utils.GetRandomSeed(),
Utils.GetRandomSeed())
if not address:
- pending_addr = mail.GetSender()
+ subscribe_address = string.lower(mail.GetSender())
else:
- pending_addr = address
+ subscribe_address = address
remote = mail.GetSender()
- if pending_addr == self.GetListEmail():
- badremote = "\n\tfrom "
- if remote: badremote = badremote + remote
- else: badremote = badremote + "unidentified sender"
- self.LogMsg("mischief", ("Attempt to self subscribe %s:%s"
- % (pending_addr, badremote)))
- self.AddApprovalMsg("Attempt to subscribe a list to itself!")
- return
- if self.FindUser(pending_addr):
- self.AddError("%s is already a list member." % pending_addr)
- return
- cookie = Pending.gencookie()
- Pending.add2pending(pending_addr, password, digest, cookie)
- if remote == pending_addr:
- remote = ""
+ try:
+ self.AddMember(subscribe_address, password, digest, remote)
+ except Errors.MMSubscribeNeedsConfirmation:
+ #
+ # the confirmation message that's been sent takes place
+ # of the results of the mail command message
+ #
+ self.__NoMailCmdResponse = 1
+ except Errors.MMNeedApproval, admin_email:
+ self.AddToResponse("your subscription request has been forwarded the list "
+ "administrator\nat %s for review.\n" % admin_email)
+ except Errors.MMBadEmailError:
+ self.AddError("Mailman won't accept the given email "
+ "address as a valid address. \n(Does it "
+ "have an @ in it???)")
+ except Errors.MMListNotReady:
+ self.AddError("The list is not fully functional, and "
+ "can not accept subscription requests.")
+ except Errors.MMHostileAddress:
+ self.AddError("Your subscription is not allowed because\n"
+ "the email address you gave is insecure.")
+ except Errors.MMAlreadyAMember:
+ self.AddError("You are already subscribed!")
+ except Errors.MMCantDigestError:
+ self.AddError("No one can subscribe to the digest of this list!")
+ except Errors.MMMustDigestError:
+ self.AddError("This list only supports digest subscriptions!")
else:
- remote = " from " + remote
- text = Utils.maketext(
- 'verify.txt',
- {'email' : pending_addr,
- 'listaddr' : self.GetListEmail(),
- 'listname' : self.real_name,
- 'listadmin' : self.GetAdminEmail(),
- 'cookie' : cookie,
- 'remote' : remote,
- 'requestaddr' : self.GetRequestEmail(),
- })
- self.SendTextToUser(
- subject = "%s -- confirmation of subscription -- request %d" %
- (self.real_name, cookie),
- recipient = pending_addr,
- sender = self.GetRequestEmail(),
- text = text)
- self.__NoMailCmdResponse = 1
- return
+ #
+ # if the list sends a welcome message, we don't need a response
+ # from the mailcommand handler.
+ #
+ if self.send_welcome_msg:
+ self.__NoMailCmdResponse = 1
+ else:
+ self.AddToResponse("Succeeded")
@@ -497,56 +498,27 @@ class MailCommandHandler:
except:
self.AddError("Usage: confirm <confirmation number>\n")
return
- pending = Pending.get_pending()
- if not pending.has_key(cookie):
+ try:
+ self.ProcessConfirmation(cookie)
+ except Errors.MMBadConfirmation:
self.AddError("Invalid confirmation number!\n"
"Please recheck the confirmation number and"
" try again.")
- return
- (email_addr, password, digest, ts) = pending[cookie]
- if self.open_subscribe:
- self.FinishSubscribe(email_addr, password, digest,
- approved=1)
+ except Errors.MMNeedApproval, admin_addr:
+ self.AddToResponse("your request has been forwarded to the list "
+ "administrator for approval")
+
else:
- self.FinishSubscribe(email_addr, password, digest)
- del pending[cookie]
- Pending.set_pending(pending)
-
- def FinishSubscribe(self, addr, password, digest, approved=0):
- try:
- if approved:
- self.ApprovedAddMember(addr, password, digest)
+ #
+ # if the list sends a welcome message, we don't need a response
+ # from the mailcommand handler.
+ #
+ if self.send_welcome_msg:
+ self.__NoMailCmdResponse = 1
else:
- self.AddMember(addr, password, digest)
- self.AddToResponse("Succeeded.")
- except Errors.MMBadEmailError:
- self.AddError("Email address '%s' not accepted by Mailman." %
- addr)
- except Errors.MMMustDigestError:
- self.AddError("List only accepts digest members.")
- except Errors.MMCantDigestError:
- self.AddError("List doesn't accept digest members.")
- except Errors.MMListNotReady:
- self.AddError("List is not functional.")
- except Errors.MMNeedApproval:
- self.AddApprovalMsg("Subscription is pending list admin approval.")
- except Errors.MMHostileAddress:
- self.AddError("Email address '%s' not accepted by Mailman "
- "(insecure address)" % addr)
- except Errors.MMAlreadyAMember:
- self.AddError("%s is already a list member." % addr)
- except:
- self.AddError("An unknown Mailman error occured.")
- self.AddError("Please forward your request to %s" %
- self.GetAdminEmail())
- self.AddError("%s" % sys.exc_type)
- self.LogMsg("error", ("%s:\n\t%s.FinishSubscribe() encountered"
- " unexpected exception:\n\t'%s', '%s'"
- % (__name__,
- self._internal_name,
- str(sys.exc_info()[0]),
- str(sys.exc_info()[1]))))
-
+ self.AddToResponse("Succeeded")
+
+
def AddApprovalMsg(self, cmd):
text = Utils.maketext(
'approve.txt',
diff --git a/Mailman/MailList.py b/Mailman/MailList.py
index 5f05b9e82..6ef9e9c0c 100644
--- a/Mailman/MailList.py
+++ b/Mailman/MailList.py
@@ -172,12 +172,10 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin,
self.info = ''
self.welcome_msg = ''
self.goodbye_msg = ''
- self.open_subscribe = mm_cfg.DEFAULT_OPEN_SUBSCRIBE
+ self.subscribe_policy = mm_cfg.DEFAULT_SUBSCRIBE_POLICY
self.private_roster = mm_cfg.DEFAULT_PRIVATE_ROSTER
self.obscure_addresses = mm_cfg.DEFAULT_OBSCURE_ADDRESSES
self.member_posting_only = mm_cfg.DEFAULT_MEMBER_POSTING_ONLY
- self.web_subscribe_requires_confirmation = \
- mm_cfg.DEFAULT_WEB_SUBSCRIBE_REQUIRES_CONFIRMATION
self.host_name = mm_cfg.DEFAULT_HOST_NAME
# Analogs to these are initted in Digester.InitVars
@@ -353,6 +351,34 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin,
" list. It can be useful for selecting a particular URL"
" of a host that has multiple addresses."),
]
+ if mm_cfg.ALLOW_OPEN_SUBSCRIBE:
+ sub_cfentry = ('subscribe_policy', mm_cfg.Radio,
+ ('none', 'confirm', 'require approval', 'confirm+approval'), 0,
+ "What steps are required for subscription?",
+ "None - no verification steps (<em>Not Recommended </em>)<br>"
+ "confirm (*) - email confirmation step required <br>"
+ "require approval - require list administrator approval for subscriptions <br>"
+ "confirm+approval - both confirm and approve"
+
+ "<p> (*) when someone requests a subscription, mailman sends"
+ "them a notice with a unique subscription request number that "
+ "they must reply to in order to subscribe.<br> This prevents "
+ "list abusers from subscribing people to your list who don't want"
+ "to be subscribed."
+ )
+ else:
+ sub_cfentry = ('subscribe_policy', mm_cfg.Radio,
+ ('confirm', 'require approval', 'confirm+approval'), 1,
+ "What steps are required for subscription?",
+ "confirm (*) - email confirmation required <br>"
+ "require approval - require list administrator approval for subscription"
+ "confirm+approval - both confirm and approve"
+ "<p> (*) when someone requests a subscription, mailman sends"
+ "them a notice with a unique subscription request number that "
+ "they must reply to in order to subscribe.<br> This prevents "
+ "list abusers from subscribing people to your list who don't want"
+ "to be subscribed." )
+
config_info['privacy'] = [
"List access policies, including anti-spam measures,"
@@ -367,25 +393,8 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin,
'Advertise this list when people ask what lists are on '
'this machine?'),
- ('open_subscribe', mm_cfg.Radio, ('No', 'Yes'), 0,
- 'Are subscribes done without admins approval (ie, is this'
- ' an <em>open</em> list)?',
-
- "Disabling this option makes the list <em>closed</em>, where"
- " members are admitted only at the discretion of the list"
- " administrator."),
-
- ('web_subscribe_requires_confirmation', mm_cfg.Radio,
- ('None', 'Requestor confirms via email', 'Admin approves'), 0,
- 'What confirmation is required for on-the-web subscribes?',
-
- "This option determines whether web-initiated subscribes"
- " require further confirmation, either from the subscribed"
- " address or from the list administrator. Absence of"
- " <em>any</em> confirmation makes web-based subscription a"
- " tempting opportunity for mischievous subscriptions by third"
- " parties."),
-
+ sub_cfentry,
+
"Membership exposure",
('private_roster', mm_cfg.Radio,
@@ -633,8 +642,8 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin,
file.close()
self._ready = 1
if check_version:
- self.CheckValues()
- self.CheckVersion(dict)
+ self.CheckValues()
+ self.CheckVersion(dict)
def LogMsg(self, kind, msg, *args):
"""Append a message to the log file for messages of specified kind."""
@@ -669,7 +678,7 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin,
if not self._ready:
raise Errors.MMListNotReady
- def AddMember(self, name, password, digest=0, web_subscribe=0):
+ def AddMember(self, name, password, digest=0, remote=None):
self.IsListInitialized()
# Remove spaces... it's a common thing for people to add...
name = string.join(string.split(string.lower(name)), '')
@@ -688,25 +697,56 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin,
elif not digest and not self.nondigestable:
raise Errors.MMMustDigestError
- if self.open_subscribe:
- if (web_subscribe and self.web_subscribe_requires_confirmation):
- if self.web_subscribe_requires_confirmation == 1:
- # Requester confirmation required.
- raise Errors.MMWebSubscribeRequiresConfirmation
- else:
- # Admin approval required.
- self.AddRequest('add_member', digest, name, password)
+ if self.subscribe_policy == 0: # no confirmation or approval necessary
+ self.ApprovedAddMember(name, password, digest)
+ elif self.subscribe_policy == 1 or self.subscribe_policy == 3: # confirmation
+ import Pending
+ cookie = Pending.gencookie()
+ Pending.add2pending(name, password, digest, cookie)
+ if remote is not None:
+ by = " " + remote
+ remote = " from %s" % remote
else:
- # No approval required.
- self.ApprovedAddMember(name, password, digest)
- else:
- # Blanket admin approval requred...
+ by = ""
+ remote = ""
+ text = Utils.maketext('verify.txt',
+ {"email" : name,
+ "listaddr" : self.GetListEmail(),
+ "listname" : self.real_name,
+ "cookie" : cookie,
+ "hostname" : remote,
+ "requestaddr": self.GetRequestEmail(),
+ "remote" : remote,
+ "listadmin" : self.GetAdminEmail(),
+ })
+ self.SendTextToUser(
+ subject=("%s -- confirmation of subscription -- request %d" %
+ (self.real_name, cookie)),
+ recipient = name,
+ sender = self.GetRequestEmail(),
+ text = text,
+ add_headers = ["Reply-to: %s" % self.GetRequestEmail(),
+ "Errors-To: %s" % self.GetAdminEmail()])
+ self.LogMsg("subscribe", "%s: pending %s %s",
+ self._internal_name,
+ name,
+ by)
+ raise Errors.MMSubscribeNeedsConfirmation
+ else: # approval needed
self.AddRequest('add_member', digest, name, password)
+ raise Errors.MMNeedApproval, self.GetAdminEmail()
+
- def ApprovedAddMember(self, name, password, digest, noack=0):
+
+ def ApprovedAddMember(self, name, password, digest, ack=None):
# XXX klm: It *might* be nice to leave the case of the name alone,
# but provide a common interface that always returns the
# lower case version for computations.
+ if ack is None:
+ if self.send_welcome_msg:
+ ack = 1
+ else:
+ ack = 0
name = string.lower(name)
if self.IsMember(name):
raise Errors.MMAlreadyAMember
@@ -720,9 +760,25 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin,
self._internal_name, kind, name)
self.passwords[name] = password
self.Save()
- if not noack:
+ if ack:
self.SendSubscribeAck(name, password, digest)
+
+ def ProcessConfirmation(self, cookie):
+ import Pending
+ pending = Pending.get_pending()
+ if not pending.has_key(cookie):
+ raise Errors.MMBadConfirmation
+ (email_addr, password, digest, ts) = pending[cookie]
+ del pending[cookie]
+ Pending.set_pending(pending)
+ if self.subscribe_policy == 3: # confirm + approve
+ self.AddRequest('add_member', digest, email_addr, password)
+ raise Errors.MMNeedApproval, self.GetAdminEmail()
+ self.ApprovedAddMember(email_addr, password, digest)
+
+
+
def DeleteMember(self, name, whence=None):
self.IsListInitialized()
# FindMatchingAddresses *should* never return more than 1 address.
diff --git a/Mailman/Makefile.in b/Mailman/Makefile.in
index 85075f7f3..5a1f63f29 100644
--- a/Mailman/Makefile.in
+++ b/Mailman/Makefile.in
@@ -83,7 +83,7 @@ clean:
done
distclean:
- -rm Makefile Defaults.py
+ -rm Makefile Defaults.py mm_cfg.py
for d in $(SUBDIRS); \
do \
(cd $$d; $(MAKE) distclean); \
diff --git a/Mailman/versions.py b/Mailman/versions.py
index 94ece1ad6..d030f2e3d 100644
--- a/Mailman/versions.py
+++ b/Mailman/versions.py
@@ -61,6 +61,15 @@ def UpdateOldVars(l, stored_state):
'mimimum_post_count_before_bounce_action')
PreferStored('bad_posters', 'forbidden_posters')
PreferStored('automatically_remove', 'automatic_bounce_action')
+ if hasattr(l, "open_subscribe"):
+ if l.open_subscribe:
+ if mm_cfg.ALLOW_OPEN_SUBSCRIBE:
+ l.subscribe_policy = 0
+ else:
+ l.subscribe_policy = 1
+ else:
+ l.subscribe_policy = 2 # admin approval
+ delattr(l, "open_subscribe")
# - dropped vars:
# for a in ['archive_retain_text_copy',
# 'archive_update_frequency']: