Example #1
0
    def add_members (self, save=False):
        """Add any email addressses that are provided in the create form."""

        if self.welcome == '':
            text = ('Welcome to %s. Visit the List Server to ' +
            'manage your subscriptions') % self.ln
        else:
            text = self.welcome

        for key in self.cgidata.keys():
            if re.match('^lc_member_', key):
                fn, em = parseaddr(self.cgival(key).lower().strip())
                userdesc = UserDesc(em, fn, mm_cfg.SSO_STOCK_USER_PWD, False)
                try:
                    self.ml.ApprovedAddMember(userdesc, True, text,
                                              whence='SSO List Creation Time')
                    syslog('sso',
                           'Successfully added %s to list: %s' % (em,
                                                                  self.ln))
                except Errors.MMAlreadyAMember:
                    ## FIXME: Need to find some way of communicating this
                    ## case to the user. As thisi s a new list, this can only
                    ## happen if the same address is given by the admin... hm
                    syslog('sso',
                           '%s already a member of listL %s' % (em, self.ln))

        if save:
            self.ml.Save()
Example #2
0
    def edit_members (self):
        oldm = self.ml.getRegularMemberKeys()
        newm = []
        for key in self.cgidata.keys():
            if re.match('^lc_member_', key):
                fn, em = parseaddr(self.cgival(key).lower())
                newm.append(em)

        remove = [x for x in oldm if not x in newm]
        insert = [x for x in newm if not x in oldm]

        syslog('sso', 'Will remove %s from list %s' % (remove, self.ln))
        syslog('sso', 'Will add %s to list %s' % (insert, self.ln))

        for em in remove:
            self.ml.ApprovedDeleteMember(em, whence='SSO Web Interface')

        for em in insert:
            userdesc = UserDesc(em, '', mm_cfg.SSO_STOCK_USER_PWD, False)
            try:
                self.ml.ApprovedAddMember(userdesc, True, self.welcome,
                                          whence='SSO List Edit')
                syslog('sso',
                       'Successfully added %s to list: %s' % (em,
                                                              self.ln))
            except Errors.MMAlreadyAMember:
                syslog('sso',
                       'request_edit: %s already a member of list %s' % (em,
                                                                         self.ln))
Example #3
0
def get_lists(userdesc, perms, vhost, email=None):
    """ List available lists for the given vhost
    """
    if email is None:
        udesc = userdesc
    else:
        udesc = UserDesc(email.lower(), email.lower(), None, 0)
    prefix = vhost.lower()+VHOST_SEP
    names = Utils.list_names()
    names.sort()
    result = []
    for name in names:
        if not name.startswith(prefix):
            continue
        try:
            mlist = MailList.MailList(name, lock=0)
        except:
            continue
        try:
            details = get_list_info(udesc, perms, mlist, (email is None and vhost == PLATAL_DOMAIN))
            if details is not None:
                result.append(details[0])
        except Exception, e:
            sys.stderr.write('Can\'t get list %s: %s\n' % (name, str(e)))
            continue
Example #4
0
 def getUser(self, uid, md5, vhost):
     res = mysql_fetchone ("""SELECT  a.full_name, IF(s.email IS NULL, a.email, CONCAT(s.email, '@%s')),
                                      IF (a.is_admin, 'admin',
                                                      IF(FIND_IN_SET('lists', at.perms) OR FIND_IN_SET('lists', a.user_perms), 'lists', NULL))
                                FROM  accounts AS a
                          INNER JOIN  account_types AS at ON (at.type = a.type)
                           LEFT JOIN  email_source_account AS s ON (s.uid = a.uid AND s.type = 'forlife')
                               WHERE  a.uid = '%s' AND a.password = '******' AND a.state = 'active'
                               LIMIT  1""" \
                           % (PLATAL_DOMAIN, uid, md5))
     if res:
         name, forlife, perms = res
         if vhost != PLATAL_DOMAIN and perms != 'admin':
             res = mysql_fetchone ("""SELECT  m.uid, IF(m.perms = 'admin', 'admin', 'lists')
                                        FROM  group_members AS m
                                  INNER JOIN  groups        AS g ON (m.asso_id = g.id)
                                       WHERE  uid = '%s' AND mail_domain = '%s'""" \
                                   % (uid, vhost))
             if res:
                 _, perms = res
         userdesc = UserDesc(forlife, name, None, 0)
         return (userdesc, perms, vhost)
     else:
         print >> sys.stderr, "no user found for uid: %s, passwd: %s" % (
             uid, md5)
         return None
   def __handlesubscription(self, record, value, comment):
       global _
       stime, addr, fullname, password, digest, lang = record
       if value == mm_cfg.DEFER:
           return DEFER
       elif value == mm_cfg.DISCARD:
           syslog('vette', '%s: discarded subscription request from %s',
                  self.internal_name(), addr)
       elif value == mm_cfg.REJECT:
           self.__refuse(_('Subscription request'),
                         addr,
                         comment or _('[No reason given]'),
                         lang=lang)
           syslog(
               'vette', """%s: rejected subscription request from %s
tReason: %s""", self.internal_name(), addr, comment or '[No reason given]')
       else:
           # subscribe
           assert value == mm_cfg.SUBSCRIBE
           try:
               _ = D_
               whence = _('via admin approval')
               _ = i18n._
               userdesc = UserDesc(addr, fullname, password, digest, lang)
               self.ApprovedAddMember(userdesc, whence=whence)
           except Errors.MMAlreadyAMember:
               # User has already been subscribed, after sending the request
               pass
           # TBD: disgusting hack: ApprovedAddMember() can end up closing
           # the request database.
           self.__opendb()
       return REMOVE
Example #6
0
    def getUser(self, uid, md5, vhost):
        # Check perms
        if '+' in uid and uid.split('+')[0] == SYSTEM_LOGIN and md5 == SYSTEM_PASS:
            # This is a "sudo" login, format is <SYSTEM_LOGIN>+<REAL_LOGIN>
            uid = uid.split('+', 1)[1]

            res = mysql_fetchone("""SELECT  a.uid
                                      FROM  accounts AS a
                                     WHERE  a.uid = %s AND a.state = 'active'
                                     LIMIT  1""",
                                     (uid,))

        else:
            # Normal login, check password
            res = mysql_fetchone("""SELECT  a.uid
                                      FROM  accounts AS a
                                     WHERE  a.uid = %s AND a.password = %s AND a.state = 'active'
                                     LIMIT  1""",
                (uid, md5))

        if not res:
            # Invalid/inactive account, even with superuser access
            print >> sys.stderr, "no user found for uid: %s, passwd: %s" % (uid, md5)
            return None

        # Fetch profile
        res = mysql_fetchone ("""SELECT  a.full_name, IF(esa.email IS NULL, a.email, CONCAT(esa.email, '@', evd.name)),
                                         IF (a.is_admin, 'admin',
                                                         IF(FIND_IN_SET('lists', at.perms) OR FIND_IN_SET('lists', a.user_perms), 'lists', NULL))
                                   FROM  accounts AS a
                             INNER JOIN  account_types AS at ON (at.type = a.type)
                              LEFT JOIN  email_source_account AS esa ON (esa.uid = a.uid AND esa.type = 'forlife')
                              LEFT JOIN  email_virtual_domains AS evd ON (esa.domain = evd.id)
                                  WHERE  a.uid = %s
                                  LIMIT  1""",
                              (uid,))

        # Alternate perm lookup for X.net requests
        if res:
            name, forlife, perms = res
            if vhost != PLATAL_DOMAIN and perms != 'admin':
                res = mysql_fetchone ("""SELECT  m.uid, IF(m.perms = 'admin', 'admin', 'lists')
                                           FROM  group_members AS m
                                     INNER JOIN  groups        AS g ON (m.asso_id = g.id)
                                          WHERE  uid = %s AND mail_domain = %s""",
                                      (uid, vhost))
                if res:
                    _, perms = res
            userdesc = UserDesc(forlife, name, None, 0)
            return (userdesc, perms, vhost)

        # No account found
        print >> sys.stderr, "no user found for uid: %s, passwd: %s" % (uid, md5)
        return None
Example #7
0
def mass_subscribe(vhost,listname,users):
    try:
        mlist = MailList.MailList(vhost+'-'+listname)
    except:
        return 0
    try:
        members = mlist.getRegularMemberKeys()
        added = []
        for user in users:
            name, forlife = user;
            if forlife+'@polytechnique.org' in members:
                continue
            userd = UserDesc(forlife+'@polytechnique.org', name, None, 0)
            mlist.ApprovedAddMember(userd, 0, 0)
            added.append( (userd.fullname, userd.address) )
        mlist.Save()
    finally:
        mlist.Unlock()
        return added
Example #8
0
def mass_subscribe(userdesc, perms, mlist, users):
    """ Add a list of users to the list.
            @mlist
            @edit
            @admin
    """
    if isinstance(users, dict):
        users = users.values()
    if not isinstance(users, list):
        raise Exception("userlist must be a list")
    members = mlist.getRegularMemberKeys()
    added = []
    for user in users:
        email, name = to_forlife(user)
        if ( email is None ) or ( email in members ):
            continue
        userd = UserDesc(email, name, None, 0)
        mlist.ApprovedAddMember(userd)
        added.append( (quote(userd.fullname), userd.address) )
    return added
Example #9
0
    def handler (self):
        listname = self.cgidata.getvalue('list')
        action   = self.cgidata.getvalue('action').lower().strip()

        syslog('sso', 'User: %s; Listname: %s; action: %s' % (self.curr_user,
                                                              listname, action))

        mlist = MailList.MailList(listname)
        userdesc = UserDesc(self.curr_user, u'', mm_cfg.SSO_STOCK_USER_PWD,
                            False)

        if action == 'join':
            try:
                text = ('Welcome to %s. Visit the List Server to ' +
                        'manage your subscriptions') % listname
                mlist.ApprovedAddMember(userdesc, True, text,
                                        whence='SSO Web Interface')
                mlist.Save()
                self.kwargs_add('notice_success', True)
                self.kwargs_add('notice_text',
                                'Successfully added to list: %s' % listname)
            except Errors.MMAlreadyAMember:
                self.kwargs_add('notice_success', False)
                self.kwargs_add('notice_text',
                                'You are already subscribed to %s' % listname)
        elif action == 'leave':
            try:
                mlist.ApprovedDeleteMember(self.curr_user)
                mlist.Save()
                self.kwargs_add('notice_success', True)
                self.kwargs_add('notice_text',
                                'Successfully removed from list: %s' % listname)
            except Errors.NotAMemberError:
                # User has already been unsubscribed
                self.kwargs_add('notice_success', False)
                self.kwargs_add('notice_text',
                                'You are not a member of %s' % listname)

        self.render()
Example #10
0
    # possible, and that kind of defeats the purpose of private rosters.
    # We'll use this string for all successful or unsuccessful subscription
    # results.
    if mlist.private_roster == 0:
        # Public rosters
        privacy_results = ''
    else:
        privacy_results = _("""\
Your subscription request has been received, and will soon be acted upon.
Depending on the configuration of this mailing list, your subscription request
may have to be first confirmed by you via email, or approved by the list
moderator.  If confirmation is required, you will soon get a confirmation
email which contains further instructions.""")

    try:
        userdesc = UserDesc(email, fullname, password, digest, lang)
        mlist.AddMember(userdesc, remote)
        results = ''
    # Check for all the errors that mlist.AddMember can throw options on the
    # web page for this cgi
    except Errors.MembershipIsBanned:
        results = _("""The email address you supplied is banned from this
        mailing list.  If you think this restriction is erroneous, please
        contact the list owners at %(listowner)s.""")
    except Errors.MMBadEmailError:
        results = _("""\
The email address you supplied is not valid.  (E.g. it must contain an
`@'.)""")
    except Errors.MMHostileAddress:
        results = _("""\
Your subscription is not allowed because the email address you gave is
Example #11
0
def subscription_confirm(mlist, doc, cookie, cgidata):
    # See the comment in admin.py about the need for the signal
    # handler.
    def sigterm_handler(signum, frame, mlist=mlist):
        mlist.Unlock()
        sys.exit(0)

    listname = mlist.real_name
    mlist.Lock()
    try:
        try:
            # Some pending values may be overridden in the form.  email of
            # course is hardcoded. ;)
            lang = cgidata.getvalue('language')
            if not Utils.IsLanguage(lang):
                lang = mlist.preferred_language
            i18n.set_language(lang)
            doc.set_language(lang)
            if cgidata.has_key('digests'):
                try:
                    digest = int(cgidata.getvalue('digests'))
                except ValueError:
                    digest = None
            else:
                digest = None
            userdesc = mlist.pend_confirm(cookie, expunge=False)[1]
            fullname = cgidata.getvalue('realname', None)
            if fullname is not None:
                fullname = Utils.canonstr(fullname, lang)
            overrides = UserDesc(fullname=fullname, digest=digest, lang=lang)
            userdesc += overrides
            op, addr, pw, digest, lang = mlist.ProcessConfirmation(
                cookie, userdesc)
        except Errors.MMNeedApproval:
            title = _('Awaiting moderator approval')
            doc.SetTitle(title)
            doc.AddItem(Header(3, Bold(FontAttr(title, size='+2'))))
            doc.AddItem(
                _("""\
            You have successfully confirmed your subscription request to the
            mailing list %(listname)s, however final approval is required from
            the list moderator before you will be subscribed.  Your request
            has been forwarded to the list moderator, and you will be notified
            of the moderator's decision."""))
        except Errors.NotAMemberError:
            bad_confirmation(
                doc,
                _('''Invalid confirmation string.  It is
            possible that you are attempting to confirm a request for an
            address that has already been unsubscribed.'''))
        except Errors.MMAlreadyAMember:
            doc.addError(_("You are already a member of this mailing list!"))
        except Errors.MembershipIsBanned:
            owneraddr = mlist.GetOwnerEmail()
            doc.addError(
                _("""You are currently banned from subscribing to
            this list.  If you think this restriction is erroneous, please
            contact the list owners at %(owneraddr)s."""))
        except Errors.HostileSubscriptionError:
            doc.addError(
                _("""\
            You were not invited to this mailing list.  The invitation has
            been discarded, and both list administrators have been
            alerted."""))
        else:
            # Use the user's preferred language
            i18n.set_language(lang)
            doc.set_language(lang)
            # The response
            listname = mlist.real_name
            title = 'Anmeldung best&auml;tigt'
            optionsurl = mlist.GetOptionsURL(addr, absolute=1)
            doc.SetTitle(title)
            doc.AddItem(Header(3, Bold(FontAttr(title, size='+2'))))
            doc.AddItem(
                _('''\
            Die Anmeldung der Email-Adresse <strong>%(addr)s</strong> zur Mailingliste
            <strong>%(listname)s</strong> ist hiermit best&auml;tigt.
            '''))
        mlist.Save()
    finally:
        mlist.Unlock()
Example #12
0
def process_form(mlist, doc, cgidata, lang):
    listowner = mlist.GetOwnerEmail()
    realname = mlist.real_name
    results = []

    # The email address being subscribed, required
    email = cgidata.getvalue('email', '').strip()
    if not email:
        results.append(_('You must supply a valid email address.'))

    fullname = cgidata.getvalue('fullname', '')
    # Canonicalize the full name
    fullname = Utils.canonstr(fullname, lang)
    # Who was doing the subscribing?
    remote = os.environ.get(
        'REMOTE_HOST', os.environ.get('REMOTE_ADDR', 'unidentified origin'))
    # Are we checking the hidden data?
    if mm_cfg.SUBSCRIBE_FORM_SECRET:
        now = int(time.time())
        try:
            ftime, fhash = cgidata.getvalue('sub_form_token', '').split(':')
            then = int(ftime)
        except ValueError:
            ftime = fhash = ''
            then = now
        token = Utils.sha_new(mm_cfg.SUBSCRIBE_FORM_SECRET + ftime +
                              mlist.internal_name() + remote).hexdigest()
        if now - then > mm_cfg.FORM_LIFETIME:
            results.append(_('The form is too old.  Please GET it again.'))
        if now - then < mm_cfg.SUBSCRIBE_FORM_MIN_TIME:
            results.append(
                _('Please take a few seconds to fill out the form before submitting it.'
                  ))
        if token != fhash:
            results.append(_('You must GET the form before submitting it.'))
    # Was an attempt made to subscribe the list to itself?
    if email == mlist.GetListEmail():
        syslog('mischief', 'Attempt to self subscribe %s: %s', email, remote)
        results.append(_('You may not subscribe a list to itself!'))
    # If the user did not supply a password, generate one for him
    password = cgidata.getvalue('pw', '').strip()
    confirmed = cgidata.getvalue('pw-conf', '').strip()

    if not password and not confirmed:
        password = Utils.MakeRandomPassword()
    elif not password or not confirmed:
        results.append(_('If you supply a password, you must confirm it.'))
    elif password <> confirmed:
        results.append(_('Your passwords did not match.'))

    # Get the digest option for the subscription.
    digestflag = cgidata.getvalue('digest')
    if digestflag:
        try:
            digest = int(digestflag)
        except ValueError:
            digest = 0
    else:
        digest = mlist.digest_is_default

    # Sanity check based on list configuration.  BAW: It's actually bogus that
    # the page allows you to set the digest flag if you don't really get the
    # choice. :/
    if not mlist.digestable:
        digest = 0
    elif not mlist.nondigestable:
        digest = 1

    if results:
        print_results(mlist, ERRORSEP.join(results), doc, lang)
        return

    # If this list has private rosters, we have to be careful about the
    # message that gets printed, otherwise the subscription process can be
    # used to mine for list members.  It may be inefficient, but it's still
    # possible, and that kind of defeats the purpose of private rosters.
    # We'll use this string for all successful or unsuccessful subscription
    # results.
    if mlist.private_roster == 0:
        # Public rosters
        privacy_results = ''
    else:
        privacy_results = _("""\
Your subscription request has been received, and will soon be acted upon.
Depending on the configuration of this mailing list, your subscription request
may have to be first confirmed by you via email, or approved by the list
moderator.  If confirmation is required, you will soon get a confirmation
email which contains further instructions.""")

    try:
        userdesc = UserDesc(email, fullname, password, digest, lang)
        mlist.AddMember(userdesc, remote)
        results = ''
    # Check for all the errors that mlist.AddMember can throw options on the
    # web page for this cgi
    except Errors.MembershipIsBanned:
        results = _("""The email address you supplied is banned from this
        mailing list.  If you think this restriction is erroneous, please
        contact the list owners at %(listowner)s.""")
    except Errors.MMBadEmailError:
        results = _("""\
The email address you supplied is not valid.  (E.g. it must contain an
`@'.)""")
    except Errors.MMHostileAddress:
        results = _("""\
Your subscription is not allowed because the email address you gave is
insecure.""")
    except Errors.MMSubscribeNeedsConfirmation:
        # Results string depends on whether we have private rosters or not
        if privacy_results:
            results = privacy_results
        else:
            results = _("""\
Confirmation from your email address is required, to prevent anyone from
subscribing you without permission.  Instructions are being sent to you at
%(email)s.  Please note your subscription will not start until you confirm
your subscription.""")
    except Errors.MMNeedApproval, x:
        # Results string depends on whether we have private rosters or not
        if privacy_results:
            results = privacy_results
        else:
            # We need to interpolate into x.__str__()
            x = _(str(x))
            results = _("""\
Your subscription request was deferred because %(x)s.  Your request has been
forwarded to the list moderator.  You will receive email informing you of the
moderator's decision when they get to your request.""")
def process(res, args):
    mlist = res.mlist
    digest = None
    password = None
    address = None
    realname = None
    # Parse the args
    argnum = 0
    for arg in args:
        if arg.lower().startswith('address='):
            address = arg[8:]
        elif argnum == 0:
            password = arg
        elif argnum == 1:
            if arg.lower() not in ('digest', 'nodigest'):
                res.results.append(_('Bad digest specifier: %(arg)s'))
                return STOP
            if arg.lower() == 'digest':
                digest = 1
            else:
                digest = 0
        else:
            res.results.append(_('Usage:'))
            res.results.append(gethelp(mlist))
            return STOP
        argnum += 1
    # Fix the password/digest issue
    if (digest is None
            and password and password.lower() in ('digest', 'nodigest')):
        if password.lower() == 'digest':
            digest = 1
        else:
            digest = 0
        password = None
    # Fill in empty defaults
    if digest is None:
        digest = mlist.digest_is_default
    if password is None:
        password = Utils.MakeRandomPassword()
    if address is None:
        realname, address = parseaddr(res.msg['from'])
        if not address:
            # Fall back to the sender address
            address = res.msg.get_sender()
        if not address:
            res.results.append(_('No valid address found to subscribe'))
            return STOP
        # Watch for encoded names
        try:
            h = make_header(decode_header(realname))
            # BAW: in Python 2.2, use just unicode(h)
            realname = str(h)
        except UnicodeError:
            realname = ''
        # Coerce to byte string if uh contains only ascii
        try:
            realname = realname.encode('us-ascii')
        except UnicodeError:
            pass
    # Create the UserDesc record and do a non-approved subscription
    listowner = mlist.GetOwnerEmail()
    userdesc = UserDesc(address, realname, password, digest)
    remote = res.msg.get_sender()
    try:
        mlist.AddMember(userdesc, remote)
    except Errors.MembershipIsBanned:
        res.results.append(_("""\
The email address you supplied is banned from this mailing list.
If you think this restriction is erroneous, please contact the list
owners at %(listowner)s."""))
        return STOP
    except Errors.MMBadEmailError:
        res.results.append(_("""\
Mailman won't accept the given email address as a valid address.
(E.g. it must have an @ in it.)"""))
        return STOP
    except Errors.MMHostileAddress:
        res.results.append(_("""\
Your subscription is not allowed because
the email address you gave is insecure."""))
        return STOP
    except Errors.MMAlreadyAMember:
        res.results.append(_('You are already subscribed!'))
        return STOP
    except Errors.MMCantDigestError:
        res.results.append(
            _('No one can subscribe to the digest of this list!'))
        return STOP
    except Errors.MMMustDigestError:
        res.results.append(_('This list only supports digest subscriptions!'))
        return STOP
    except Errors.MMSubscribeNeedsConfirmation:
        # We don't need to respond /and/ send a confirmation message.
        res.respond = 0
    except Errors.MMNeedApproval:
        res.results.append(_("""\
Your subscription request has been forwarded to the list administrator
at %(listowner)s for review."""))
    else:
        # Everything is a-ok
        res.results.append(_('Subscription request succeeded.'))
Example #14
0
def process_form(mlist, doc, cgidata, lang):
    listowner = mlist.GetOwnerEmail()
    realname = mlist.real_name
    results = []

    # The email address being subscribed, required
    email = cgidata.getfirst('email', '').strip()
    if not email:
        results.append(_('You must supply a valid email address.'))

    fullname = cgidata.getfirst('fullname', '')
    # Canonicalize the full name
    fullname = Utils.canonstr(fullname, lang)
    # Who was doing the subscribing?
    remote = os.environ.get('HTTP_FORWARDED_FOR',
             os.environ.get('HTTP_X_FORWARDED_FOR',
             os.environ.get('REMOTE_ADDR',
                            'unidentified origin')))

    # Check reCAPTCHA submission, if enabled
    if mm_cfg.RECAPTCHA_SECRET_KEY:
        request = urllib2.Request(
            url = 'https://www.google.com/recaptcha/api/siteverify',
            data = urllib.urlencode({
                'secret': mm_cfg.RECAPTCHA_SECRET_KEY,
                'response': cgidata.getvalue('g-recaptcha-response', ''),
                'remoteip': remote}))
        try:
            httpresp = urllib2.urlopen(request)
            captcha_response = json.load(httpresp)
            httpresp.close()
            if not captcha_response['success']:
                e_codes = COMMASPACE.join(captcha_response['error-codes'])
                results.append(_('reCAPTCHA validation failed: %(e_codes)s'))
        except urllib2.URLError as e:
            e_reason = e.reason
            results.append(_('reCAPTCHA could not be validated: %(e_reason)s'))

    # Are we checking the hidden data?
    if mm_cfg.SUBSCRIBE_FORM_SECRET:
        now = int(time.time())
        # Try to accept a range in case of load balancers, etc.  (LP: #1447445)
        if remote.find('.') >= 0:
            # ipv4 - drop last octet
            remote1 = remote.rsplit('.', 1)[0]
        else:
            # ipv6 - drop last 16 (could end with :: in which case we just
            #        drop one : resulting in an invalid format, but it's only
            #        for our hash so it doesn't matter.
            remote1 = remote.rsplit(':', 1)[0]
        try:
            ftime, fhash = cgidata.getfirst('sub_form_token', '').split(':')
            then = int(ftime)
        except ValueError:
            ftime = fhash = ''
            then = 0
        token = Utils.sha_new(mm_cfg.SUBSCRIBE_FORM_SECRET +
                              ftime +
                              mlist.internal_name() +
                              remote1).hexdigest()
        if ftime and now - then > mm_cfg.FORM_LIFETIME:
            results.append(_('The form is too old.  Please GET it again.'))
        if ftime and now - then < mm_cfg.SUBSCRIBE_FORM_MIN_TIME:
            results.append(
    _('Please take a few seconds to fill out the form before submitting it.'))
        if ftime and token != fhash:
            results.append(
                _("The hidden token didn't match.  Did your IP change?"))
        if not ftime:
            results.append(
    _('There was no hidden token in your submission or it was corrupted.'))
            results.append(_('You must GET the form before submitting it.'))
    # Was an attempt made to subscribe the list to itself?
    if email == mlist.GetListEmail():
        syslog('mischief', 'Attempt to self subscribe %s: %s', email, remote)
        results.append(_('You may not subscribe a list to itself!'))
    # If the user did not supply a password, generate one for him
    password = cgidata.getfirst('pw', '').strip()
    confirmed = cgidata.getfirst('pw-conf', '').strip()

    if not password and not confirmed:
        password = Utils.MakeRandomPassword()
    elif not password or not confirmed:
        results.append(_('If you supply a password, you must confirm it.'))
    elif password <> confirmed:
        results.append(_('Your passwords did not match.'))

    # Get the digest option for the subscription.
    digestflag = cgidata.getfirst('digest')
    if digestflag:
        try:
            digest = int(digestflag)
        except (TypeError, ValueError):
            digest = 0
    else:
        digest = mlist.digest_is_default

    # Sanity check based on list configuration.  BAW: It's actually bogus that
    # the page allows you to set the digest flag if you don't really get the
    # choice. :/
    if not mlist.digestable:
        digest = 0
    elif not mlist.nondigestable:
        digest = 1

    if results:
        print_results(mlist, ERRORSEP.join(results), doc, lang)
        return

    # If this list has private rosters, we have to be careful about the
    # message that gets printed, otherwise the subscription process can be
    # used to mine for list members.  It may be inefficient, but it's still
    # possible, and that kind of defeats the purpose of private rosters.
    # We'll use this string for all successful or unsuccessful subscription
    # results.
    if mlist.private_roster == 0:
        # Public rosters
        privacy_results = ''
    else:
        privacy_results = _("""\
Your subscription request has been received, and will soon be acted upon.
Depending on the configuration of this mailing list, your subscription request
may have to be first confirmed by you via email, or approved by the list
moderator.  If confirmation is required, you will soon get a confirmation
email which contains further instructions.""")

    try:
        userdesc = UserDesc(email, fullname, password, digest, lang)
        mlist.AddMember(userdesc, remote)
        results = ''
    # Check for all the errors that mlist.AddMember can throw options on the
    # web page for this cgi
    except Errors.MembershipIsBanned:
        results = _("""The email address you supplied is banned from this
        mailing list.  If you think this restriction is erroneous, please
        contact the list owners at %(listowner)s.""")
    except Errors.MMBadEmailError:
        results = _("""\
The email address you supplied is not valid.  (E.g. it must contain an
`@'.)""")
    except Errors.MMHostileAddress:
        results = _("""\
Your subscription is not allowed because the email address you gave is
insecure.""")
    except Errors.MMSubscribeNeedsConfirmation:
        # Results string depends on whether we have private rosters or not
        if privacy_results:
            results = privacy_results
        else:
            results = _("""\
Confirmation from your email address is required, to prevent anyone from
subscribing you without permission.  Instructions are being sent to you at
%(email)s.  Please note your subscription will not start until you confirm
your subscription.""")
    except Errors.MMNeedApproval, x:
        # Results string depends on whether we have private rosters or not
        if privacy_results:
            results = privacy_results
        else:
            # We need to interpolate into x.__str__()
            x = _(str(x))
            results = _("""\
Your subscription request was deferred because %(x)s.  Your request has been
forwarded to the list moderator.  You will receive email informing you of the
moderator's decision when they get to your request.""")
 def __iadd__(self, other):
     UserDesc.__iadd__(self, other)
     if getattr(other, 'essay', None) is not None:
         self.essay = other.essay
     return self
 def __init__(self, address=None, fullname=None, password=None,
              digest=None, lang=None, essay=None):
     UserDesc.__init__(self, address, fullname, password, digest, lang)
     if essay is not None:
         self.essay = essay