Beispiel #1
0
 def _setValue(self, mlist, property, val, doc):
     # Do value conversion from web representation to internal
     # representation.
     try:
         if property == 'bounce_processing':
             val = int(val)
         elif property == 'bounce_score_threshold':
             val = float(val)
         elif property == 'bounce_info_stale_after':
             val = days(int(val))
         elif property == 'bounce_you_are_disabled_warnings':
             val = int(val)
         elif property == 'bounce_you_are_disabled_warnings_interval':
             val = days(int(val))
         elif property == 'bounce_notify_owner_on_disable':
             val = int(val)
         elif property == 'bounce_notify_owner_on_removal':
             val = int(val)
     except ValueError:
         doc.addError(
             _("""Bad value for <a href="?VARHELP=bounce/%(property)s"
             >%(property)s</a>: %(val)s"""),
             tag=_('Error: '))
         return
     GUIBase._setValue(self, mlist, property, val, doc)
Beispiel #2
0
 def GetStandardReplacements(self, lang=None):
     dmember_len = len(self.getDigestMemberKeys())
     member_len = len(self.getRegularMemberKeys())
     # If only one language is enabled for this mailing list, omit the
     # language choice buttons.
     if len(self.GetAvailableLanguages()) == 1:
         listlangs = _(Utils.GetLanguageDescr(self.preferred_language))
     else:
         listlangs = self.GetLangSelectBox(lang).Format()
     d = {
         '<mm-mailman-footer>' : self.GetMailmanFooter(),
         '<mm-list-name>' : self.real_name,
         '<mm-email-user>' : self._internal_name,
         '<mm-list-description>' : Utils.websafe(self.description),
         '<mm-list-info>' : 
             '<!---->' + BR.join(self.info.split(NL)) + '<!---->',
         '<mm-form-end>'  : self.FormatFormEnd(),
         '<mm-archive>'   : self.FormatArchiveAnchor(),
         '</mm-archive>'  : '</a>',
         '<mm-list-subscription-msg>' : self.FormatSubscriptionMsg(),
         '<mm-restricted-list-message>' : \
             self.RestrictedListMessage(_('The current archive'),
                                        self.archive_private),
         '<mm-num-reg-users>' : `member_len`,
         '<mm-num-digesters>' : `dmember_len`,
         '<mm-num-members>' : (`member_len + dmember_len`),
         '<mm-posting-addr>' : '%s' % self.GetListEmail(),
         '<mm-request-addr>' : '%s' % self.GetRequestEmail(),
         '<mm-owner>' : self.GetOwnerEmail(),
         '<mm-reminder>' : self.FormatReminder(self.preferred_language),
         '<mm-host>' : self.host_name,
         '<mm-list-langs>' : listlangs,
         }
Beispiel #3
0
def loginpage(mlist, scriptname, msg='', frontpage=None):
    url = mlist.GetScriptURL(scriptname)
    if frontpage:
        actionurl = url
    else:
        actionurl = Utils.GetRequestURI(url)
    if msg:
        msg = FontAttr(msg, color='#ff0000', size='+1').Format()
        # give an HTTP 401 for authentication failure
        print 'Status: 401 Unauthorized'
    if scriptname == 'admindb':
        who = _('Moderator')
    else:
        who = _('Administrator')
    # Language stuff
    charset = Utils.GetCharSet(mlist.preferred_language)
    print 'Content-type: text/html; charset=' + charset + '\n\n'
    print Utils.maketext('admlogin.html', {
        'listname': mlist.real_name,
        'path': actionurl,
        'message': msg,
        'who': who,
    },
                         mlist=mlist)
    print mlist.GetMailmanFooter()
Beispiel #4
0
def do_discard(mlist, msg):
    sender = msg.get_sender()
    # Do we forward auto-discards to the list owners?
    if mlist.forward_auto_discards:
        lang = mlist.preferred_language
        varhelp = '%s/?VARHELP=privacy/sender/discard_these_nonmembers' % \
                  mlist.GetScriptURL('admin', absolute=1)
        nmsg = Message.UserNotification(mlist.GetOwnerEmail(),
                                        mlist.GetBouncesEmail(),
                                        _('Auto-discard notification'),
                                        lang=lang)
        nmsg.set_type('multipart/mixed')
        text = MIMEText(Utils.wrap(_(
            'The attached message has been automatically discarded.')),
                        _charset=Utils.GetCharSet(lang))
        nmsg.attach(text)

        decrypted = msg.get('X-Mailman-SLS-decrypted', '').lower()
        if decrypted == 'yes':
            syslog('gpg',
 'forwarding only headers of message from %s to listmaster to notify discard since message was decrypted',
 sender)
            msgtext = msg.as_string()
            (header, body) = msgtext.split("\n\n", 1)
            nmsg.attach(MIMEText(header))
        else:
            nmsg.attach(MIMEMessage(msg))

        nmsg.send(mlist)
    # Discard this sucker
    raise Errors.DiscardMessage
def MailmanLogo():
    t = Table(border=0, width='100%')

    version = mm_cfg.VERSION
    mmlink = _("Delivered by Mailman")
    pylink = _("Python Powered")
    gnulink = _("GNU's Not Unix")
    if mm_cfg.SITE_LINK:
        sitelink = mm_cfg.SITE_TEXT

    if mm_cfg.IMAGE_LOGOS:
        def logo(file, alt, base=mm_cfg.IMAGE_LOGOS):
            return '<img src="%s" alt="%s" border="0" />' % \
              (base + file, alt)
        mmlink = logo(DELIVERED_BY, mmlink)
        pylink = logo(PYTHON_POWERED, pylink)
        gnulink = logo(GNU_HEAD, gnulink)
        if mm_cfg.SITE_LINK:
            sitelink = logo(mm_cfg.SITE_LOGO, sitelink, "")

    mmlink = Link(MAILMAN_URL, mmlink + _('<br>version %(version)s'))
    pylink = Link(PYTHON_URL, pylink)
    gnulink = Link(GNU_URL, gnulink)
    links = [mmlink, pylink, gnulink]
    if mm_cfg.SITE_LINK:
        if mm_cfg.SITE_URL:
            sitelink = Link(mm_cfg.SITE_URL, sitelink)
        links.append(sitelink)
    t.AddRow(links)
    return t
Beispiel #6
0
 def GetConfigSubCategories(self, category):
     if category == 'members':
         return [('list',   _('Membership&nbsp;List')),
                 ('add',    _('Mass&nbsp;Subscription')),
                 ('remove', _('Mass&nbsp;Removal')),
                 ]
     return None
Beispiel #7
0
def loginpage(mlist, scriptname, msg='', frontpage=None):
    url = mlist.GetScriptURL(scriptname)
    if frontpage:
        actionurl = url
    else:
        actionurl = Utils.GetRequestURI(url)
    if msg:
        msg = FontAttr(msg, color='#ff0000', size='+1').Format()
        # give an HTTP 401 for authentication failure
        print 'Status: 401 Unauthorized'
    if scriptname == 'admindb':
        who = _('Moderator')
    else:
        who = _('Administrator')
    # Language stuff
    charset = Utils.GetCharSet(mlist.preferred_language)
    print 'Content-type: text/html; charset=' + charset + '\n\n'
    print Utils.maketext(
        'admlogin.html',
        {'listname': mlist.real_name,
         'path'    : actionurl,
         'message' : msg,
         'who'     : who,
         }, mlist=mlist)
    print mlist.GetMailmanFooter()
 def handleForm(self, mlist, category, subcat, cgidata, doc):
     for item in self.GetConfigInfo(mlist, category, subcat):
         # Skip descriptions and legacy non-attributes
         if not isinstance(item, TupleType) or len(item) < 5:
             continue
         # Unpack the gui item description
         property, wtype, args, deps, desc = item[0:5]
         # BAW: I know this code is a little crufty but I wanted to
         # reproduce the semantics of the original code in admin.py as
         # closely as possible, for now.  We can clean it up later.
         #
         # The property may be uploadable...
         uploadprop = property + '_upload'
         if cgidata.has_key(uploadprop) and cgidata[uploadprop].value:
             val = cgidata[uploadprop].value
         elif not cgidata.has_key(property):
             continue
         elif isinstance(cgidata[property], ListType):
             val = [x.value for x in cgidata[property]]
         else:
             val = cgidata[property].value
         # Coerce the value to the expected type, raising exceptions if the
         # value is invalid.
         try:
             val = self._getValidValue(mlist, property, wtype, val)
         except ValueError:
             doc.addError(_('Invalid value for variable: %(property)s'))
         # This is the parent of MMBadEmailError and MMHostileAddress
         except Errors.EmailAddressError, error:
             doc.addError(
                 _('Bad email address for option %(property)s: %(error)s'))
         else:
             # Set the attribute, which will normally delegate to the mlist
             self._setValue(mlist, property, val, doc)
Beispiel #9
0
def maybe_forward(mlist, msg):
    # Does the list owner want to get non-matching bounce messages?
    # If not, simply discard it.
    if mlist.bounce_unrecognized_goes_to_list_owner:
        adminurl = mlist.GetScriptURL('admin', absolute=1) + '/bounce'
        mlist.ForwardMessage(msg,
                             text=_("""\
The attached message was received as a bounce, but either the bounce format
was not recognized, or no member addresses could be extracted from it.  This
mailing list has been configured to send all unrecognized bounce messages to
the list administrator(s).

For more information see:
%(adminurl)s

"""),
                             subject=_('Uncaught bounce notification'),
                             tomoderators=0)
        syslog('bounce',
               '%s: forwarding unrecognized, message-id: %s',
               mlist.internal_name(),
               msg.get('message-id', 'n/a'))
    else:
        syslog('bounce',
               '%s: discarding unrecognized, message-id: %s',
               mlist.internal_name(),
               msg.get('message-id', 'n/a'))
 def GetStandardReplacements(self, lang=None):
     dmember_len = len(self.getDigestMemberKeys())
     member_len = len(self.getRegularMemberKeys())
     # If only one language is enabled for this mailing list, omit the
     # language choice buttons.
     if len(self.GetAvailableLanguages()) == 1:
         listlangs = _(Utils.GetLanguageDescr(self.preferred_language))
     else:
         listlangs = self.GetLangSelectBox(lang).Format()
     d = {
         '<mm-mailman-footer>' : self.GetMailmanFooter(),
         '<mm-list-name>' : self.real_name,
         '<mm-email-user>' : self._internal_name,
         '<mm-list-description>' : Utils.websafe(self.description),
         '<mm-list-info>' : 
             '<!---->' + BR.join(self.info.split(NL)) + '<!---->',
         '<mm-form-end>'  : self.FormatFormEnd(),
         '<mm-archive>'   : self.FormatArchiveAnchor(),
         '</mm-archive>'  : '</a>',
         '<mm-list-subscription-msg>' : self.FormatSubscriptionMsg(),
         '<mm-restricted-list-message>' : \
             self.RestrictedListMessage(_('The current archive'),
                                        self.archive_private),
         '<mm-num-reg-users>' : `member_len`,
         '<mm-num-digesters>' : `dmember_len`,
         '<mm-num-members>' : (`member_len + dmember_len`),
         '<mm-posting-addr>' : '%s' % self.GetListEmail(),
         '<mm-request-addr>' : '%s' % self.GetRequestEmail(),
         '<mm-owner>' : self.GetOwnerEmail(),
         '<mm-reminder>' : self.FormatReminder(self.preferred_language),
         '<mm-host>' : self.host_name,
         '<mm-list-langs>' : listlangs,
         }
Beispiel #11
0
def MailmanLogo():
    t = Table(border=0, width='100%')

    version = mm_cfg.VERSION
    mmlink = _("Delivered by Mailman")
    pylink = _("Python Powered")
    gnulink = _("GNU's Not Unix")
    if mm_cfg.SITE_LINK:
        sitelink = mm_cfg.SITE_TEXT

    if mm_cfg.IMAGE_LOGOS:

        def logo(file, alt, base=mm_cfg.IMAGE_LOGOS):
            return '<img src="%s" alt="%s" border="0" />' % \
              (base + file, alt)

        mmlink = logo(DELIVERED_BY, mmlink)
        pylink = logo(PYTHON_POWERED, pylink)
        gnulink = logo(GNU_HEAD, gnulink)
        if mm_cfg.SITE_LINK:
            sitelink = logo(mm_cfg.SITE_LOGO, sitelink, "")

    mmlink = Link(MAILMAN_URL, mmlink + _('<br>version %(version)s'))
    pylink = Link(PYTHON_URL, pylink)
    gnulink = Link(GNU_URL, gnulink)
    links = [mmlink, pylink, gnulink]
    if mm_cfg.SITE_LINK:
        if mm_cfg.SITE_URL:
            sitelink = Link(mm_cfg.SITE_URL, sitelink)
        links.append(sitelink)
    t.AddRow(links)
    return t
Beispiel #12
0
def maybe_forward(mlist, msg):
    # Does the list owner want to get non-matching bounce messages?
    # If not, simply discard it.
    if mlist.bounce_unrecognized_goes_to_list_owner:
        adminurl = mlist.GetScriptURL('admin', absolute=1) + '/bounce'
        mlist.ForwardMessage(msg,
                             text=_("""\
The attached message was received as a bounce, but either the bounce format
was not recognized, or no member addresses could be extracted from it.  This
mailing list has been configured to send all unrecognized bounce messages to
the list administrator(s).

For more information see:
%(adminurl)s

"""),
                             subject=_('Uncaught bounce notification'),
                             tomoderators=0)
        syslog('bounce',
               '%s: forwarding unrecognized, message-id: %s',
               mlist.internal_name(),
               msg.get('message-id', 'n/a'))
    else:
        syslog('bounce',
               '%s: discarding unrecognized, message-id: %s',
               mlist.internal_name(),
               msg.get('message-id', 'n/a'))
Beispiel #13
0
def process(mlist, msg, msgdata):
    # Extract the sender's address and find them in the user database
    sender = msgdata.get('original_sender', msg.get_sender())
    try:
        ack = mlist.getMemberOption(sender, mm_cfg.AcknowledgePosts)
        if not ack:
            return
    except Errors.NotAMemberError:
        return
    # Okay, they want acknowledgement of their post.  Give them their original
    # subject.  BAW: do we want to use the decoded header?
    origsubj = msgdata.get('origsubj', msg.get('subject', _('(no subject)')))
    # Get the user's preferred language
    lang = msgdata.get('lang', mlist.getMemberLanguage(sender))
    # Now get the acknowledgement template
    realname = mlist.real_name
    text = Utils.maketext(
        'postack.txt', {
            'subject': Utils.oneline(origsubj, Utils.GetCharSet(lang)),
            'listname': realname,
            'listinfo_url': mlist.GetScriptURL('listinfo', absolute=1),
            'optionsurl': mlist.GetOptionsURL(sender, absolute=1),
        },
        lang=lang,
        mlist=mlist,
        raw=1)
    # Craft the outgoing message, with all headers and attributes
    # necessary for general delivery.  Then enqueue it to the outgoing
    # queue.
    subject = _('%(realname)s post acknowledgement')
    usermsg = Message.UserNotification(sender, mlist.GetBouncesEmail(),
                                       subject, text, lang)
    usermsg.send(mlist)
    def OpenIDOption(self, lang):
        #from Cgi import client
        container = Container()
        hostname = mm_cfg.DEFAULT_URL_HOST
        hostid = mm_cfg.DEFAULT_OID_CONSUMER
#       if self.private_roster == 0:
#            either = _('<b><i>either</i></b> ')
#        else:
#            either = ''
#        realname = self.real_name
        container.AddItem(Hidden('language', lang))
        if not self.private_roster:
            container.AddItem(_("Click here for the list of ")
                              + self.real_name
                              + _(" subscribers: "))
            container.AddItem(SubmitButton('LoginThrough',
                                           _("Visit Subscriber list")))
        else:
            if self.private_roster == 1:
                only = _('members')
                whom = _('Address:')
            else:
                only = _('the list administrator')
                whom = _('Admin address:')

        container.AddItem(_("<B> <p>Use Common ")
                             # + whom[:-1].lower()
                              + _("Authentication to access"
                              "  <a href='http://%(hostname)s:%(hostid)s'>  all lists</a>  <p> </B> ")
                              + _("<p> <B> You can enable Common Authentication <a href='http://%(hostname)s/mailman/openidreg'> Enable </a> </B>")
                        #      + whom
                              + " ")
        container.AddItem("</center>")         

        return container
Beispiel #15
0
def process(mlist, msg, msgdata):
    # Extract the sender's address and find them in the user database
    sender = msgdata.get('original_sender', msg.get_sender())
    try:
        ack = mlist.getMemberOption(sender, mm_cfg.AcknowledgePosts)
        if not ack:
            return
    except Errors.NotAMemberError:
        return
    # Okay, they want acknowledgement of their post.  Give them their original
    # subject.  BAW: do we want to use the decoded header?
    origsubj = msgdata.get('origsubj', msg.get('subject', _('(no subject)')))
    # Get the user's preferred language
    lang = msgdata.get('lang', mlist.getMemberLanguage(sender))
    # Now get the acknowledgement template
    realname = mlist.real_name
    text = Utils.maketext(
        'postack.txt',
        {'subject'     : Utils.oneline(origsubj, Utils.GetCharSet(lang)),
         'listname'    : realname,
         'listinfo_url': mlist.GetScriptURL('listinfo', absolute=1),
         'optionsurl'  : mlist.GetOptionsURL(sender, absolute=1),
         }, lang=lang, mlist=mlist, raw=1)
    # Craft the outgoing message, with all headers and attributes
    # necessary for general delivery.  Then enqueue it to the outgoing
    # queue.
    subject = _('%(realname)s post acknowledgement')
    usermsg = Message.UserNotification(sender, mlist.GetBouncesEmail(),
                                       subject, text, lang)
    usermsg.send(mlist)
Beispiel #16
0
 def handleForm(self, mlist, category, subcat, cgidata, doc):
     for item in self.GetConfigInfo(mlist, category, subcat):
         # Skip descriptions and legacy non-attributes
         if not isinstance(item, TupleType) or len(item) < 5:
             continue
         # Unpack the gui item description
         property, wtype, args, deps, desc = item[0:5]
         # BAW: I know this code is a little crufty but I wanted to
         # reproduce the semantics of the original code in admin.py as
         # closely as possible, for now.  We can clean it up later.
         #
         # The property may be uploadable...
         uploadprop = property + '_upload'
         if cgidata.has_key(uploadprop) and cgidata[uploadprop].value:
             val = cgidata[uploadprop].value
         elif not cgidata.has_key(property):
             continue
         elif isinstance(cgidata[property], ListType):
             val = [x.value for x in cgidata[property]]
         else:
             val = cgidata[property].value
         # Coerce the value to the expected type, raising exceptions if the
         # value is invalid.
         try:
             val = self._getValidValue(mlist, property, wtype, val)
         except ValueError:
             doc.addError(_('Invalid value for variable: %(property)s'))
         # This is the parent of MMBadEmailError and MMHostileAddress
         except Errors.EmailAddressError, error:
             doc.addError(
                 _('Bad email address for option %(property)s: %(error)s'))
         else:
             # Set the attribute, which will normally delegate to the mlist
             self._setValue(mlist, property, val, doc)
Beispiel #17
0
 def _setValue(self, mlist, property, val, doc):
     # Watch for the special, immediate action attributes
     if property == "_new_volume" and val:
         mlist.bump_digest_volume()
         volume = mlist.volume
         number = mlist.next_digest_number
         doc.AddItem(
             _(
                 """The next digest will be sent as volume
         %(volume)s, number %(number)s"""
             )
         )
     elif property == "_send_digest_now" and val:
         status = mlist.send_digest_now()
         if status:
             doc.AddItem(_("""A digest has been sent."""))
         else:
             doc.AddItem(_("""There was no digest to send."""))
     else:
         # Everything else...
         if property in ("digest_header", "digest_footer"):
             val = self._convertString(mlist, property, ALLOWEDS, val, doc)
             if val is None:
                 # There was a problem, so don't set it
                 return
         GUIBase._setValue(self, mlist, property, val, doc)
    def scrub_msg822(self, part):
        # submessage
        submsg = part.get_payload(0)
        omask = os.umask(002)
        try:
            url = save_attachment(self.mlist, part, self.dir)
        finally:
            os.umask(omask)
        subject = submsg.get('subject', _('no subject'))
        subject = Utils.oneline(subject, self.lcset)
        date = submsg.get('date', _('no date'))
        who = submsg.get('from', _('unknown sender'))
        who = Utils.oneline(who, self.lcset)
        size = len(str(submsg))
        self.msgtexts.append(unicode(_("""\
An embedded message was scrubbed...
From: %(who)s
Subject: %(subject)s
Date: %(date)s
Size: %(size)s
URL: %(url)s
"""), self.lcset))
        # Replace this part because subparts should not be walk()-ed.
        del part['content-type']
        part.set_payload('blah blah', 'us-ascii')
Beispiel #19
0
 def _setValue(self, mlist, property, val, doc):
     # Do value conversion from web representation to internal
     # representation.
     try:
         if property == 'bounce_processing':
             val = int(val)
         elif property == 'bounce_score_threshold':
             val = float(val)
         elif property == 'bounce_info_stale_after':
             val = days(int(val))
         elif property == 'bounce_you_are_disabled_warnings':
             val = int(val)
         elif property == 'bounce_you_are_disabled_warnings_interval':
             val = days(int(val))
         elif property == 'bounce_notify_owner_on_disable':
             val = int(val)
         elif property == 'bounce_notify_owner_on_removal':
             val = int(val)
     except ValueError:
         doc.addError(
             _("""Bad value for <a href="?VARHELP=bounce/%(property)s"
             >%(property)s</a>: %(val)s"""),
             tag = _('Error: '))
         return
     GUIBase._setValue(self, mlist, property, val, doc)
Beispiel #20
0
 def GetConfigSubCategories(self, category):
     if category == 'privacy':
         return [('subscribing', _('Subscription&nbsp;rules')),
                 ('sender',      _('Sender&nbsp;filters')),
                 ('recipient',   _('Recipient&nbsp;filters')),
                 ('spam',        _('Spam&nbsp;filters')),
                 ]
     return None
Beispiel #21
0
 def addError(self, errmsg, tag=None):
     if tag is None:
         tag = _('Error: ')
     self.AddItem(
         Header(
             3,
             Bold(FontAttr(_(tag), color=mm_cfg.WEB_ERROR_COLOR,
                           size='+2')).Format() + Italic(errmsg).Format()))
Beispiel #22
0
 def GetConfigSubCategories(self, category):
     if category == 'privacy':
         return [('subscribing', _('Subscription&nbsp;rules')),
                 ('sender',      _('Sender&nbsp;filters')),
                 ('recipient',   _('Recipient&nbsp;filters')),
                 ('spam',        _('Spam&nbsp;filters')),
                 ]
     return None
Beispiel #23
0
 def GetConfigSubCategories(self, category):
     if category == 'members':
         return [('list',   _('Membership&nbsp;List')),
                 ('add',    _('Mass&nbsp;Subscription')),
                 ('remove', _('Mass&nbsp;Removal')),
                 ('change', _('Address&nbsp;Change')),
                 ]
     return None
Beispiel #24
0
 def RestrictedListMessage(self, which, restriction):
     if not restriction:
         return ''
     elif restriction == 1:
         return _('''(<i>%(which)s is only available to the list
             members.</i>)''')
     else:
         return _('''(<i>%(which)s is only available to the list
         administrator.</i>)''')
def do_reject(mlist):
    listowner = mlist.GetOwnerEmail()
    if mlist.nonmember_rejection_notice:
        raise Errors.RejectMessage(Utils.wrap(_(mlist.nonmember_rejection_notice)))
    else:
        raise Errors.RejectMessage(Utils.wrap(_("""\
Your message has been rejected, probably because you are not subscribed to the
mailing list and the list's policy is to prohibit non-members from posting to
it.  If you think that your messages are being rejected in error, contact the
mailing list owner at %(listowner)s.""")))
Beispiel #26
0
def convert(mlist):
    for attr in ('msg_header', 'msg_footer', 'digest_header', 'digest_footer',
                 'autoresponse_postings_text', 'autoresponse_admin_text',
                 'autoresponse_request_text'):
        s = getattr(mlist, attr)
        t = Utils.to_dollar(s)
        setattr(mlist, attr, t)
    mlist.use_dollar_strings = 1
    print _('Saving list')
    mlist.Save()
 def RestrictedListMessage(self, which, restriction):
     if not restriction:
         return ''
     elif restriction == 1:
         return _(
             '''(<i>%(which)s is only available to the list
             members.</i>)''')
     else:
         return _('''(<i>%(which)s is only available to the list
         administrator.</i>)''')
Beispiel #28
0
def do_reject(mlist):
    listowner = mlist.GetOwnerEmail()
    if mlist.nonmember_rejection_notice:
        raise Errors.RejectMessage, \
              Utils.wrap(_(mlist.nonmember_rejection_notice))
    else:
        raise Errors.RejectMessage, Utils.wrap(_("""\
You are not allowed to post to this mailing list, and your message has been
automatically rejected.  If you think that your messages are being rejected in
error, contact the mailing list owner at %(listowner)s."""))
Beispiel #29
0
def convert(mlist):
    for attr in ('msg_header', 'msg_footer', 'digest_header', 'digest_footer',
                 'autoresponse_postings_text', 'autoresponse_admin_text',
                 'autoresponse_request_text'):
        s = getattr(mlist, attr)
        t = Utils.to_dollar(s)
        setattr(mlist, attr, t)
    mlist.use_dollar_strings = 1
    print _('Saving list')
    mlist.Save()
    def _setValue(self, mlist, property, val, doc):
        if property == 'real_name' and \
               val.lower() != mlist.internal_name().lower():
            # These values can't differ by other than case
            doc.addError(_("""<b>real_name</b> attribute not
            changed!  It must differ from the list's name by case
            only."""))
        elif property == 'new_member_options':
            # Get current value because there are valid bits not in OPTIONS.
            # If we're the admin CGI, we then process the bits in OPTIONS,
            # turning them on or off as appropriate.  Otherwise we process all
            # the bits in mm_cfg.OPTINFO so that config_list can set and reset
            # them.
            newopts = mlist.new_member_options
            if isinstance(doc, Document):
                opts = OPTIONS
            else:
                opts = mm_cfg.OPTINFO
            for opt in opts:
                bitfield = mm_cfg.OPTINFO[opt]
                if opt in val:
                    newopts |= bitfield
                else:
                    newopts &= ~bitfield
            mlist.new_member_options = newopts
        elif property == 'subject_prefix':
            # Convert any html entities to Unicode
            mlist.subject_prefix = Utils.canonstr(
                val, mlist.preferred_language)
        elif property == 'info':
            if val != mlist.info:
                if Utils.suspiciousHTML(val):
                    doc.addError(_("""The <b>info</b> attribute you saved
contains suspicious HTML that could potentially expose your users to cross-site
scripting attacks.  This change has therefore been rejected.  If you still want
to make these changes, you must have shell access to your Mailman server.
This change can be made with bin/withlist or with bin/config_list by setting
mlist.info.
                        """))
                else:
                    mlist.info = val
        elif property == 'admin_member_chunksize' and (val < 1
                                          or not isinstance(val, int)):
            doc.addError(_("""<b>admin_member_chunksize</b> attribute not
            changed!  It must be an integer > 0."""))
        elif property == 'host_name':
            try:
                Utils.ValidateEmail('user@' + val)
            except Errors.EmailAddressError:
                doc.addError(_("""<b>host_name</b> attribute not changed!
                It must be a valid domain name."""))
            else:
                GUIBase._setValue(self, mlist, property, val, doc)
        else:
            GUIBase._setValue(self, mlist, property, val, doc)
Beispiel #31
0
def do_reject(mlist):
    listowner = mlist.GetOwnerEmail()
    if mlist.nonmember_rejection_notice:
        raise Errors.RejectMessage, \
              Utils.wrap(_(mlist.nonmember_rejection_notice))
    else:
        raise Errors.RejectMessage, Utils.wrap(
            _("""\
You are not allowed to post to this mailing list, and your message has been
automatically rejected.  If you think that your messages are being rejected in
error, contact the mailing list owner at %(listowner)s."""))
Beispiel #32
0
def do_reject(mlist):
    listowner = mlist.GetOwnerEmail()
    if mlist.nonmember_rejection_notice:
        raise Errors.RejectMessage, \
              Utils.wrap(_(mlist.nonmember_rejection_notice))
    else:
        raise Errors.RejectMessage, Utils.wrap(_("""\
Your message has been rejected, probably because you are not subscribed to the
mailing list and the list's policy is to prohibit non-members from posting to
it.  If you think that your messages are being rejected in error, contact the
mailing list owner at %(listowner)s."""))
    def scrub_text(self, part):
        # Plain text scrubber.
        omask = os.umask(002)
        try:
            url = save_attachment(self.mlist, part, self.dir)
        finally:
            os.umask(omask)
        filename = part.get_filename(_('not available'))
        filename = Utils.oneline(filename, self.lcset)
        self.msgtexts.append(unicode(_("""\
An embedded and charset-unspecified text was scrubbed...
Name: %(filename)s
URL: %(url)s
"""), self.lcset))
Beispiel #34
0
    def GetConfigInfo(self, mlist, category, subcat=None):
        if category <> 'topics':
            return None
        WIDTH = mm_cfg.TEXTFIELDWIDTH

        return [
            _('List topic keywords'),

            ('topics_enabled', mm_cfg.Radio, (_('Disabled'), _('Enabled')), 0,
             _('''Should the topic filter be enabled or disabled?'''),

             _("""The topic filter categorizes each incoming email message
             according to <a
            href="http://docs.python.org/library/re.html">regular
             expression filters</a> you specify below.  If the message's
             <code>Subject:</code> or <code>Keywords:</code> header contains a
             match against a topic filter, the message is logically placed
             into a topic <em>bucket</em>.  Each user can then choose to only
             receive messages from the mailing list for a particular topic
             bucket (or buckets).  Any message not categorized in a topic
             bucket registered with the user is not delivered to the list.

             <p>Note that this feature only works with regular delivery, not
             digest delivery.

             <p>The body of the message can also be optionally scanned for
             <code>Subject:</code> and <code>Keywords:</code> headers, as
             specified by the <a
       href="?VARHELP=topics/topics_bodylines_limit">topics_bodylines_limit</a>
             configuration variable.""")),

            ('topics_bodylines_limit', mm_cfg.Number, 5, 0,
             _('How many body lines should the topic matcher scan?'),

             _("""The topic matcher will scan this many lines of the message
             body looking for topic keyword matches.  Body scanning stops when
             either this many lines have been looked at, or a non-header-like
             body line is encountered.  By setting this value to zero, no body
             lines will be scanned (i.e. only the <code>Keywords:</code> and
             <code>Subject:</code> headers will be scanned).  By setting this
             value to a negative number, then all body lines will be scanned
             until a non-header-like line is encountered.
             """)),

            ('topics', mm_cfg.Topics, 0, 0,
             _('Topic keywords, one per line, to match against each message.'),

             _("""Each topic keyword is actually a regular expression, which is
             matched against certain parts of a mail message, specifically the
             <code>Keywords:</code> and <code>Subject:</code> message headers.
             Note that the first few lines of the body of the message can also
             contain a <code>Keywords:</code> and <code>Subject:</code>
             "header" on which matching is also performed.""")),

            ]
def create(mlist, cgi=False, nolock=False, quiet=False):
    if mlist is None:
        return
    listname = mlist.internal_name()
    fieldsz = len(listname) + len('-unsubscribe')
    if cgi:
        # If a list is being created via the CGI, the best we can do is send
        # an email message to mailman-owner requesting that the proper aliases
        # be installed.
        sfp = StringIO()
        if not quiet:
            print(_("""
The mailing list `%(listname)s' has been created via the through-the-web
interface.  In order to complete the activation of this mailing list, the
proper /etc/aliases (or equivalent) file must be updated.  The program
`newaliases' may also have to be run.

Here are the entries for the /etc/aliases file:
"""),
                  file=sfp)
        outfp = sfp
    else:
        if not quiet:
            print(
                C_("""\
To finish creating your mailing list, you must edit your /etc/aliases (or
equivalent) file by adding the following lines, and possibly running the
`newaliases' program:
"""))
        print(C_("""\
## %(listname)s mailing list"""))
        outfp = sys.stdout
    # Common path
    for k, v in makealiases(listname):
        print(k + ':', ((fieldsz - len(k)) * ' '), v, file=outfp)
    # If we're using the command line interface, we're done.  For ttw, we need
    # to actually send the message to mailman-owner now.
    if not cgi:
        print(file=outfp)
        return
    # Send the message to the site -owner so someone can do something about
    # this request.
    siteowner = Utils.get_site_email(extra='owner')
    # Should this be sent in the site list's preferred language?
    msg = Message.UserNotification(
        siteowner, siteowner,
        _('Mailing list creation request for list %(listname)s'),
        sfp.getvalue(), mm_cfg.DEFAULT_SERVER_LANGUAGE)
    msg.send(mlist)
def process(res, args):
    mlist = res.mlist
    password = None
    address = None
    argnum = 0
    for arg in args:
        if arg.startswith('address='):
            address = arg[8:]
        elif argnum == 0:
            password = arg
        else:
            res.results.append(_('Usage:'))
            res.results.append(gethelp(mlist))
            return STOP
        argnum += 1
    # Fill in empty defaults
    if address is None:
        realname, address = parseaddr(res.msg['from'])
    if not mlist.isMember(address):
        listname = mlist.real_name
        res.results.append(
            _('%(address)s is not a member of the %(listname)s mailing list'))
        return STOP
    # If we're doing admin-approved unsubs, don't worry about the password
    if mlist.unsubscribe_policy:
        try:
            mlist.DeleteMember(address, 'mailcmd')
        except Errors.MMNeedApproval:
            res.results.append(
                _("""\
Your unsubscription request has been forwarded to the list administrator for
approval."""))
    elif password is None:
        # No password was given, so we need to do a mailback confirmation
        # instead of unsubscribing them here.
        cpaddr = mlist.getMemberCPAddress(address)
        mlist.ConfirmUnsubscription(cpaddr)
        # We don't also need to send a confirmation to this command
        res.respond = 0
    else:
        # No admin approval is necessary, so we can just delete them if the
        # passwords match.
        oldpw = mlist.getMemberPassword(address)
        if oldpw != password:
            res.results.append(_('You gave the wrong password'))
            return STOP
        mlist.ApprovedDeleteMember(address, 'mailcmd')
        res.results.append(_('Unsubscription request succeeded.'))
Beispiel #37
0
 def _setValue(self, mlist, property, val, doc):
     if property in ('filter_mime_types', 'pass_mime_types'):
         types = []
         for spectype in [s.strip() for s in val.splitlines()]:
             ok = 1
             slashes = spectype.count('/')
             if slashes == 0 and not spectype:
                 ok = 0
             elif slashes == 1:
                 maintype, subtype = [s.strip().lower()
                                      for s in spectype.split('/')]
                 if not maintype or not subtype:
                     ok = 0
             elif slashes > 1:
                 ok = 0
             if not ok:
                 doc.addError(_('Bad MIME type ignored: %(spectype)s'))
             else:
                 types.append(spectype.strip().lower())
         if property == 'filter_mime_types':
             mlist.filter_mime_types = types
         elif property == 'pass_mime_types':
             mlist.pass_mime_types = types
     elif property in ('filter_filename_extensions',
                       'pass_filename_extensions'):
         fexts = []
         for ext in [s.strip() for s in val.splitlines()]:
             fexts.append(ext.lower())
         if property == 'filter_filename_extensions':
             mlist.filter_filename_extensions = fexts
         elif property == 'pass_filename_extensions':
             mlist.pass_filename_extensions = fexts
     else:
         GUIBase._setValue(self, mlist, property, val, doc)
 def _setValue(self, mlist, property, val, doc):
     # Watch for the special, immediate action attributes
     if property == '_mass_catchup' and val:
         mlist.usenet_watermark = None
         doc.AddItem(_('Mass catchup completed'))
     else:
         GUIBase._setValue(self, mlist, property, val, doc)
    def __init__(self, basedir = None, reload = 1, database = None):
        # If basedir isn't provided, assume the current directory
        if basedir is None:
            self.basedir = os.getcwd()
        else:
            basedir = os.path.expanduser(basedir)
            self.basedir = basedir
        self.database = database

        # If the directory doesn't exist, create it.  This code shouldn't get
        # run anymore, we create the directory in Archiver.py.  It should only
        # get used by legacy lists created that are only receiving their first
        # message in the HTML archive now -- Marc
        try:
            os.stat(self.basedir)
        except os.error, errdata:
            errno, errmsg = errdata
            if errno != 2:
                raise os.error, errdata
            else:
                self.message(_('Creating archive directory ') + self.basedir)
                omask = os.umask(0)
                try:
                    os.mkdir(self.basedir, self.DIRMODE)
                finally:
                    os.umask(omask)
 def GetStandardReplacement(self):
     dmember_len = len(self.getDigestMemberKeys())
     member_len = len(self.getRegularMemberKeys())
     # If only one language is enabled for this mailing list, omit the
     # language choice buttons.
     
     d = {
         '<mm-mailman-footer>' : self.GetMailmanFooter(),
         '<mm-list-name>' : self.real_name,
         '<mm-email-user>' : self._internal_name,
         '<mm-list-description>' : self.description,
         '<mm-list-info>' : BR.join(self.info.split(NL)),
         '<mm-form-end>'  : self.FormatFormEnd(),
         '<mm-archive>'   : self.FormatArchiveAnchor(),
         '</mm-archive>'  : '</a>',
         '<mm-list-subscription-msg>' : self.FormatSubscriptionMsg(),
         '<mm-restricted-list-message>' : \
             self.RestrictedListMessage(_('The current archive'),
                                        self.archive_private),
         '<mm-num-reg-users>' : `member_len`,
         '<mm-num-digesters>' : `dmember_len`,
         '<mm-num-members>' : (`member_len + dmember_len`),
         '<mm-posting-addr>' : '%s' % self.GetListEmail(),
         '<mm-request-addr>' : '%s' % self.GetRequestEmail(),
         '<mm-owner>' : self.GetOwnerEmail(),
         '<mm-reminder>' : self.FormatReminder(self.preferred_language),
         '<mm-host>' : self.host_name,
      #   '<mm-list-langs>' : listlangs,
         '<mm-post-thread-addr>' : '%s' % self.GetListStartThreadEmail(), # added for Dlists
         }
 def _setValue(self, mlist, property, val, doc):
     if property in ('filter_mime_types', 'pass_mime_types'):
         types = []
         for spectype in [s.strip() for s in val.splitlines()]:
             ok = 1
             slashes = spectype.count('/')
             if slashes == 0 and not spectype:
                 ok = 0
             elif slashes == 1:
                 maintype, subtype = [
                     s.strip().lower() for s in spectype.split('/')
                 ]
                 if not maintype or not subtype:
                     ok = 0
             elif slashes > 1:
                 ok = 0
             if not ok:
                 doc.addError(_('Bad MIME type ignored: %(spectype)s'))
             else:
                 types.append(spectype.strip().lower())
         if property == 'filter_mime_types':
             mlist.filter_mime_types = types
         elif property == 'pass_mime_types':
             mlist.pass_mime_types = types
     elif property in ('filter_filename_extensions',
                       'pass_filename_extensions'):
         fexts = []
         for ext in [s.strip() for s in val.splitlines()]:
             fexts.append(ext.lower())
         if property == 'filter_filename_extensions':
             mlist.filter_filename_extensions = fexts
         elif property == 'pass_filename_extensions':
             mlist.pass_filename_extensions = fexts
     else:
         GUIBase._setValue(self, mlist, property, val, doc)
Beispiel #42
0
    def __init__(self, basedir=None, reload=1, database=None):
        # If basedir isn't provided, assume the current directory
        if basedir is None:
            self.basedir = os.getcwd()
        else:
            basedir = os.path.expanduser(basedir)
            self.basedir = basedir
        self.database = database

        # If the directory doesn't exist, create it.  This code shouldn't get
        # run anymore, we create the directory in Archiver.py.  It should only
        # get used by legacy lists created that are only receiving their first
        # message in the HTML archive now -- Marc
        try:
            os.stat(self.basedir)
        except os.error, errdata:
            errno, errmsg = errdata
            if errno != 2:
                raise os.error, errdata
            else:
                self.message(_('Creating archive directory ') + self.basedir)
                omask = os.umask(0)
                try:
                    os.mkdir(self.basedir, self.DIRMODE)
                finally:
                    os.umask(omask)
    def scrub_html1(self, part):
        # sanitize == 1
        payload = Utils.websafe(part.get_payload(decode=True))
        # For whitespace in the margin, change spaces into
        # non-breaking spaces, and tabs into 8 of those.  Then use a
        # mono-space font.  Still looks hideous to me, but then I'd
        # just as soon discard them.
        def doreplace(s):
            return s.expandtabs(8).replace(' ', '&nbsp;')
        lines = [doreplace(s) for s in payload.split('\n')]
        payload = '<tt>\n' + BR.join(lines) + '\n</tt>\n'
        part.set_payload(payload)
        # We're replacing the payload with the decoded payload so this
        # will just get in the way.
        del part['content-transfer-encoding']
        omask = os.umask(002)
        try:
            url = save_attachment(self.mlist, part, self.dir,
                                  filter_html=False)
        finally:
            os.umask(omask)
        self.msgtexts.append(unicode(_("""\
An HTML attachment was scrubbed...
URL: %(url)s
"""), self.lcset))
Beispiel #44
0
 def _setValue(self, mlist, property, val, doc):
     # Watch for the special, immediate action attributes
     if property == '_mass_catchup' and val:
         mlist.usenet_watermark = None
         doc.AddItem(_('Mass catchup completed'))
     else:
         GUIBase._setValue(self, mlist, property, val, doc)
    def do_command(self, cmd, args=None):
        if args is None:
            args = ()
        # Try to import a command handler module for this command
        modname = 'Mailman.Commands.cmd_' + cmd
        try:
            __import__(modname)
            handler = sys.modules[modname]
        # ValueError can be raised if cmd has dots in it.
        except (ImportError, ValueError):
            # If we're on line zero, it was the Subject: header that didn't
            # contain a command.  It's possible there's a Re: prefix (or
            # localized version thereof) on the Subject: line that's messing
            # things up.  Pop the prefix off and try again... once.
            #
            # If that still didn't work it isn't enough to stop processing.
            # BAW: should we include a message that the Subject: was ignored?
            if not self.subjcmdretried and args:
                self.subjcmdretried += 1
                cmd = args.pop(0)
                return self.do_command(cmd, args)
            return self.lineno <> 0
	# with Dlists, we don't allow email subscription
  	if DlistUtils.enabled(self.mlist) and (cmd == 'subscribe' or cmd == 'join'):
            realname = self.mlist.real_name
            domain = Utils.get_domain()
            self.results.append(Utils.wrap(_("""\
This list cannot be subscribed to via email. 
Please use the website at http://%(domain)s/mailman/listinfo/%(realname)s .
""")))
            return self.lineno <> 0 # superstitious behavior as they do it above

	return handler.process(self, args)
Beispiel #46
0
    def _setValue(self, mlist, property, val, doc):
        if property == 'real_name' and \
               val.lower() <> str(mlist.real_name.lower()):
            # These values can't differ by other than case
            doc.addError(_("""<b>real_name</b> attribute not
            changed!  It must differ from the list's name by case
            only."""))
        elif property == 'new_member_options':
            # Get current value because there are valid bits not in OPTIONS.
            # If we're the admin CGI, we then process the bits in OPTIONS,
            # turning them on or off as appropriate.  Otherwise we process all
            # the bits in mm_cfg.OPTINFO so that config_list can set and reset
            # them.
            newopts = mlist.new_member_options
            if isinstance(doc, Document):
                opts = OPTIONS
            else:
                opts = mm_cfg.OPTINFO
            for opt in opts:
                bitfield = mm_cfg.OPTINFO[opt]
                if opt in val:
                    newopts |= bitfield
                else:
                    newopts &= ~bitfield
            mlist.new_member_options = newopts
        elif property == 'subject_prefix':
            # Convert any html entities to Unicode
            mlist.subject_prefix = Utils.canonstr(
                val, mlist.preferred_language)
        elif property == 'info':
            if val <> mlist.info:
                if 0 and Utils.suspiciousHTML(val):
                    doc.addError(_("""The <b>info</b> attribute you saved
contains suspicious HTML that could potentially expose your users to cross-site
scripting attacks.  This change has therefore been rejected.  If you still want
to make these changes, you must have shell access to your Mailman server.
This change can be made with bin/withlist or with bin/config_list by setting
mlist.info.
                        """))
                else:
                    mlist.info = val
        elif property == 'admin_member_chunksize' and (val < 1
                                          or not isinstance(val, IntType)):
            doc.addError(_("""<b>admin_member_chunksize</b> attribute not
            changed!  It must be an integer > 0."""))
        else:
            GUIBase._setValue(self, mlist, property, val, doc)
Beispiel #47
0
def process(res, args):
    mlist = res.mlist
    password = None
    address = None
    argnum = 0
    for arg in args:
        if arg.startswith('address='):
            address = arg[8:]
        elif argnum == 0:
            password = arg
        else:
            res.results.append(_('Usage:'))
            res.results.append(gethelp(mlist))
            return STOP
        argnum += 1
    # Fill in empty defaults
    if address is None:
        realname, address = parseaddr(res.msg['from'])
    if not mlist.isMember(address):
        listname = mlist.real_name
        res.results.append(
            _('%(address)s is not a member of the %(listname)s mailing list'))
        return STOP
    # If we're doing admin-approved unsubs, don't worry about the password
    if mlist.unsubscribe_policy:
        try:
            mlist.DeleteMember(address, 'mailcmd')
        except Errors.MMNeedApproval:
            res.results.append(_("""\
Your unsubscription request has been forwarded to the list administrator for
approval."""))
    elif password is None:
        # No password was given, so we need to do a mailback confirmation
        # instead of unsubscribing them here.
        cpaddr = mlist.getMemberCPAddress(address)
        mlist.ConfirmUnsubscription(cpaddr)
        # We don't also need to send a confirmation to this command
        res.respond = 0
    else:
        # No admin approval is necessary, so we can just delete them if the
        # passwords match.
        oldpw = mlist.getMemberPassword(address)
        if oldpw <> password:
            res.results.append(_('You gave the wrong password'))
            return STOP
        mlist.ApprovedDeleteMember(address, 'mailcmd')
        res.results.append(_('Unsubscription request succeeded.'))
Beispiel #48
0
def process(mlist, msg, msgdata):
    # Short circuit if we've already calculated the recipients list,
    # regardless of whether the list is empty or not.
    if msgdata.has_key('recips'):
        return
    # Should the original sender should be included in the recipients list?
    include_sender = 1
    sender = msg.get_sender()
    try:
        if mlist.getMemberOption(sender, mm_cfg.DontReceiveOwnPosts):
            include_sender = 0
    except Errors.NotAMemberError:
        pass
    # Support for urgent messages, which bypasses digests and disabled
    # delivery and forces an immediate delivery to all members Right Now.  We
    # are specifically /not/ allowing the site admins password to work here
    # because we want to discourage the practice of sending the site admin
    # password through email in the clear. (see also Approve.py)
    missing = []
    password = msg.get('urgent', missing)
    if password is not missing:
        if mlist.Authenticate((mm_cfg.AuthListPoster,
                               mm_cfg.AuthListModerator,
                               mm_cfg.AuthListAdmin),
                              password):
            recips = mlist.getMemberCPAddresses(mlist.getRegularMemberKeys() +
                                                mlist.getDigestMemberKeys())
            msgdata['recips'] = recips
            return
        else:
            # Bad Urgent: password, so reject it instead of passing it on.  I
            # think it's better that the sender know they screwed up than to
            # deliver it normally.
            realname = mlist.real_name
            text = _("""\
Your urgent message to the %(realname)s mailing list was not authorized for
delivery.  The original message as received by Mailman is attached.
""")
            raise Errors.RejectMessage, Utils.wrap(text)
    # Calculate the regular recipients of the message
    recips = [mlist.getMemberCPAddress(m)
              for m in mlist.getRegularMemberKeys()
              if mlist.getDeliveryStatus(m) == ENABLED]
    # Remove the sender if they don't want to receive their own posts
    if not include_sender:
        try:
            recips.remove(mlist.getMemberCPAddress(sender))
        except (Errors.NotAMemberError, ValueError):
            # Sender does not want to get copies of their own messages (not
            # metoo), but delivery to their address is disabled (nomail).  Or
            # the sender is not a member of the mailing list.
            pass
    # Handle topic classifications
    do_topic_filters(mlist, msg, msgdata, recips)
    # Regular delivery exclude/include (if in/not_in To: or Cc:) lists
    recips = do_exclude(mlist, msg, msgdata, recips)
    recips = do_include(mlist, msg, msgdata, recips)
    # Bookkeeping
    msgdata['recips'] = recips
Beispiel #49
0
 def FormatUmbrellaNotice(self, user, type):
     addr = self.GetMemberAdminEmail(user)
     if self.umbrella_list:
         return _("(Note - you are subscribing to a list of mailing lists, "
                  "so the %(type)s notice will be sent to the admin address"
                  " for your membership, %(addr)s.)<p>")
     else:
         return ""
Beispiel #50
0
 def _postValidate(self, mlist, doc):
     if not mlist.reply_to_address.strip() and \
            mlist.reply_goes_to_list == 2:
         # You can't go to an explicit address that is blank
         doc.addError(_("""You cannot add a Reply-To: to an explicit
         address if that address is blank.  Resetting these values."""))
         mlist.reply_to_address = ''
         mlist.reply_goes_to_list = 0
 def FormatUmbrellaNotice(self, user, type):
     addr = self.GetMemberAdminEmail(user)
     if self.umbrella_list:
         return _("(Note - you are subscribing to a list of mailing lists, "
                  "so the %(type)s notice will be sent to the admin address"
                  " for your membership, %(addr)s.)<p>")
     else:
         return ""
Beispiel #52
0
 def _postValidate(self, mlist, doc):
     if not mlist.reply_to_address.strip() and \
            mlist.reply_goes_to_list == 2:
         # You can't go to an explicit address that is blank
         doc.addError(_("""You cannot add a Reply-To: to an explicit
         address if that address is blank.  Resetting these values."""))
         mlist.reply_to_address = ''
         mlist.reply_goes_to_list = 0
def process(res, args):
    # Get the help text introduction
    mlist = res.mlist
    # Since this message is personalized, add some useful information if the
    # address requesting help is a member of the list.
    msg = res.msg
    for sender in msg.get_senders():
        if mlist.isMember(sender):
            memberurl = mlist.GetOptionsURL(sender, absolute=1)
            urlhelp = _(
                'You can access your personal options via the following url:')
            res.results.append(urlhelp)
            res.results.append(memberurl)
            # Get a blank line in the output.
            res.results.append('')
            break
    # build the specific command helps from the module docstrings
    modhelps = {}
    import Mailman.Commands
    path = os.path.dirname(os.path.abspath(Mailman.Commands.__file__))
    for file in os.listdir(path):
        if not file.startswith('cmd_') or not file.endswith('.py'):
            continue
        module = os.path.splitext(file)[0]
        modname = 'Mailman.Commands.' + module
        try:
            __import__(modname)
        except ImportError:
            continue
        cmdname = module[4:]
        help = None
        if hasattr(sys.modules[modname], 'gethelp'):
            help = sys.modules[modname].gethelp(mlist)
        if help:
            modhelps[cmdname] = help
    # Now sort the command helps
    helptext = []
    keys = list(modhelps.keys())
    keys.sort()
    for cmd in keys:
        helptext.append(modhelps[cmd])
    commands = EMPTYSTRING.join(helptext)
    # Now craft the response
    helptext = Utils.maketext(
        'help.txt', {
            'listname': mlist.real_name,
            'version': mm_cfg.VERSION,
            'listinfo_url': mlist.GetScriptURL('listinfo', absolute=1),
            'requestaddr': mlist.GetRequestEmail(),
            'adminaddr': mlist.GetOwnerEmail(),
            'commands': commands,
        },
        mlist=mlist,
        lang=res.msgdata['lang'],
        raw=1)
    # Now add to the response
    res.results.append('help')
    res.results.append(helptext)
Beispiel #54
0
def usage(code, msg=''):
    if code:
        fd = sys.stderr
    else:
        fd = sys.stdout
    print >> fd, _(__doc__.replace('%', '%%'))
    if msg:
        print >> fd, msg
    sys.exit(code)
Beispiel #55
0
def process(res, args):
    mlist = res.mlist
    if len(args) <> 1:
        res.results.append(_('Usage:'))
        res.results.append(gethelp(mlist))
        return STOP
    cookie = args[0]
    try:
        results = mlist.ProcessConfirmation(cookie, res.msg)
    except Errors.MMBadConfirmation, e:
        # Express in approximate days
        days = int(mm_cfg.PENDING_REQUEST_LIFE / mm_cfg.days(1) + 0.5)
        res.results.append(
            _("""\
Invalid confirmation string.  Note that confirmation strings expire
approximately %(days)s days after the initial subscription request.  If your
confirmation has expired, please try to re-submit your original request or
message."""))
Beispiel #56
0
class T:
    DIRMODE = 0755  # Mode to give to created directories
    FILEMODE = 0644  # Mode to give to created files
    INDEX_EXT = ".html"  # Extension for indexes

    def __init__(self, basedir=None, reload=1, database=None):
        # If basedir isn't provided, assume the current directory
        if basedir is None:
            self.basedir = os.getcwd()
        else:
            basedir = os.path.expanduser(basedir)
            self.basedir = basedir
        self.database = database

        # If the directory doesn't exist, create it.  This code shouldn't get
        # run anymore, we create the directory in Archiver.py.  It should only
        # get used by legacy lists created that are only receiving their first
        # message in the HTML archive now -- Marc
        try:
            os.stat(self.basedir)
        except os.error, errdata:
            errno, errmsg = errdata
            if errno != 2:
                raise os.error, errdata
            else:
                self.message(_('Creating archive directory ') + self.basedir)
                omask = os.umask(0)
                try:
                    os.mkdir(self.basedir, self.DIRMODE)
                finally:
                    os.umask(omask)

        # Try to load previously pickled state
        try:
            if not reload:
                raise IOError
            f = open(os.path.join(self.basedir, 'pipermail.pck'), 'r')
            self.message(_('Reloading pickled archive state'))
            d = pickle.load(f)
            f.close()
            for key, value in d.items():
                setattr(self, key, value)
        except (IOError, EOFError):
            # No pickled version, so initialize various attributes
            self.archives = []  # Archives
            self._dirty_archives = []  # Archives that will have to be updated
            self.sequence = 0  # Sequence variable used for
            #   numbering articles
            self.update_TOC = 0  # Does the TOC need updating?
        #
        # make the basedir variable work when passed in as an __init__ arg
        # and different from the one in the pickle.  Let the one passed in
        # as an __init__ arg take precedence if it's stated.  This way, an
        # archive can be moved from one place to another and still work.
        #
        if basedir != self.basedir:
            self.basedir = basedir
def remove(mlist, cgi=False):
    listname = mlist.internal_name()
    fieldsz = len(listname) + len('-unsubscribe')
    if cgi:
        # If a list is being removed via the CGI, the best we can do is send
        # an email message to mailman-owner requesting that the appropriate
        # aliases be deleted.
        sfp = StringIO()
        print(_("""\
The mailing list `%(listname)s' has been removed via the through-the-web
interface.  In order to complete the de-activation of this mailing list, the
appropriate /etc/aliases (or equivalent) file must be updated.  The program
`newaliases' may also have to be run.

Here are the entries in the /etc/aliases file that should be removed:
"""),
              file=sfp)
        outfp = sfp
    else:
        print(
            C_("""
To finish removing your mailing list, you must edit your /etc/aliases (or
equivalent) file by removing the following lines, and possibly running the
`newaliases' program:

## %(listname)s mailing list"""))
        outfp = sys.stdout
    # Common path
    for k, v in makealiases(listname):
        print(k + ':', ((fieldsz - len(k)) * ' '), v, file=outfp)
    # If we're using the command line interface, we're done.  For ttw, we need
    # to actually send the message to mailman-owner now.
    if not cgi:
        print(file=outfp)
        return
    siteowner = Utils.get_site_email(extra='owner')
    # Should this be sent in the site list's preferred language?
    msg = Message.UserNotification(
        siteowner, siteowner,
        _('Mailing list removal request for list %(listname)s'),
        sfp.getvalue(), mm_cfg.DEFAULT_SERVER_LANGUAGE)
    msg['Date'] = email.utils.formatdate(localtime=1)
    outq = get_switchboard(mm_cfg.OUTQUEUE_DIR)
    outq.enqueue(msg, recips=[siteowner], nodecorate=1)
Beispiel #58
0
    def update_archive(self, archive):
        self.archive = archive
        self.message(_("Updating index files for archive [%(archive)s]"))
        arcdir = os.path.join(self.basedir, archive)
        self.__set_parameters(archive)

        for hdr in ('Date', 'Subject', 'Author'):
            self._update_simple_index(hdr, archive, arcdir)

        self._update_thread_index(archive, arcdir)