def main(): parser, opts, args = parseargs() config.load(opts.config) listnames = opts.listnames or config.list_manager.names includes = set(listname.lower() for listname in listnames) excludes = set(listname.lower() for listname in opts.excludes) listnames = includes - excludes if not listnames: print _('No lists to search') return cres = [] for r in args: cres.append(re.compile(r, re.IGNORECASE)) # dictionary of {address, (listname, ownerp)} matches = {} for listname in listnames: try: mlist = MailList.MailList(listname, lock=False) except errors.MMListError: print _('No such list: $listname') continue if opts.owners: owners = mlist.owner else: owners = [] for cre in cres: for member in mlist.getMembers(): if cre.search(member): addr = mlist.getMemberCPAddress(member) entries = matches.get(addr, {}) aswhat = entries.get(listname, 0) aswhat |= AS_MEMBER entries[listname] = aswhat matches[addr] = entries for owner in owners: if cre.search(owner): entries = matches.get(owner, {}) aswhat = entries.get(listname, 0) aswhat |= AS_OWNER entries[listname] = aswhat matches[owner] = entries addrs = matches.keys() addrs.sort() for k in addrs: hits = matches[k] lists = hits.keys() print k, _('found in:') for name in lists: aswhat = hits[name] if aswhat & AS_MEMBER: print ' ', name if aswhat & AS_OWNER: print ' ', name, _('(as owner)')
def process_lists(glock): for listname in config.list_manager.names: glock.refresh() # Open the list unlocked just to check to see if it is gating news to # mail. If not, we're done with the list. Otherwise, lock the list # and gate the group. mlist = MailList.MailList(listname, lock=False) if not mlist.gateway_to_mail: continue # Get the list's watermark, i.e. the last article number that we gated # from news to mail. None means that this list has never polled its # newsgroup and that we should do a catch up. watermark = getattr(mlist, 'usenet_watermark', None) # Open the newsgroup, but let most exceptions percolate up. try: conn, first, last = open_newsgroup(mlist) except (socket.error, nntplib.NNTPError): break log.info('%s: [%d..%d]', listname, first, last) try: try: if watermark is None: mlist.Lock(timeout=config.LIST_LOCK_TIMEOUT) # This is the first time we've tried to gate this # newsgroup. We essentially do a mass catch-up, otherwise # we'd flood the mailing list. mlist.usenet_watermark = last log.info('%s caught up to article %d', listname, last) else: # The list has been polled previously, so now we simply # grab all the messages on the newsgroup that have not # been seen by the mailing list. The first such article # is the maximum of the lowest article available in the # newsgroup and the watermark. It's possible that some # articles have been expired since the last time gate_news # has run. Not much we can do about that. start = max(watermark + 1, first) if start > last: log.info('nothing new for list %s', listname) else: mlist.Lock(timeout=config.LIST_LOCK_TIMEOUT) log.info('gating %s articles [%d..%d]', listname, start, last) # Use last+1 because poll_newsgroup() employes a for # loop over range, and this will not include the last # element in the list. poll_newsgroup(mlist, conn, start, last + 1, glock) except TimeOutError: log.error('Could not acquire list lock: %s', listname) finally: if mlist.Locked(): mlist.Save() mlist.Unlock() log.info('%s watermark: %d', listname, mlist.usenet_watermark)
def main(): opts, args, parser = parseargs() initialize(opts.config) for name in config.list_manager.names: # The list must be locked in order to open the requests database mlist = MailList.MailList(name) try: count = IListRequests(mlist).count # While we're at it, let's evict yesterday's autoresponse data midnight_today = midnight() evictions = [] for sender in mlist.hold_and_cmd_autoresponses.keys(): date, respcount = mlist.hold_and_cmd_autoresponses[sender] if midnight(date) < midnight_today: evictions.append(sender) if evictions: for sender in evictions: del mlist.hold_and_cmd_autoresponses[sender] # This is the only place we've changed the list's database mlist.Save() if count: # Set the default language the the list's preferred language. _.default = mlist.preferred_language realname = mlist.real_name discarded = auto_discard(mlist) if discarded: count = count - discarded text = _('Notice: $discarded old request(s) ' 'automatically expired.\n\n') else: text = '' if count: text += Utils.maketext( 'checkdbs.txt', { 'count': count, 'mail_host': mlist.mail_host, 'adminDB': mlist.GetScriptURL('admindb', absolute=1), 'real_name': realname, }, mlist=mlist) text += '\n' + pending_requests(mlist) subject = _('$count $realname moderator ' 'request(s) waiting') else: subject = _('$realname moderator request check result') msg = UserNotification(mlist.GetOwnerEmail(), mlist.GetBouncesEmail(), subject, text, mlist.preferred_language) msg.send(mlist, **{'tomoderators': True}) finally: mlist.Unlock()
def main(): opts, args, parser = parseargs() config.load(opts.config) listnames = set(args or config.list_manager.names) if not listnames: print(_('Nothing to do.')) sys.exit(0) for listname in listnames: try: # Be sure the list is locked mlist = MailList.MailList(listname) except errors.MMListError: parser.print_help() print(_('No such list: $listname'), file=sys.stderr) sys.exit(1) try: mlist.bump_digest_volume() finally: mlist.Save() mlist.Unlock()
def do_output(listname, outfile, parser): closep = False try: if outfile == '-': outfp = sys.stdout else: outfp = open(outfile, 'w') closep = True # Open the specified list unlocked, since we're only reading it. try: mlist = MailList.MailList(listname, lock=False) except errors.MMListError: parser.error(_('No such list: $listname')) # Preamble for the config info. PEP 263 charset and capture time. charset = mlist.preferred_language.charset # Set the system's default language. _.default = mlist.preferred_language.code if not charset: charset = 'us-ascii' when = time.ctime(time.time()) print >> outfp, _('''\ # -*- python -*- # -*- coding: $charset -*- ## "$listname" mailing list configuration settings ## captured on $when ''') # Get all the list config info. All this stuff is accessible via the # web interface. for k in config.ADMIN_CATEGORIES: subcats = mlist.GetConfigSubCategories(k) if subcats is None: do_list_categories(mlist, k, None, outfp) else: for subcat in [t[0] for t in subcats]: do_list_categories(mlist, k, subcat, outfp) finally: if closep: outfp.close()
def main(): opts, args, parser = parseargs() initialize(opts.config) for listname in set(opts.listnames or config.list_manager.names): mlist = MailList.MailList(listname, lock=False) if mlist.digest_send_periodic: mlist.Lock() try: try: mlist.send_digest_now() mlist.Save() # We are unable to predict what exception may occur in digest # processing and we don't want to lose the other digests, so # we catch everything. except Exception as errmsg: print >> sys.stderr, \ 'List: %s: problem processing %s:\n%s' % \ (listname, os.path.join(mlist.data_path, 'digest.mbox'), errmsg) finally: mlist.Unlock()
def do_input(listname, infile, checkonly, verbose, parser): fakedoc = FakeDoc() # Open the specified list locked, unless checkonly is set try: mlist = MailList.MailList(listname, lock=not checkonly) except errors.MMListError as error: parser.error(_('No such list "$listname"\n$error')) savelist = False guibyprop = getPropertyMap(mlist) try: globals = {'mlist': mlist} # Any exception that occurs in execfile() will cause the list to not # be saved, but any other problems are not save-fatal. execfile(infile, globals) savelist = True for k, v in globals.items(): if k in ('mlist', '__builtins__'): continue if not hasattr(mlist, k): print >> sys.stderr, _('attribute "$k" ignored') continue if verbose: print >> sys.stderr, _('attribute "$k" changed') missing = [] gui, wtype = guibyprop.get(k, (missing, missing)) if gui is missing: # This isn't an official property of the list, but that's # okay, we'll just restore it the old fashioned way print >> sys.stderr, _('Non-standard property restored: $k') setattr(mlist, k, v) else: # BAW: This uses non-public methods. This logic taken from # the guts of GUIBase.handleForm(). try: validval = gui._getValidValue(mlist, k, wtype, v) except ValueError: print >> sys.stderr, _('Invalid value for property: $k') except errors.EmailAddressError: print >> sys.stderr, _( 'Bad email address for option $k: $v') else: # BAW: Horrible hack, but then this is special cased # everywhere anyway. :( Privacy._setValue() knows that # when ALLOW_OPEN_SUBSCRIBE is false, the web values are # 0, 1, 2 but these really should be 1, 2, 3, so it adds # one. But we really do provide [0..3] so we need to undo # the hack that _setValue adds. :( :( if k == 'subscribe_policy' and \ not config.ALLOW_OPEN_SUBSCRIBE: validval -= 1 # BAW: Another horrible hack. This one is just too hard # to fix in a principled way in Mailman 2.1 elif k == 'new_member_options': # Because this is a Checkbox, _getValidValue() # transforms the value into a list of one item. validval = validval[0] validval = [ bitfield for bitfield, bitval in config.OPTINFO.items() if validval & bitval ] gui._setValue(mlist, k, validval, fakedoc) # BAW: when to do gui._postValidate()??? finally: if savelist and not checkonly: mlist.Save() mlist.Unlock()
def main(): opts, args, parser = parseargs() config.load(opts.config) loginit.initialize(propagate=True) elog = logging.getLogger('mailman.error') blog = logging.getLogger('mailman.bounce') listnames = set(opts.listnames or config.list_manager.names) who = tuple(opts.who) msg = _('[disabled by periodic sweep and cull, no message available]') today = time.mktime(time.localtime()[:3] + (0,) * 6) for listname in listnames: # List of members to notify notify = [] mlist = MailList.MailList(listname) try: interval = mlist.bounce_you_are_disabled_warnings_interval # Find all the members who are currently bouncing and see if # they've reached the disable threshold but haven't yet been # disabled. This is a sweep through the membership catching # situations where they've bounced a bunch, then the list admin # lowered the threshold, but we haven't (yet) seen more bounces # from the member. Note: we won't worry about stale information # or anything else since the normal bounce processing code will # handle that. disables = [] for member in mlist.getBouncingMembers(): if mlist.getDeliveryStatus(member) <> MemberAdaptor.ENABLED: continue info = mlist.getBounceInfo(member) if info.score >= mlist.bounce_score_threshold: disables.append((member, info)) if disables: for member, info in disables: mlist.disableBouncingMember(member, info, msg) # Go through all the members who have delivery disabled, and find # those that are due to have another notification. If they are # disabled for another reason than bouncing, and we're processing # them (because of the command line switch) then they won't have a # bounce info record. We can piggyback on that for all disable # purposes. members = mlist.getDeliveryStatusMembers(who) for member in members: info = mlist.getBounceInfo(member) if not info: # See if they are bounce disabled, or disabled for some # other reason. status = mlist.getDeliveryStatus(member) if status == MemberAdaptor.BYBOUNCE: elog.error( '%s disabled BYBOUNCE lacks bounce info, list: %s', member, mlist.internal_name()) continue info = _BounceInfo( member, 0, today, mlist.bounce_you_are_disabled_warnings, mlist.pend_new(Pending.RE_ENABLE, mlist.internal_name(), member)) mlist.setBounceInfo(member, info) lastnotice = time.mktime(info.lastnotice + (0,) * 6) if opts.force or today >= lastnotice + interval: notify.append(member) # Now, send notifications to anyone who is due for member in notify: blog.info('Notifying disabled member %s for list: %s', member, mlist.internal_name()) try: mlist.sendNextNotification(member) except NotAMemberError: # There must have been some problem with the data we have # on this member. Most likely it's that they don't have a # password assigned. Log this and delete the member. blog.info( 'Cannot send disable notice to non-member: %s', member) mlist.ApprovedDeleteMember(member, 'cron/disabled') mlist.Save() finally: mlist.Unlock()