def decorate(mlist, template, what, extradict=None): # `what' is just a descriptive phrase used in the log message # # BAW: We've found too many situations where Python can be fooled into # interpolating too much revealing data into a format string. For # example, a footer of "% silly %(real_name)s" would give a header # containing all list attributes. While we've previously removed such # really bad ones like `password' and `passwords', it's much better to # provide a whitelist of known good attributes, then to try to remove a # blacklist of known bad ones. d = SafeDict({'real_name' : mlist.real_name, 'list_name' : mlist.internal_name(), # For backwards compatibility '_internal_name': mlist.internal_name(), 'host_name' : mlist.host_name, 'web_page_url' : mlist.web_page_url, 'description' : mlist.description, 'info' : mlist.info, 'cgiext' : mm_cfg.CGIEXT, }) if extradict is not None: d.update(extradict) # Using $-strings? if getattr(mlist, 'use_dollar_strings', 0): template = Utils.to_percent(template) # Interpolate into the template try: text = re.sub(r'(?m)(?<!^--) +(?=\n)', '', re.sub(r'\r\n', r'\n', template % d)) except (ValueError, TypeError), e: syslog('error', 'Exception while calculating %s:\n%s', what, e) text = template
def decorate(mlist, template, what, extradict=None): # `what' is just a descriptive phrase used in the log message # # BAW: We've found too many situations where Python can be fooled into # interpolating too much revealing data into a format string. For # example, a footer of "% silly %(real_name)s" would give a header # containing all list attributes. While we've previously removed such # really bad ones like `password' and `passwords', it's much better to # provide a whitelist of known good attributes, then to try to remove a # blacklist of known bad ones. d = SafeDict({ 'real_name': mlist.real_name, 'list_name': mlist.internal_name(), # For backwards compatibility '_internal_name': mlist.internal_name(), 'host_name': mlist.host_name, 'web_page_url': mlist.web_page_url, 'description': mlist.description, 'info': mlist.info, 'cgiext': mm_cfg.CGIEXT, }) if extradict is not None: d.update(extradict) # Using $-strings? if getattr(mlist, 'use_dollar_strings', 0): template = Utils.to_percent(template) # Interpolate into the template try: text = re.sub(r'(?m)(?<!^--) +(?=\n)', '', re.sub(r'\r\n', r'\n', template % d)) except (ValueError, TypeError), e: syslog('error', 'Exception while calculating %s:\n%s', what, e) text = template
def _(s): if s == '': return s assert s # Do translation of the given string into the current language, and do # Ping-string interpolation into the resulting string. # # This lets you write something like: # # now = time.ctime(time.time()) # print _('The current time is: %(now)s') # # and have it Just Work. Note that the lookup order for keys in the # original string is 1) locals dictionary, 2) globals dictionary. # # First, get the frame of the caller frame = sys._getframe(1) # A `safe' dictionary is used so we won't get an exception if there's a # missing key in the dictionary. dict = SafeDict(frame.f_globals.copy()) dict.update(frame.f_locals) # Translating the string returns an encoded 8-bit string. Rather than # turn that into a Unicode, we turn any Unicodes in the dictionary values # into encoded 8-bit strings. BAW: Returning a Unicode here broke too # much other stuff and _() has many tentacles. Eventually I think we want # to use Unicode everywhere. tns = _translation.gettext(s) charset = _translation.charset() if not charset: charset = 'us-ascii' for k, v in dict.items(): if isinstance(v, UnicodeType): dict[k] = v.encode(charset, 'replace') return tns % dict
def quick_maketext(templatefile, dict=None, lang=None, mlist=None): """Create an output using a template""" # Used by various html output functions such as as_html, html_TOC and write_index_entry if mlist is None: listname = '' else: listname = mlist._internal_name if lang is None: if mlist is None: lang = mm_cfg.DEFAULT_SERVER_LANGUAGE else: lang = mlist.preferred_language cachekey = (templatefile, lang, listname) filepath = _templatefilepathcache.get(cachekey) if filepath: template = _templatecache.get(filepath) if filepath is None or template is None: # Use the basic maketext, with defaults to get the raw template template, filepath = Utils.findtext(templatefile, lang=lang, raw=True, mlist=mlist) _templatefilepathcache[cachekey] = filepath _templatecache[filepath] = template # Copied from Utils.maketext() text = template if dict is not None: try: sdict = SafeDict(dict) try: text = sdict.interpolate(template) except UnicodeError: # Try again after coercing the template to unicode utemplate = unicode(template, Utils.GetCharSet(lang), 'replace') text = sdict.interpolate(utemplate) except (TypeError, ValueError): # The template is really screwed up pass # Make sure the text is in the given character set, or html-ify any bogus # characters. return Utils.uncanonstr(text, lang)
def ExternalArchive(self, ar, txt): d = SafeDict({ 'listname': self.internal_name(), 'hostname': self.host_name, }) cmd = ar % d extarch = os.popen(cmd, 'w') extarch.write(txt) status = extarch.close() if status: syslog('error', 'external archiver non-zero exit status: %d\n', (status & 0xff00) >> 8)
def _(s, frame=1): if s == '': return s assert s # Do translation of the given string into the current language, and do # Ping-string interpolation into the resulting string. # # This lets you write something like: # # now = time.ctime(time.time()) # print _('The current time is: %(now)s') # # and have it Just Work. Note that the lookup order for keys in the # original string is 1) locals dictionary, 2) globals dictionary. # # First, get the frame of the caller frame = sys._getframe(frame) # A `safe' dictionary is used so we won't get an exception if there's a # missing key in the dictionary. dict = SafeDict(frame.f_globals.copy()) dict.update(frame.f_locals) # Translating the string returns an encoded 8-bit string. Rather than # turn that into a Unicode, we turn any Unicodes in the dictionary values # into encoded 8-bit strings. BAW: Returning a Unicode here broke too # much other stuff and _() has many tentacles. Eventually I think we want # to use Unicode everywhere. tns = _translation.gettext(s) charset = _translation.charset() if not charset: charset = 'us-ascii' for k, v in list(dict.items()): if isinstance(v, str): dict[k] = v if isinstance(v, (bytes, bytearray)): dict[k] = v.decode(charset, 'replace') try: return tns % dict except (ValueError, TypeError): # Bad interpolation format. Punt. return tns
def quick_maketext(templatefile, dict=None, lang=None, mlist=None): if mlist is None: listname = '' else: listname = mlist._internal_name if lang is None: if mlist is None: lang = mm_cfg.DEFAULT_SERVER_LANGUAGE else: lang = mlist.preferred_language cachekey = (templatefile, lang, listname) filepath = _templatefilepathcache.get(cachekey) if filepath: template = _templatecache.get(filepath) if filepath is None or template is None: # Use the basic maketext, with defaults to get the raw template template, filepath = Utils.findtext(templatefile, lang=lang, raw=True, mlist=mlist) _templatefilepathcache[cachekey] = filepath _templatecache[filepath] = template # Copied from Utils.maketext() text = template if dict is not None: try: sdict = SafeDict(dict) try: text = sdict.interpolate(template) except UnicodeError: # Try again after coercing the template to unicode utemplate = unicode(template, Utils.GetCharSet(lang), 'replace') text = sdict.interpolate(utemplate) except (TypeError, ValueError): # The template is really screwed up pass # Make sure the text is in the given character set, or html-ify any bogus # characters. return Utils.uncanonstr(text, lang)
def quick_maketext(templatefile, dict=None, lang=None, mlist=None): if mlist is None: listname = '' else: listname = mlist._internal_name if lang is None: if mlist is None: lang = mm_cfg.DEFAULT_SERVER_LANGUAGE else: lang = mlist.preferred_language cachekey = (templatefile, lang, listname) filepath = _templatefilepathcache.get(cachekey) if filepath: template = _templatecache.get(filepath) if filepath is None or template is None: # Use the basic maketext, with defaults to get the raw template template, filepath = Utils.findtext(templatefile, lang=lang, raw=True, mlist=mlist) _templatefilepathcache[cachekey] = filepath _templatecache[filepath] = template # Copied from Utils.maketext() text = template if dict is not None: try: sdict = SafeDict(dict) try: text = sdict.interpolate(template) except UnicodeError: # Try again after coercing the template to unicode utemplate = unicode(template, Utils.GetCharSet(lang), 'replace') text = sdict.interpolate(utemplate) except (TypeError, ValueError), e: # The template is really screwed up syslog('error', 'broken template: %s\n%s', filepath, e)
if fp is None: # Try one last time with the distro English template, which, unless # you've got a really broken installation, must be there. try: filename = os.path.join(mm_cfg.TEMPLATE_DIR, 'en', templatefile) fp = open(filename) except IOError, e: if e.errno <> errno.ENOENT: raise # We never found the template. BAD! raise IOError(errno.ENOENT, 'No template file found', templatefile) template = fp.read() fp.close() text = template if dict is not None: try: sdict = SafeDict(dict) try: text = sdict.interpolate(template) except UnicodeError: # Try again after coercing the template to unicode utemplate = unicode(template, GetCharSet(lang), 'replace') text = sdict.interpolate(utemplate) except (TypeError, ValueError), e: # The template is really screwed up syslog('error', 'broken template: %s\n%s', filename, e) pass if raw: return text, filename return wrap(text), filename
def process(mlist, msg, msgdata): # Normally, the replybot should get a shot at this message, but there are # some important short-circuits, mostly to suppress 'bot storms, at least # for well behaved email bots (there are other governors for misbehaving # 'bots). First, if the original message has an "X-Ack: No" header, we # skip the replybot. Then, if the message has a Precedence header with # values bulk, junk, or list, and there's no explicit "X-Ack: yes" header, # we short-circuit. Finally, if the message metadata has a true 'noack' # key, then we skip the replybot too. ack = msg.get('x-ack', '').lower() if ack == 'no' or msgdata.get('noack'): return precedence = msg.get('precedence', '').lower() if ack <> 'yes' and precedence in ('bulk', 'junk', 'list'): return # Check to see if the list is even configured to autorespond to this email # message. Note: the owner script sets the `toowner' key, and the various # confirm, join, leave, request, subscribe and unsubscribe scripts set the # keys we use for `torequest'. toadmin = msgdata.get('toowner') torequest = msgdata.get('torequest') or msgdata.get('toconfirm') or \ msgdata.get('tojoin') or msgdata.get('toleave') if ((toadmin and not mlist.autorespond_admin) or (torequest and not mlist.autorespond_requests) or \ (not toadmin and not torequest and not mlist.autorespond_postings)): return # Now see if we're in the grace period for this sender. graceperiod <= 0 # means always autorespond, as does an "X-Ack: yes" header (useful for # debugging). sender = msg.get_sender() now = time.time() graceperiod = mlist.autoresponse_graceperiod if graceperiod > 0 and ack <> 'yes': if toadmin: quiet_until = mlist.admin_responses.get(sender, 0) elif torequest: quiet_until = mlist.request_responses.get(sender, 0) else: quiet_until = mlist.postings_responses.get(sender, 0) if quiet_until > now: return # # Okay, we know we're going to auto-respond to this sender, craft the # message, send it, and update the database. realname = mlist.real_name subject = _( 'Auto-response for your message to the "%(realname)s" mailing list') # Do string interpolation d = SafeDict({'listname' : realname, 'listurl' : mlist.GetScriptURL('listinfo'), 'requestemail': mlist.GetRequestEmail(), # BAW: Deprecate adminemail; it's not advertised but still # supported for backwards compatibility. 'adminemail' : mlist.GetBouncesEmail(), 'owneremail' : mlist.GetOwnerEmail(), }) # Just because we're using a SafeDict doesn't mean we can't get all sorts # of other exceptions from the string interpolation. Let's be ultra # conservative here. if toadmin: rtext = mlist.autoresponse_admin_text elif torequest: rtext = mlist.autoresponse_request_text else: rtext = mlist.autoresponse_postings_text # Using $-strings? if getattr(mlist, 'use_dollar_strings', 0): rtext = Utils.to_percent(rtext) try: text = rtext % d except Exception: syslog('error', 'Bad autoreply text for list: %s\n%s', mlist.internal_name(), rtext) text = rtext # Wrap the response. text = Utils.wrap(text) outmsg = Message.UserNotification(sender, mlist.GetBouncesEmail(), subject, text, mlist.preferred_language) outmsg['X-Mailer'] = _('The Mailman Replybot') # prevent recursions and mail loops! outmsg['X-Ack'] = 'No' outmsg.send(mlist) # update the grace period database if graceperiod > 0: # graceperiod is in days, we need # of seconds quiet_until = now + graceperiod * 24 * 60 * 60 if toadmin: mlist.admin_responses[sender] = quiet_until elif torequest: mlist.request_responses[sender] = quiet_until else: mlist.postings_responses[sender] = quiet_until