diff options
| -rw-r--r-- | Mailman/Defaults.py.in | 6 | ||||
| -rw-r--r-- | Mailman/MailList.py | 23 | ||||
| -rw-r--r-- | Mailman/Utils.py | 60 | ||||
| -rw-r--r-- | Mailman/versions.py | 2 |
4 files changed, 84 insertions, 7 deletions
diff --git a/Mailman/Defaults.py.in b/Mailman/Defaults.py.in index 4307298c4..7dce4fce6 100644 --- a/Mailman/Defaults.py.in +++ b/Mailman/Defaults.py.in @@ -184,6 +184,8 @@ DEFAULT_AUTOMATIC_BOUNCE_ACTION = 1 # get in 1 hour. DEFAULT_MAX_POSTS_BETWEEN_BOUNCES = 5 +DEFAULT_ADMINISTRIVIA = 1 + # # how long the cookie authorizing administrative # changes via the admin cgi lasts @@ -195,6 +197,8 @@ ADMIN_COOKIE_LIFE = 60 * 20 # 20 minutes # ADMIN_MEMBER_CHUNKSIZE = 10 + + # These directories are used to find various important files in the Mailman # installation. PREFIX and EXEC_PREFIX are set by configure and should point # to the installation directory of the Mailman package. @@ -250,4 +254,4 @@ PRIVATE_ARCHIVE_FILE_DIR = os.path.join(PREFIX, 'archives/private') VERSION = '@VERSION@' # Data file version number -DATA_FILE_VERSION = 5 +DATA_FILE_VERSION = 6 diff --git a/Mailman/MailList.py b/Mailman/MailList.py index 82a12efd4..5aa8a2b90 100644 --- a/Mailman/MailList.py +++ b/Mailman/MailList.py @@ -278,6 +278,18 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin, '"Reply-To" Munging Considered Harmful</a> for a general.' " discussion of this issue."), + ('administrivia', mm_cfg.Radio, ('No', 'Yes'), 0, + "check messages that are destined for the list for" + " adminsitrative request content?", + + "Administrivia tests will chech mail that is destined for the list " + " for adminstriative contect (like subscribe, unsubscribe, etc). " + " If the message looks like an adminitrative request, it will " + "be added to the administrative requests database and the administrator " + "will be notified. "), + + + ('reminders_to_admins', mm_cfg.Radio, ('No', 'Yes'), 0, 'Send password reminders to "-admin" address instead of' ' directly to user.', @@ -780,8 +792,8 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin, def DeleteMember(self, name, whence=None): self.IsListInitialized() -# FindMatchingAddresses *should* never return more than 1 address. -# However, should log this, just to make sure. + # FindMatchingAddresses *should* never return more than 1 address. + # However, should log this, just to make sure. aliases = Utils.FindMatchingAddresses(name, self.members + self.digest_members) if not len(aliases): @@ -897,7 +909,7 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin, return line return 0 -#msg should be an IncomingMessage object. + # msg should be an IncomingMessage object. def Post(self, msg, approved=0): self.IsListInitialized() # Be sure to ExtractApproval, whether or not flag is already set! @@ -953,6 +965,11 @@ class MailList(MailCommandHandler, HTMLFormatter, Deliverer, ListAdmin, 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: diff --git a/Mailman/Utils.py b/Mailman/Utils.py index 88f2ea5c7..b78731314 100644 --- a/Mailman/Utils.py +++ b/Mailman/Utils.py @@ -368,15 +368,16 @@ def ObscureEmail(addr, for_text=0): When for_text option is set (not default), make a sentence fragment instead of a token.""" if for_text: - return re.sub("@", " at ", addr) + return string.replace(addr, "@", " at ") else: - return re.sub("@", "__at__", addr) + return string.replace(addr, "@", "__at__") def UnobscureEmail(addr): """Invert ObscureEmail() conversion.""" # Contrived to act as an identity operation on already-unobscured # emails, so routines expecting obscured ones will accept both. - return re.sub("__at__", "@", addr) + return string.replace(addr, "__at__", "@") + def map_maillists(func, names=None, unlock=None, verbose=0): """Apply function (of one argument) to all list objs in turn. @@ -436,6 +437,59 @@ def maketext(templatefile, dict, raw=0): return wrap(template % dict) +# +# given an IncomingMessage object, +# test for administrivia (eg subscribe, unsubscribe, etc). +# the test must be a good guess -- messages that return true +# get sent to the list admin instead of the entire list. +# +def IsAdministrivia(msg): + lines = map(string.lower, msg.readlines()) + if len(lines) > 30: + return 0 + # + # check to see how many lines that actually have text in them there are + # + admin_data = {"subscribe": (0, 3), + "unsubscribe": (0, 1), + "who": (0,0), + "info": (0,0), + "lists": (0,0), + "set": (2, 3), + "help": (0,0), + "password": (2, 2), + "options": (0,0), + "remove": (0, 0)} + lines_with_text = 0 + for line in lines: + if string.strip(line): + lines_with_text = lines_with_text + 1 + if lines_with_text > 10: # we might want to change this to mm_cfg.DEFAULT_MAIL_COMMANDS_MAX_LINES. + return 0 + if admin_data.has_key(string.lower(string.strip(msg.body))): + return 1 + try: + if admin_data.has_key(string.lower(string.strip(msg["subject"]))): + return 1 + except KeyError: + pass + for line in lines[:5]: + if not string.strip(line): + return + words = string.split(line) + if admin_data.has_key(words[0]): + min_args, max_args = admin_data[words[0]] + if min_args <= len(words[1:]) <= max_args: + return 1 + return 0 + + + + + + + + diff --git a/Mailman/versions.py b/Mailman/versions.py index d030f2e3d..83de0fd92 100644 --- a/Mailman/versions.py +++ b/Mailman/versions.py @@ -70,6 +70,8 @@ def UpdateOldVars(l, stored_state): else: l.subscribe_policy = 2 # admin approval delattr(l, "open_subscribe") + if not hasattr(l, "administrivia"): + setatrr(l, "administrivia", mm_cfg.DEFAULT_ADMINISTRIVIA) # - dropped vars: # for a in ['archive_retain_text_copy', # 'archive_update_frequency']: |
