diff options
| author | bwarsaw | 1999-11-10 20:00:52 +0000 |
|---|---|---|
| committer | bwarsaw | 1999-11-10 20:00:52 +0000 |
| commit | 64a68562d0a2fe22fc9fb0d01688ce2ca8c5b8d9 (patch) | |
| tree | 4e5885ebc55782ff3c158225b3ded7cc93524a85 | |
| parent | a16ada3fad582dbe8b8708ec9f4f4cbb08f75ef9 (diff) | |
| download | mailman-64a68562d0a2fe22fc9fb0d01688ce2ca8c5b8d9.tar.gz mailman-64a68562d0a2fe22fc9fb0d01688ce2ca8c5b8d9.tar.zst mailman-64a68562d0a2fe22fc9fb0d01688ce2ca8c5b8d9.zip | |
reworked imports
InitTempVars(): no longer need to call Digest.InitTempVars(), but we
/do/ need to call ListAdmin.InitTempVars().
Save(): must call SaveRequestDb() to flush out any unsaved changes to
the request database.
AddMember(): New call for entering the subscription request requiring
approval to the requests database.
ApprovedAddMembers(), DeleteMember(): Use new Message object
interface.
Post(): Massively re-vamped. Now uses the message pipeline found in
Mailman.Handlers.HandlerAPI.process().
internal_name(), fullpath(): New functional interface to this data.
| -rw-r--r-- | Mailman/MailList.py | 259 |
1 files changed, 62 insertions, 197 deletions
diff --git a/Mailman/MailList.py b/Mailman/MailList.py index 96cf3fccf..f80654e1e 100644 --- a/Mailman/MailList.py +++ b/Mailman/MailList.py @@ -17,33 +17,38 @@ """The class representing a Mailman mailing list. -Mixes in many task-specific classes.""" +Mixes in many task-specific classes. +""" -try: - import mm_cfg -except ImportError: - raise RuntimeError, ('missing mm_cfg - has Config_dist been configured ' - 'for the site?') - -import sys, os, marshal, string, posixfile, time +import sys +import os +import marshal +import string import errno import re -import Utils -import Errors from types import StringType, IntType, DictType -from ListAdmin import ListAdmin -from Deliverer import Deliverer -from MailCommandHandler import MailCommandHandler -from HTMLFormatter import HTMLFormatter -from Archiver import Archiver -from Digester import Digester -from SecurityManager import SecurityManager -from Bouncer import Bouncer -from GatewayManager import GatewayManager +import paths +from Mailman import mm_cfg +from Mailman import Utils +from Mailman import Errors +from Mailman import LockFile + +# base classes +from Mailman.pythonlib.StringIO import StringIO +from Mailman.ListAdmin import ListAdmin +from Mailman.Deliverer import Deliverer +from Mailman.MailCommandHandler import MailCommandHandler +from Mailman.HTMLFormatter import HTMLFormatter +from Mailman.Archiver import Archiver +from Mailman.Digester import Digester +from Mailman.SecurityManager import SecurityManager +from Mailman.Bouncer import Bouncer +from Mailman.GatewayManager import GatewayManager from Mailman.Logging.StampedLogger import StampedLogger -import LockFile + + # Note: # an _ in front of a member variable for the MailList class indicates # a variable that does not save when we marshal our state. @@ -269,7 +274,7 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin, self._log_files = {} # 'class': log_file_obj if name: self._full_path = os.path.join(mm_cfg.LIST_DATA_DIR, name) - Digester.InitTempVars(self) + ListAdmin.InitTempVars(self) def InitVars(self, name=None, admin='', crypted_password=''): """Assign default values - some will be overriden by stored state.""" @@ -797,6 +802,7 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin, finally: os.umask(omask) self.CheckHTMLArchiveDir() + self.SaveRequestsDb() def Load(self, check_version = 1): if self.__createlock_p: @@ -924,9 +930,28 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin, who, by) raise Errors.MMSubscribeNeedsConfirmation - else: # approval needed - self.AddRequest('add_member', digest, name, password) - raise Errors.MMNeedApproval, self.GetAdminEmail() + else: + # subscription approval is required. add this entry to the admin + # requests database. + self.HoldSubscription(name, password, digest) + raise Errors.MMNeedApproval, \ + 'subscriptions to %s require administrator approval' % \ + self.real_name + + def ProcessConfirmation(self, cookie): + from Pending import Pending + got = Pending().confirmed(cookie) + if not got: + raise Errors.MMBadConfirmation + else: + (email_addr, password, digest) = got + if self.subscribe_policy == 3: # confirm + approve + self.HoldSubscription(email_addr, password, digest) + raise Errors.MMNeedApproval, \ + 'subscriptions to %s require administrator approval' % \ + self.real_name + self.ApprovedAddMember(email_addr, password, digest) + self.Save() def ApprovedAddMember(self, name, password, digest, ack=None, admin_notif=None): @@ -1036,23 +1061,10 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin, "admin_email": self.GetAdminEmail(), "listname": self.real_name, "member": name}, 1) - msg = Message.IncomingMessage(txt) + msg = Message.Message(StringIO(txt)) self.DeliverToOwner(msg, self.owner) return result - def ProcessConfirmation(self, cookie): - from Pending import Pending - got = Pending().confirmed(cookie) - if not got: - raise Errors.MMBadConfirmation - else: - (email_addr, password, digest) = got - 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) - self.Save() - def DeleteMember(self, name, whence=None, admin_notif=None): self.IsListInitialized() # FindMatchingAddresses *should* never return more than 1 address. @@ -1098,7 +1110,7 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin, "admin_email": self.GetAdminEmail(), "listname": self.real_name, "member": name}, 1) - msg = Message.IncomingMessage(txt) + msg = Message.Message(StringIO(txt)) self.DeliverToOwner(msg, self.owner) if whence: whence = "; %s" % whence else: whence = "" @@ -1205,165 +1217,12 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin, return line return 0 - # msg should be an IncomingMessage object. - def Post(self, msg, approved=0): + # msg should be an Message.Message object. + def Post(self, msg): self.IsListInitialized() - # Be sure to ExtractApproval, whether or not flag is already set! - msgapproved = self.ExtractApproval(msg) - if not approved: - approved = msgapproved - sender = None - if mm_cfg.USE_ENVELOPE_SENDER: - sender = msg.GetEnvelopeSender() - # Specialcase an ugly sendmail feature: If there exists an - # "owner-foo: bar" alias and sendmail receives mail for address - # "foo", sendmail will change the envelope sender of the message - # to "bar" before delivering. This feature does not appear to - # be configurable. *Boggle*. - if (not sender or sender[:len(self._internal_name)+6] == - '%s-admin' % self._internal_name): - sender = msg.GetSender() -## sys.stderr.write('envsend: %s, sender: %s\n' % -## (msg.GetEnvelopeSender(), msg.GetSender())) - # If it's the admin, which we know by the approved variable, - # we can skip a large number of checks. - if not approved: - beentheres = map(lambda x: string.split(x, ": ")[1][:-1], - msg.getallmatchingheaders('x-beenthere')) - if self.GetListEmail() in beentheres: - # Exit from scripts/post - no longer held - raise Errors.MMLoopingPost - if len(self.forbidden_posters): - forbidden_posters = Utils.List2Dict(self.forbidden_posters) - addrs = Utils.FindMatchingAddresses(sender, forbidden_posters) - if len(addrs): - self.AddRequest('post', Utils.SnarfMessage(msg), - Errors.FORBIDDEN_SENDER_MSG, - msg.getheader('subject')) - if self.moderated and not len(self.posters): - self.AddRequest('post', Utils.SnarfMessage(msg), - Errors.MODERATED_LIST_MSG, - msg.getheader('subject')) - elif self.moderated and len(self.posters): - addrs = Utils.FindMatchingAddresses( - sender, Utils.List2Dict(self.posters)) - if not len(addrs): - self.AddRequest('post', Utils.SnarfMessage(msg), - Errors.MODERATED_LIST_MSG, - msg.getheader('subject')) - # - # not moderated - # - elif len(self.posters): - addrs = Utils.FindMatchingAddresses( - sender, Utils.List2Dict(self.posters)) - if not len(addrs): - if self.member_posting_only: - if not self.IsMember(sender): - self.AddRequest('post', Utils.SnarfMessage(msg), - 'Only approved posters may post' - ' without moderator approval.', - msg.getheader('subject')) - else: - self.AddRequest('post', Utils.SnarfMessage(msg), - 'Only approved posters may post' - ' without moderator approval.', - msg.getheader('subject')) - - elif self.member_posting_only and not self.IsMember(sender): - self.AddRequest('post', Utils.SnarfMessage(msg), - 'Postings from member addresses only.', - msg.getheader('subject')) - if self.max_num_recipients > 0: - recips = [] - toheader = msg.getheader('to') - if toheader: - recips = recips + string.split(toheader, ',') - ccheader = msg.getheader('cc') - if ccheader: - recips = recips + string.split(ccheader, ',') - if len(recips) > self.max_num_recipients: - self.AddRequest('post', Utils.SnarfMessage(msg), - 'Too many recipients.', - msg.getheader('subject')) - if (self.require_explicit_destination and - not self.HasExplicitDest(msg)): - self.AddRequest('post', Utils.SnarfMessage(msg), - Errors.IMPLICIT_DEST_MSG, - msg.getheader('subject')) - if self.administrivia and Utils.IsAdministrivia(msg): - self.AddRequest('post', Utils.SnarfMessage(msg), - 'possible administrivia to list', - msg.getheader("subject")) - - if self.bounce_matching_headers: - triggered = self.HasMatchingHeader(msg) - if triggered: - # Darn - can't include the matching line for the admin - # message because the info would also go to the sender. - self.AddRequest('post', Utils.SnarfMessage(msg), - Errors.SUSPICIOUS_HEADER_MSG, - msg.getheader('subject')) - if self.max_message_size > 0: - if len(msg.body)/1024. > self.max_message_size: - self.AddRequest('post', Utils.SnarfMessage(msg), - 'Message body too long (>%dk)' % - self.max_message_size, - msg.getheader('subject')) - # Prepend the subject_prefix to the subject line. - subj = msg.getheader('subject') - prefix = self.subject_prefix - if not subj: - msg.SetHeader('Subject', '%s(no subject)' % prefix) - elif prefix and not re.search(re.escape(self.subject_prefix), - subj, re.I): - msg.SetHeader('Subject', '%s%s' % (prefix, subj)) - if self.anonymous_list: - del msg['reply-to'] - del msg['sender'] - msg.SetHeader('From', self.GetAdminEmail()) - msg.SetHeader('Reply-to', self.GetListEmail()) - if self.digestable: - self.SaveForDigest(msg) - if self.archive: - self.ArchiveMail(msg) - if self.gateway_to_news: - self.SendMailToNewsGroup(msg) - - dont_send_to_sender = 0 - ack_post = 0 - # Try to get the address the list thinks this sender is - sender = self.FindUser(msg.GetSender()) - if sender: - if self.GetUserOption(sender, mm_cfg.DontReceiveOwnPosts): - dont_send_to_sender = 1 - if self.GetUserOption(sender, mm_cfg.AcknowlegePosts): - ack_post = 1 - # Deliver the mail. - members = self.GetDeliveryMembers() - recipients = [] - for m in members: - if not self.GetUserOption(m, mm_cfg.DisableDelivery): - recipients.append(m) - if dont_send_to_sender: - try: - recipients.remove(self.GetUserSubscribedAddress(sender)) - except ValueError: - # sender does not want to get copies of their own messages - # (not metoo), but delivery to their address is disabled - # (nomail) - pass - self.LogMsg("post", "post to %s from %s size=%d", - self._internal_name, msg.GetSender(), len(msg.body)) - d = self.__dict__.copy() - d['cgiext'] = mm_cfg.CGIEXT - self.DeliverToList(msg, recipients, - header = self.msg_header % d, - footer = self.msg_footer % d) - if ack_post: - self.SendPostAck(msg, sender) - self.last_post_time = time.time() - self.post_id = self.post_id + 1 + # TBD: this is bogus and will later be configurable + import Mailman.Handlers.HandlerAPI + Mailman.Handlers.HandlerAPI.process(self, msg) self.Save() def Locked(self): @@ -1386,3 +1245,9 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin, return ("<%s.%s %s%s at %s>" % (self.__module__, self.__class__.__name__, `self._internal_name`, status, hex(id(self))[2:])) + + def internal_name(self): + return self._internal_name + + def fullpath(self): + return self._full_path |
